diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2015-04-24 16:55:55 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2015-04-24 16:55:55 +0200 |
commit | f103f86ec3247ff27e7cc23dfce5e426f385ed8c (patch) | |
tree | 4efffb7d254e494944ce555d343c34d957238be0 | |
parent | 2a0f9e035f673f1ee387924501a31990de37f18d (diff) |
Take one on library linking
-rw-r--r-- | build/bin/module | 26 | ||||
-rw-r--r-- | build/bin/module.cxx | 58 | ||||
-rw-r--r-- | build/bin/rule.cxx | 26 | ||||
-rw-r--r-- | build/bin/target.cxx | 7 | ||||
-rw-r--r-- | build/buildfile | 2 | ||||
-rw-r--r-- | build/cxx/rule.cxx | 168 | ||||
-rw-r--r-- | build/dump.cxx | 2 |
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) |