aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-04-24 16:55:55 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-04-24 16:55:55 +0200
commitf103f86ec3247ff27e7cc23dfce5e426f385ed8c (patch)
tree4efffb7d254e494944ce555d343c34d957238be0
parent2a0f9e035f673f1ee387924501a31990de37f18d (diff)
Take one on library linking
-rw-r--r--build/bin/module26
-rw-r--r--build/bin/module.cxx58
-rw-r--r--build/bin/rule.cxx26
-rw-r--r--build/bin/target.cxx7
-rw-r--r--build/buildfile2
-rw-r--r--build/cxx/rule.cxx168
-rw-r--r--build/dump.cxx2
7 files changed, 238 insertions, 51 deletions
diff --git a/build/bin/module b/build/bin/module
new file mode 100644
index 0000000..f2d9502
--- /dev/null
+++ b/build/bin/module
@@ -0,0 +1,26 @@
+// file : build/bin/module -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BUILD_BIN_MODULE
+#define BUILD_BIN_MODULE
+
+#include <build/path>
+#include <build/module>
+
+namespace build
+{
+ namespace bin
+ {
+ void
+ init (scope&, scope&, const location&);
+
+ // Init the 'lib' part of the module because a lib{} target
+ // has been created in the specified directory.
+ //
+ void
+ init_lib (const dir_path&);
+ }
+}
+
+#endif // BUILD_BIN_MODULE
diff --git a/build/bin/module.cxx b/build/bin/module.cxx
new file mode 100644
index 0000000..89ea9fe
--- /dev/null
+++ b/build/bin/module.cxx
@@ -0,0 +1,58 @@
+// file : build/bin/module.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#include <build/bin/module>
+
+#include <build/scope>
+#include <build/variable>
+#include <build/diagnostics>
+
+#include <build/config/utility>
+
+using namespace std;
+
+namespace build
+{
+ namespace bin
+ {
+ void
+ init (scope& root, scope& base, const location& l)
+ {
+ //@@ TODO: avoid multiple inits (generally, for modules).
+ //
+ tracer trace ("bin::init");
+
+ //@@ Should it be this way?
+ //
+ if (&root != &base)
+ fail (l) << "bin module must be initialized in project root scope";
+
+ //@@ TODO: need to register target types, rules here instead of main().
+
+ const dir_path& out_root (root.path ());
+ level4 ([&]{trace << "for " << out_root;});
+
+ // Configure.
+ //
+ }
+
+ void
+ init_lib (const dir_path& d)
+ {
+ scope* root (scopes.find (d).root_scope ());
+
+ if (root == nullptr)
+ return;
+
+ // config.bin.lib
+ //
+ {
+ auto v (root->vars.assign ("bin.lib"));
+
+ if (!v)
+ v = config::required (*root, "config.bin.lib", "shared").first;
+ }
+ }
+ }
+}
diff --git a/build/bin/rule.cxx b/build/bin/rule.cxx
index 1b887bf..d84af25 100644
--- a/build/bin/rule.cxx
+++ b/build/bin/rule.cxx
@@ -9,8 +9,6 @@
#include <build/algorithm>
#include <build/diagnostics>
-#include <build/config/utility>
-
#include <build/bin/target>
using namespace std;
@@ -47,28 +45,16 @@ namespace build
{
lib& t (static_cast<lib&> (xt));
- // Configure.
- //
- // The logic is as follows: if this library somehow knowns what
- // it wants to be (i.e., the bin.lib is defined), then don't
- // bother configuring the project-wide value.
+ // Get the library type to build. If not set for a target, this
+ // should be configured at the project scope by init_lib().
//
- const string* type (nullptr);
-
- if (auto v = t["bin.lib"])
- type = &v.as<const string&> ();
- else
- {
- scope& root (*t.root_scope ());
- type = &config::required (root, "config.bin.lib", "shared").first;
- root.assign ("bin.lib") = *type;
- }
+ const string& type (t["bin.lib"].as<const string&> ());
- bool ar (*type == "static" || *type == "both");
- bool so (*type == "shared" || *type == "both");
+ bool ar (type == "static" || type == "both");
+ bool so (type == "shared" || type == "both");
if (!ar && !so)
- fail << "unknown library type: " << *type <<
+ fail << "unknown library type: " << type <<
info << "'static', 'shared', or 'both' expected";
if (ar)
diff --git a/build/bin/target.cxx b/build/bin/target.cxx
index 1849533..ca198d7d 100644
--- a/build/bin/target.cxx
+++ b/build/bin/target.cxx
@@ -4,6 +4,8 @@
#include <build/bin/target>
+#include <build/bin/module>
+
using namespace std;
namespace build
@@ -131,6 +133,11 @@ namespace build
static target*
lib_factory (dir_path d, string n, const string* e)
{
+ // If there is a target of type lib{} in this project, then
+ // initialized the lib part of the module.
+ //
+ init_lib (d);
+
liba* a (targets.find<liba> (d, n));
libso* so (targets.find<libso> (d, n));
lib* l (new lib (move (d), move (n), e));
diff --git a/build/buildfile b/build/buildfile
index dd6fcaa..1224548 100644
--- a/build/buildfile
+++ b/build/buildfile
@@ -1,5 +1,5 @@
config = config/{operation module utility}
-bin = bin/{target rule}
+bin = bin/{target rule module}
cxx = cxx/{target rule module}
exe{b b-prev}: cxx{b algorithm name operation spec scope variable target \
diff --git a/build/cxx/rule.cxx b/build/cxx/rule.cxx
index 9d25143..e59c5b9 100644
--- a/build/cxx/rule.cxx
+++ b/build/cxx/rule.cxx
@@ -434,7 +434,8 @@ namespace build
// Scan prerequisites and see if we can work with what we've got.
//
- bool seen_cxx (false), seen_c (false), seen_obj (false);
+ bool seen_cxx (false), seen_c (false), seen_obj (false),
+ seen_lib (false);
for (prerequisite& p: group_prerequisites (t))
{
@@ -458,6 +459,12 @@ namespace build
{
seen_obj = seen_obj || true;
}
+ else if (p.type.id == typeid (liba) ||
+ p.type.id == typeid (libso) ||
+ p.type.id == typeid (lib))
+ {
+ seen_lib = seen_lib || true;
+ }
else if (p.type.id != typeid (fsdir))
{
level3 ([&]{trace << "unexpected prerequisite type " << p.type;});
@@ -474,23 +481,86 @@ namespace build
return nullptr;
}
- return seen_cxx || seen_c || seen_obj ? &t : nullptr;
+ return seen_cxx || seen_c || seen_obj || seen_lib ? &t : nullptr;
+ }
+
+ static inline target_state
+ select_obja_liba (action a, target& t)
+ {
+ target* r;
+ if (obj* o = t.is_a<obj> ())
+ r = o->a;
+ else if (lib* l = t.is_a<lib> ())
+ r = l->a;
+ else
+ r = &t;
+
+ return execute (a, *r);
}
static inline target_state
- select_a (action a, target& t)
+ select_obja_libso (action a, target& t)
{
- obj* o (t.is_a<obj> ());
- return execute (a, o != nullptr ? *o->a : t);
+ target* r;
+ if (obj* o = t.is_a<obj> ())
+ r = o->a;
+ else if (lib* l = t.is_a<lib> ())
+ r = l->so;
+ else
+ r = &t;
+
+ return execute (a, *r);
}
static inline target_state
- select_so (action a, target& t)
+ select_objso_liba (action a, target& t)
{
- obj* o (t.is_a<obj> ());
- return execute (a, o != nullptr ? *o->so : t);
+ target* r;
+ if (obj* o = t.is_a<obj> ())
+ r = o->so;
+ else if (lib* l = t.is_a<lib> ())
+ r = l->a;
+ else
+ r = &t;
+
+ return execute (a, *r);
}
+ static inline target_state
+ select_objso_libso (action a, target& t)
+ {
+ target* r;
+ if (obj* o = t.is_a<obj> ())
+ r = o->so;
+ else if (lib* l = t.is_a<lib> ())
+ r = l->so;
+ else
+ r = &t;
+
+ return execute (a, *r);
+ }
+
+ static executor_function* clean_table[2][2] =
+ {
+ {&perform_clean<select_obja_liba>, &perform_clean<select_obja_libso>},
+ {&perform_clean<select_objso_liba>, &perform_clean<select_objso_libso>}
+ };
+
+ static executor_function* default_table[2][2] =
+ {
+ {&default_action<select_obja_liba>, &default_action<select_obja_libso>},
+ {&default_action<select_objso_liba>, &default_action<select_objso_libso>}
+ };
+
+ static bool (*execute_table[2][2]) (action, target&, const timestamp&) =
+ {
+ {&execute_prerequisites<select_obja_liba>,
+ &execute_prerequisites<select_obja_libso>},
+
+ {&execute_prerequisites<select_objso_liba>,
+ &execute_prerequisites<select_objso_libso>}
+ };
+
recipe link::
apply (action a, target& xt, void*) const
{
@@ -502,7 +572,17 @@ namespace build
? type::exe
: (t.is_a<liba> () ? type::liba : type::libso));
- bool so (tt == type::libso);
+ bool so (tt == type::libso); // Obj-so.
+
+ // Decide which lib{} member to use for this target.
+ //
+ bool lso; // Lib-so.
+ switch (tt)
+ {
+ case type::exe: lso = true; break;
+ case type::liba: lso = false; break;
+ case type::libso: lso = true; break;
+ }
// Derive file name from target name.
//
@@ -542,8 +622,8 @@ namespace build
continue;
}
- // If this is the obj{} target group, then pick the appropriate
- // member and make sure it is searched and matched.
+ // If this is the obj{} or lib{} target group, then pick the
+ // appropriate member and make sure it is searched and matched.
//
target* pt;
@@ -572,6 +652,32 @@ namespace build
if (!group)
pe.target = pt;
}
+ else if (lib* l = pe.target->is_a<lib> ())
+ {
+ // Make sure the library build that we need is available.
+ //
+ const string& at ((*l)["bin.lib"].as<const string&> ());
+
+ if (lso ? at == "static" : at == "shared")
+ fail << (lso ? "shared" : "static") << " build of " << *l
+ << " is not available";
+
+ pt = lso ? static_cast<target*> (l->so) : l->a;
+
+ if (pt == nullptr)
+ {
+ const target_type& type (
+ lso ? libso::static_type : liba::static_type);
+
+ pt = &search (
+ prerequisite_key {&type, &p.dir, &p.name, &p.ext, &p.scope});
+ }
+
+ // Same logic as for obj{}
+ //
+ if (!group)
+ pe.target = pt;
+ }
else
pt = pe.target;
@@ -736,23 +842,11 @@ namespace build
//
inject_parent_fsdir (a, t);
- if (so)
- {
- switch (a)
- {
- case perform_update_id: return &perform_update;
- case perform_clean_id: return &perform_clean<select_so>;
- default: return default_action<select_so>; // Forward to prerequisites.
- }
- }
- else
+ switch (a)
{
- switch (a)
- {
- case perform_update_id: return &perform_update;
- case perform_clean_id: return &perform_clean<select_a>;
- default: return default_action<select_a>; // Forward to prerequisites.
- }
+ case perform_update_id: return &perform_update;
+ case perform_clean_id: return clean_table[so][lso];
+ default: return default_table[so][lso]; // Forward to prerequisites.
}
}
@@ -767,9 +861,17 @@ namespace build
bool so (tt == type::libso);
- if (so
- ? !execute_prerequisites<select_so> (a, t, t.mtime ())
- : !execute_prerequisites<select_a> (a, t, t.mtime ()))
+ // Decide which lib{} member to use for this target.
+ //
+ bool lso; // Lib-so.
+ switch (tt)
+ {
+ case type::exe: lso = true; break;
+ case type::liba: lso = false; break;
+ case type::libso: lso = true; break;
+ }
+
+ if (!execute_table[so][lso] (a, t, t.mtime ()))
return target_state::unchanged;
// Translate paths to relative (to working directory) ones. This
@@ -820,6 +922,12 @@ namespace build
;
else if ((ppt = pt->is_a<objso> ()))
;
+ else if (lib* l = pt->is_a<lib> ())
+ ppt = lso ? static_cast<path_target*> (l->so) : l->a;
+ else if ((ppt = pt->is_a<liba> ()))
+ ;
+ else if ((ppt = pt->is_a<libso> ()))
+ ;
else
continue;
diff --git a/build/dump.cxx b/build/dump.cxx
index 6496598..9299a86 100644
--- a/build/dump.cxx
+++ b/build/dump.cxx
@@ -21,6 +21,8 @@ namespace build
static void
dump_target (ostream& os, const target& t)
{
+ //@@ Need to print group info somehow.
+
os << t << ':';
for (const prerequisite_target& pe: t.prerequisites)