diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2016-07-17 08:18:45 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2016-07-17 08:18:45 +0200 |
commit | db3534da1bcbf286df7ac4c8736f5c5157399ced (patch) | |
tree | 9e65d9fe9806e794364db0cc8fe0d062b1f1cdc4 | |
parent | b439803cc5e09188c7b523333f6b71de3ba57dbf (diff) |
Redesign obj to exe/lib mapping
Specifically:
* objso{} and libso{} target types have been renamed to objs{} and libs{}
* obje{} has been added (so now we have obje{}, obja{}, and objs{})
* obje{} is now used for building exe{}
* object file extensions have been changed to use "hierarchical extensions"
that reflect the extension of the corresponding exe/lib target (instead of
the -so suffix we used), specifically:
obje{}: foo.o, (UNIX), foo.exe.o (MinGW), foo.exe.obj (Windows)
obja{}: foo.a.o (UNIX, MinGW), foo.lib.obj (Windows)
objs{}: foo.so.o (UNIX), foo.dylib.o (Darwin), foo.dll.o (MinGW),
foo.dll.obj (Windows)
-rw-r--r-- | build2/bin/module.cxx | 51 | ||||
-rw-r--r-- | build2/bin/rule.cxx | 61 | ||||
-rw-r--r-- | build2/bin/target | 19 | ||||
-rw-r--r-- | build2/bin/target.cxx | 105 | ||||
-rw-r--r-- | build2/buildfile | 1 | ||||
-rw-r--r-- | build2/cxx/common | 60 | ||||
-rw-r--r-- | build2/cxx/common.cxx | 70 | ||||
-rw-r--r-- | build2/cxx/compile.cxx | 80 | ||||
-rw-r--r-- | build2/cxx/install.cxx | 14 | ||||
-rw-r--r-- | build2/cxx/link | 20 | ||||
-rw-r--r-- | build2/cxx/link.cxx | 226 | ||||
-rw-r--r-- | build2/cxx/module.cxx | 30 | ||||
-rw-r--r-- | build2/cxx/utility.cxx | 4 | ||||
-rw-r--r-- | build2/cxx/windows-rpath.cxx | 4 | ||||
-rw-r--r-- | build2/target | 2 |
15 files changed, 463 insertions, 284 deletions
diff --git a/build2/bin/module.cxx b/build2/bin/module.cxx index 306d8de..334384a 100644 --- a/build2/bin/module.cxx +++ b/build2/bin/module.cxx @@ -31,7 +31,7 @@ namespace build2 // static const strings exe_lib {"shared", "static"}; static const strings liba_lib {"static"}; - static const strings libso_lib {"shared"}; + static const strings libs_lib {"shared"}; // Apply the specified stem to the config.bin.pattern. If there is no // pattern, then return the stem itself. Assume the pattern is valid, @@ -73,22 +73,22 @@ namespace build2 // Note: some overridable, some not. // - v.insert<string> ("config.bin.target", true); - v.insert<string> ("config.bin.pattern", true); + v.insert<string> ("config.bin.target", true); + v.insert<string> ("config.bin.pattern", true); - v.insert<path> ("config.bin.ar", true); - v.insert<path> ("config.bin.ranlib", true); + v.insert<path> ("config.bin.ar", true); + v.insert<path> ("config.bin.ranlib", true); - v.insert<string> ("config.bin.lib", true); - v.insert<strings> ("config.bin.exe.lib", true); - v.insert<strings> ("config.bin.liba.lib", true); - v.insert<strings> ("config.bin.libso.lib", true); - v.insert<dir_paths> ("config.bin.rpath", true); + v.insert<string> ("config.bin.lib", true); + v.insert<strings> ("config.bin.exe.lib", true); + v.insert<strings> ("config.bin.liba.lib", true); + v.insert<strings> ("config.bin.libs.lib", true); + v.insert<dir_paths> ("config.bin.rpath", true); v.insert<string> ("bin.lib"); v.insert<strings> ("bin.exe.lib"); v.insert<strings> ("bin.liba.lib"); - v.insert<strings> ("bin.libso.lib"); + v.insert<strings> ("bin.libs.lib"); v.insert<dir_paths> ("bin.rpath"); v.insert<string> ("bin.libprefix", true); @@ -133,12 +133,12 @@ namespace build2 v = required (r, "config.bin.liba.lib", liba_lib).first; } - // config.bin.libso.lib + // config.bin.libs.lib // { - value& v (b.assign ("bin.libso.lib")); + value& v (b.assign ("bin.libs.lib")); if (!v) - v = required (r, "config.bin.libso.lib", libso_lib).first; + v = required (r, "config.bin.libs.lib", libs_lib).first; } // config.bin.rpath @@ -353,13 +353,14 @@ namespace build2 { auto& t (b.target_types); - t.insert<obja> (); - t.insert<objso> (); - t.insert<obj> (); - t.insert<exe> (); - t.insert<liba> (); - t.insert<libso> (); - t.insert<lib> (); + t.insert<obje> (); + t.insert<obja> (); + t.insert<objs> (); + t.insert<obj> (); + t.insert<exe> (); + t.insert<liba> (); + t.insert<libs> (); + t.insert<lib> (); } // Register rules. @@ -407,15 +408,15 @@ namespace build2 // And a library that wants to override any such overrides (e.g., // because it does have main()) can do: // - // libso{foo}: install.mode=755 + // libs{foo}: install.mode=755 // // Everyone is happy then? Not Windows users. When targeting Windows - // libso{} is an import library and shouldn't be exec. + // libs{} is an import library and shouldn't be exec. // - install_path<libso> (b, dir_path ("lib")); // Install into install.lib. + install_path<libs> (b, dir_path ("lib")); // Install into install.lib. if (tclass == "windows") - install_mode<libso> (b, "644"); + install_mode<libs> (b, "644"); install_path<liba> (b, dir_path ("lib")); // Install into install.lib. install_mode<liba> (b, "644"); diff --git a/build2/bin/rule.cxx b/build2/bin/rule.cxx index 072e931..7710a53 100644 --- a/build2/bin/rule.cxx +++ b/build2/bin/rule.cxx @@ -23,7 +23,7 @@ namespace build2 match (action a, target& t, const string&) const { fail << diag_doing (a, t) << " target group" << - info << "explicitly select either obja{} or objso{} member"; + info << "explicitly select obje{}, obja{}, or objs{} member"; return nullptr; } @@ -33,25 +33,25 @@ namespace build2 // lib // - // The whole logic is pretty much as if we had our two group - // members as our prerequisites. + // The whole logic is pretty much as if we had our two group members as + // our prerequisites. // match_result lib_rule:: - match (action a, target& xt, const string&) const + match (action act, target& xt, const string&) const { lib& t (static_cast<lib&> (xt)); // @@ We have to re-query it on each match_only()! // Get the library type to build. If not set for a target, this - // should be configured at the project scope by init_lib(). + // should be configured at the project scope by init(). // const string& type (cast<string> (t["bin.lib"])); - bool ar (type == "static" || type == "both"); - bool so (type == "shared" || type == "both"); + bool a (type == "static" || type == "both"); + bool s (type == "shared" || type == "both"); - if (!ar && !so) + if (!a && !s) fail << "unknown library type: " << type << info << "'static', 'shared', or 'both' expected"; @@ -63,20 +63,20 @@ namespace build2 // meta-information about the library, such as the options to use // when linking it, etc. // - if (ar) + if (a) { if (t.a == nullptr) t.a = &search<liba> (t.dir, t.out, t.name, nullptr, nullptr); - match_only (a, *t.a); + match_only (act, *t.a); } - if (so) + if (s) { - if (t.so == nullptr) - t.so = &search<libso> (t.dir, t.out, t.name, nullptr, nullptr); + if (t.s == nullptr) + t.s = &search<libs> (t.dir, t.out, t.name, nullptr, nullptr); - match_only (a, *t.so); + match_only (act, *t.s); } match_result mr (t, &type); @@ -84,35 +84,35 @@ namespace build2 // If there is an outer operation, indicate that we match // unconditionally so that we don't override ourselves. // - if (a.outer_operation () != 0) - mr.recipe_action = action (a.meta_operation (), a.operation ()); + if (act.outer_operation () != 0) + mr.recipe_action = action (act.meta_operation (), act.operation ()); return mr; } recipe lib_rule:: - apply (action a, target& xt, const match_result& mr) const + apply (action act, target& xt, const match_result& mr) const { lib& t (static_cast<lib&> (xt)); const string& type (*static_cast<const string*> (mr.cpvalue)); - bool ar (type == "static" || type == "both"); - bool so (type == "shared" || type == "both"); + bool a (type == "static" || type == "both"); + bool s (type == "shared" || type == "both"); // Now we do full match. // - if (ar) - build2::match (a, *t.a); + if (a) + build2::match (act, *t.a); - if (so) - build2::match (a, *t.so); + if (s) + build2::match (act, *t.s); return &perform; } target_state lib_rule:: - perform (action a, target& xt) + perform (action act, target& xt) { lib& t (static_cast<lib&> (xt)); @@ -122,11 +122,12 @@ namespace build2 // // const string& type (cast<string> (t["bin.lib"])); - bool ar (type == "static" || type == "both"); - bool so (type == "shared" || type == "both"); - target* m1 (ar ? t.a : nullptr); - target* m2 (so ? t.so : nullptr); + bool a (type == "static" || type == "both"); + bool s (type == "shared" || type == "both"); + + target* m1 (a ? t.a : nullptr); + target* m2 (s ? t.s : nullptr); if (current_mode == execution_mode::last) swap (m1, m2); @@ -134,10 +135,10 @@ namespace build2 target_state r (target_state::unchanged); if (m1 != nullptr) - r |= execute (a, *m1); + r |= execute (act, *m1); if (m2 != nullptr) - r |= execute (a, *m2); + r |= execute (act, *m2); return r; } diff --git a/build2/bin/target b/build2/bin/target index f386592..8c32e84 100644 --- a/build2/bin/target +++ b/build2/bin/target @@ -16,6 +16,16 @@ namespace build2 { // The obj{} target group. // + class obje: public file + { + public: + using file::file; + + public: + static const target_type static_type; + virtual const target_type& dynamic_type () const {return static_type;} + }; + class obja: public file { public: @@ -26,7 +36,7 @@ namespace build2 virtual const target_type& dynamic_type () const {return static_type;} }; - class objso: public file + class objs: public file { public: using file::file; @@ -41,8 +51,9 @@ namespace build2 public: using target::target; + obje* e {nullptr}; obja* a {nullptr}; - objso* so {nullptr}; + objs* s {nullptr}; public: static const target_type static_type; @@ -71,7 +82,7 @@ namespace build2 virtual const target_type& dynamic_type () const {return static_type;} }; - class libso: public file + class libs: public file { public: using file::file; @@ -87,7 +98,7 @@ namespace build2 using target::target; liba* a {nullptr}; - libso* so {nullptr}; + libs* s {nullptr}; virtual void reset (action_type); diff --git a/build2/bin/target.cxx b/build2/bin/target.cxx index f141d97..3f16467 100644 --- a/build2/bin/target.cxx +++ b/build2/bin/target.cxx @@ -13,14 +13,41 @@ namespace build2 extern const char ext_var[] = "extension"; // VC 19 rejects constexpr. static target* + obje_factory (const target_type&, + dir_path dir, + dir_path out, + string n, + const string* ext) + { + obj* o (targets.find<obj> (dir, out, n)); + obje* e (new obje (move (dir), move (out), move (n), ext)); + + if ((e->group = o)) + o->e = e; + + return e; + } + + const target_type obje::static_type + { + "obje", + &file::static_type, + &obje_factory, + &target_extension_var<ext_var, nullptr>, + nullptr, + &search_target, // Note: not _file(); don't look for an existing file. + false + }; + + static target* obja_factory (const target_type&, dir_path dir, dir_path out, string n, - const string* e) + const string* ext) { obj* o (targets.find<obj> (dir, out, n)); - obja* a (new obja (move (dir), move (out), move (n), e)); + obja* a (new obja (move (dir), move (out), move (n), ext)); if ((a->group = o)) o->a = a; @@ -40,26 +67,26 @@ namespace build2 }; static target* - objso_factory (const target_type&, + objs_factory (const target_type&, dir_path dir, dir_path out, string n, - const string* e) + const string* ext) { obj* o (targets.find<obj> (dir, out, n)); - objso* so (new objso (move (dir), move (out), move (n), e)); + objs* s (new objs (move (dir), move (out), move (n), ext)); - if ((so->group = o)) - o->so = so; + if ((s->group = o)) + o->s = s; - return so; + return s; } - const target_type objso::static_type + const target_type objs::static_type { - "objso", + "objs", &file::static_type, - &objso_factory, + &objs_factory, &target_extension_var<ext_var, nullptr>, nullptr, &search_target, // Note: not _file(); don't look for an existing file. @@ -71,17 +98,22 @@ namespace build2 dir_path dir, dir_path out, string n, - const string* e) + const string* ext) { + obje* e (targets.find<obje> (dir, out, n)); obja* a (targets.find<obja> (dir, out, n)); - objso* so (targets.find<objso> (dir, out, n)); - obj* o (new obj (move (dir), move (out), move (n), e)); + objs* s (targets.find<objs> (dir, out, n)); + + obj* o (new obj (move (dir), move (out), move (n), ext)); + + if ((o->e = e)) + e->group = o; if ((o->a = a)) a->group = o; - if ((o->so = so)) - so->group = o; + if ((o->s = s)) + s->group = o; return o; } @@ -124,12 +156,12 @@ namespace build2 dir_path d, dir_path o, string n, - const string* e) + const string* ext) { // Only link-up to the group if the types match exactly. // lib* l (t == liba::static_type ? targets.find<lib> (d, o, n) : nullptr); - liba* a (new liba (move (d), move (o), move (n), e)); + liba* a (new liba (move (d), move (o), move (n), ext)); if ((a->group = l)) l->a = a; @@ -161,28 +193,28 @@ namespace build2 }; static target* - libso_factory (const target_type& t, - dir_path d, - dir_path o, - string n, - const string* e) + libs_factory (const target_type& t, + dir_path d, + dir_path o, + string n, + const string* ext) { // Only link-up to the group if the types match exactly. // - lib* l (t == libso::static_type ? targets.find<lib> (d, o, n) : nullptr); - libso* so (new libso (move (d), move (o), move (n), e)); + lib* l (t == libs::static_type ? targets.find<lib> (d, o, n) : nullptr); + libs* s (new libs (move (d), move (o), move (n), ext)); - if ((so->group = l)) - l->so = so; + if ((s->group = l)) + l->s = s; - return so; + return s; } - const target_type libso::static_type + const target_type libs::static_type { - "libso", + "libs", &file::static_type, - &libso_factory, + &libs_factory, &target_extension_var<ext_var, nullptr>, nullptr, &search_file, @@ -203,17 +235,18 @@ namespace build2 dir_path d, dir_path o, string n, - const string* e) + const string* ext) { liba* a (targets.find<liba> (d, o, n)); - libso* so (targets.find<libso> (d, o, n)); - lib* l (new lib (move (d), move (o), move (n), e)); + libs* s (targets.find<libs> (d, o, n)); + + lib* l (new lib (move (d), move (o), move (n), ext)); if ((l->a = a)) a->group = l; - if ((l->so = so)) - so->group = l; + if ((l->s = s)) + s->group = l; return l; } diff --git a/build2/buildfile b/build2/buildfile index 5474fbd..cbd09e8 100644 --- a/build2/buildfile +++ b/build2/buildfile @@ -44,6 +44,7 @@ exe{b}: \ config/{hxx cxx}{ module } \ config/{hxx cxx}{ operation } \ config/{hxx txx cxx}{ utility } \ + cxx/{hxx cxx}{ common } \ cxx/{hxx cxx}{ compile } \ cxx/{hxx cxx}{ guess } \ cxx/{hxx cxx}{ install } \ diff --git a/build2/cxx/common b/build2/cxx/common new file mode 100644 index 0000000..77f1149 --- /dev/null +++ b/build2/cxx/common @@ -0,0 +1,60 @@ +// file : build2/cxx/common -*- C++ -*- +// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef BUILD2_CXX_COMMON +#define BUILD2_CXX_COMMON + +#include <build2/types> +#include <build2/utility> + +#include <build2/bin/target> + +namespace build2 +{ + namespace cxx + { + // Compile/link output type (executable, static, or shared). + // + enum class otype {e, a, s}; + + inline otype + compile_type (target& t) + { + return + t.is_a<bin::obje> () ? otype::e : + t.is_a<bin::obja> () ? otype::a : + otype::s; + } + + inline otype + link_type (target& t) + { + return + t.is_a<bin::exe> () ? otype::e : + t.is_a<bin::liba> () ? otype::a : + otype::s; + } + + // Library link order. + // + enum class lorder {a, s, a_s, s_a}; + + // The reason we pass scope and not the target is because this function is + // called not only for exe/lib but also for obj as part of the library + // meta-information protocol implementation. Normally the bin.*.lib values + // will be project-wide. With this scheme they can be customized on the + // per-directory basis but not per-target which means all exe/lib in the + // same directory have to have the same link order. + // + lorder + link_order (scope& base, otype); + + // Given the link order return the library member (liba or libs) to link. + // + target& + link_member (bin::lib&, lorder); + } +} + +#endif // BUILD2_CXX_COMMON diff --git a/build2/cxx/common.cxx b/build2/cxx/common.cxx new file mode 100644 index 0000000..0b66eb5 --- /dev/null +++ b/build2/cxx/common.cxx @@ -0,0 +1,70 @@ +// file : build2/cxx/common.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include <build2/cxx/common> + +#include <build2/variable> +#include <build2/algorithm> + +using namespace std; + +namespace build2 +{ + namespace cxx + { + using namespace bin; + + lorder + link_order (scope& bs, otype ot) + { + const char* var; + + switch (ot) + { + case otype::e: var = "bin.exe.lib"; break; + case otype::a: var = "bin.liba.lib"; break; + case otype::s: var = "bin.libs.lib"; break; + } + + const auto& v (cast<strings> (bs[var])); + return v[0] == "shared" + ? v.size () > 1 && v[1] == "static" ? lorder::s_a : lorder::s + : v.size () > 1 && v[1] == "shared" ? lorder::a_s : lorder::a; + } + + target& + link_member (bin::lib& l, lorder lo) + { + bool ls (true); + const string& at (cast<string> (l["bin.lib"])); // Available members. + + switch (lo) + { + case lorder::a: + case lorder::a_s: + ls = false; // Fall through. + case lorder::s: + case lorder::s_a: + { + if (ls ? at == "static" : at == "shared") + { + if (lo == lorder::a_s || lo == lorder::s_a) + ls = !ls; + else + fail << (ls ? "shared" : "static") << " variant of " << l + << " is not available"; + } + } + } + + target* r (ls ? static_cast<target*> (l.s) : l.a); + + if (r == nullptr) + r = &search (ls ? libs::static_type : liba::static_type, + prerequisite_key {nullptr, l.key (), nullptr}); + + return *r; + } + } +} diff --git a/build2/cxx/compile.cxx b/build2/cxx/compile.cxx index 504df7f..645e818 100644 --- a/build2/cxx/compile.cxx +++ b/build2/cxx/compile.cxx @@ -21,6 +21,7 @@ #include <build2/cxx/target> #include <build2/cxx/link> +#include <build2/cxx/common> #include <build2/cxx/utility> @@ -69,15 +70,57 @@ namespace build2 path_target& t (static_cast<path_target&> (xt)); scope& rs (t.root_scope ()); + const string& cid (cast<string> (rs["cxx.id"])); + const string& tsys (cast<string> (rs["cxx.target.system"])); const string& tclass (cast<string> (rs["cxx.target.class"])); + otype ct (compile_type (t)); + // Derive file name from target name. // if (t.path ().empty ()) { - const char* ext (cid == "msvc" ? "obj" : "o"); - t.derive_path (ext, nullptr, (t.is_a<objso> () ? "-so" : nullptr)); + const char* e (nullptr); + + if (tsys == "win32-msvc") + { + switch (ct) + { + case otype::e: e = "exe.obj"; break; + case otype::a: e = "lib.obj"; break; + case otype::s: e = "dll.obj"; break; + } + } + else if (tsys == "mingw32") + { + switch (ct) + { + case otype::e: e = "exe.o"; break; + case otype::a: e = "a.o"; break; + case otype::s: e = "dll.o"; break; + } + } + else if (tsys == "darwin") + { + switch (ct) + { + case otype::e: e = "o"; break; + case otype::a: e = "a.o"; break; + case otype::s: e = "dylib.o"; break; + } + } + else + { + switch (ct) + { + case otype::e: e = "o"; break; + case otype::a: e = "a.o"; break; + case otype::s: e = "so.o"; break; + } + } + + t.derive_path (e); } // Inject dependency on the output directory. @@ -102,7 +145,7 @@ namespace build2 // meta-information protocol". See also append_lib_options() // above. // - if (p.is_a<lib> () || p.is_a<liba> () || p.is_a<libso> ()) + if (p.is_a<lib> () || p.is_a<liba> () || p.is_a<libs> ()) { if (a.operation () == update_id) { @@ -184,7 +227,7 @@ namespace build2 { target& pt (*p.target); // Already searched and matched. - if (pt.is_a<lib> () || pt.is_a<liba> () || pt.is_a<libso> ()) + if (pt.is_a<lib> () || pt.is_a<liba> () || pt.is_a<libs> ()) hash_lib_options (cs, pt, "cxx.export.poptions"); } @@ -192,7 +235,7 @@ namespace build2 hash_options (cs, t, "cxx.coptions"); hash_std (cs, rs, cid, t); - if (t.is_a<objso> ()) + if (ct == otype::s) { // On Darwin, Win32 -fPIC is the default. // @@ -369,7 +412,7 @@ namespace build2 if (t == nullptr) continue; - if (t->is_a<lib> () || t->is_a<liba> () || t->is_a<libso> ()) + if (t->is_a<lib> () || t->is_a<liba> () || t->is_a<libs> ()) append_lib_prefixes (m, *t); } @@ -389,7 +432,7 @@ namespace build2 { target& pt (*p.target); // Already searched and matched. - if (pt.is_a<lib> () || pt.is_a<liba> () || pt.is_a<libso> ()) + if (pt.is_a<lib> () || pt.is_a<liba> () || pt.is_a<libs> ()) append_lib_prefixes (m, pt); } @@ -617,7 +660,7 @@ namespace build2 { target& pt (*p.target); // Already searched and matched. - if (pt.is_a<lib> () || pt.is_a<liba> () || pt.is_a<libso> ()) + if (pt.is_a<lib> () || pt.is_a<liba> () || pt.is_a<libs> ()) append_lib_options (args, pt, "cxx.export.poptions"); } @@ -628,7 +671,7 @@ namespace build2 append_options (args, t, "cxx.coptions"); append_std (args, rs, cid, t, cxx_std); - if (t.is_a<objso> ()) + if (t.is_a<objs> ()) { // On Darwin, Win32 -fPIC is the default. // @@ -1181,19 +1224,22 @@ namespace build2 if (s == nullptr) return target_state::unchanged; - // Translate paths to relative (to working directory) ones. This - // results in easier to read diagnostics. - // - path relo (relative (t.path ())); - path rels (relative (s->path ())); - scope& rs (t.root_scope ()); + const path& cxx (cast<path> (rs["config.cxx"])); const string& cid (cast<string> (rs["cxx.id"])); const string& tclass (cast<string> (rs["cxx.target.class"])); + otype ct (compile_type (t)); + cstrings args {cxx.string ().c_str ()}; + // Translate paths to relative (to working directory) ones. This + // results in easier to read diagnostics. + // + path relo (relative (t.path ())); + path rels (relative (s->path ())); + // Add cxx.export.poptions from prerequisite libraries. Note that // here we don't need to see group members (see apply()). // @@ -1201,7 +1247,7 @@ namespace build2 { target& pt (*p.target); // Already searched and matched. - if (pt.is_a<lib> () || pt.is_a<liba> () || pt.is_a<libso> ()) + if (pt.is_a<lib> () || pt.is_a<liba> () || pt.is_a<libs> ()) append_lib_options (args, pt, "cxx.export.poptions"); } @@ -1268,7 +1314,7 @@ namespace build2 } else { - if (t.is_a<objso> ()) + if (ct == otype::s) { // On Darwin, Win32 -fPIC is the default. // diff --git a/build2/cxx/install.cxx b/build2/cxx/install.cxx index f6f502a..e07d115 100644 --- a/build2/cxx/install.cxx +++ b/build2/cxx/install.cxx @@ -6,8 +6,9 @@ #include <build2/bin/target> -#include <build2/cxx/target> #include <build2/cxx/link> +#include <build2/cxx/common> +#include <build2/cxx/target> using namespace std; @@ -31,17 +32,20 @@ namespace build2 // If this is a shared library prerequisite, install it as long as it // is in the same amalgamation as we are. // - if ((t.is_a<exe> () || t.is_a<libso> ()) && - (p.is_a<lib> () || p.is_a<libso> ())) + // @@ Shouldn't we also install a static library prerequisite of a + // static library? + // + if ((t.is_a<exe> () || t.is_a<libs> ()) && + (p.is_a<lib> () || p.is_a<libs> ())) { target* pt (&p.search ()); // If this is the lib{} group, pick a member which we would link. // if (lib* l = pt->is_a<lib> ()) - pt = &link::link_member (*l, link::link_order (t)); + pt = &link_member (*l, link_order (t.base_scope (), link_type (t))); - if (pt->is_a<libso> ()) // Can be liba{}. + if (pt->is_a<libs> ()) // Can be liba{}. return pt->in (t.weak_scope ()) ? pt : nullptr; } diff --git a/build2/cxx/link b/build2/cxx/link index ca45e17..4f00ea0 100644 --- a/build2/cxx/link +++ b/build2/cxx/link @@ -33,26 +33,6 @@ namespace build2 static link instance; - public: - enum class type {e, a, so}; - enum class order {a, so, a_so, so_a}; - - static type - link_type (target& t) - { - return t.is_a<bin::exe> () - ? type::e - : (t.is_a<bin::liba> () ? type::a : type::so); - } - - static order - link_order (target&); - - // Determine the library member (liba or libso) to link. - // - static target& - link_member (bin::lib&, order); - private: friend class compile; diff --git a/build2/cxx/link.cxx b/build2/cxx/link.cxx index 181c2b8..002cd42 100644 --- a/build2/cxx/link.cxx +++ b/build2/cxx/link.cxx @@ -19,6 +19,7 @@ #include <build2/bin/target> #include <build2/cxx/target> +#include <build2/cxx/common> #include <build2/cxx/utility> using namespace std; @@ -30,58 +31,6 @@ namespace build2 { using namespace bin; - link::order link:: - link_order (target& t) - { - const char* var; - - switch (link_type (t)) - { - case type::e: var = "bin.exe.lib"; break; - case type::a: var = "bin.liba.lib"; break; - case type::so: var = "bin.libso.lib"; break; - } - - const auto& v (cast<strings> (t[var])); - return v[0] == "shared" - ? v.size () > 1 && v[1] == "static" ? order::so_a : order::so - : v.size () > 1 && v[1] == "shared" ? order::a_so : order::a; - } - - target& link:: - link_member (bin::lib& l, order lo) - { - bool lso (true); - const string& at (cast<string> (l["bin.lib"])); // Available types. - - switch (lo) - { - case order::a: - case order::a_so: - lso = false; // Fall through. - case order::so: - case order::so_a: - { - if (lso ? at == "static" : at == "shared") - { - if (lo == order::a_so || lo == order::so_a) - lso = !lso; - else - fail << (lso ? "shared" : "static") << " build of " << l - << " is not available"; - } - } - } - - target* r (lso ? static_cast<target*> (l.so) : l.a); - - if (r == nullptr) - r = &search (lso ? libso::static_type : liba::static_type, - prerequisite_key {nullptr, l.key (), nullptr}); - - return *r; - } - // Extract system library search paths from GCC or compatible (Clang, // Intel C++) using the -print-search-dirs option. // @@ -261,7 +210,7 @@ namespace build2 const string& tsys (cast<string> (rs["cxx.target.system"])); bool l (p.is_a<lib> ()); - const string* ext (l ? nullptr : p.ext); // Only for liba/libso. + const string* ext (l ? nullptr : p.ext); // Only for liba/libs. // Then figure out what we need to search for. // @@ -302,12 +251,12 @@ namespace build2 } } - // libso + // libs // path sn; const string* se (nullptr); - if (l || p.is_a<libso> ()) + if (l || p.is_a<libs> ()) { const char* e (""); @@ -358,7 +307,7 @@ namespace build2 spc = extract_library_paths (p.scope); liba* a (nullptr); - libso* s (nullptr); + libs* s (nullptr); path f; // Reuse the buffer. const dir_path* pd; @@ -390,7 +339,7 @@ namespace build2 } } - // libso + // libs // if (!sn.empty ()) { @@ -403,7 +352,7 @@ namespace build2 // Above we searched for the import library (.dll.a) but if it's // not found, then we also search for the .dll (unless the // extension was specified explicitly) since we can link to it - // directly. Note also that the resulting libso{} would end up + // directly. Note also that the resulting libs{} would end up // being the .dll. // if (mt == timestamp_nonexistent && ext == nullptr) @@ -416,7 +365,7 @@ namespace build2 if (mt != timestamp_nonexistent) { - s = &targets.insert<libso> (d, dir_path (), p.name, se, trace); + s = &targets.insert<libs> (d, dir_path (), p.name, se, trace); if (s->path ().empty ()) s->path (move (f)); @@ -444,7 +393,7 @@ namespace build2 // It should automatically link-up to the members we have found. // assert (l.a == a); - assert (l.so == s); + assert (l.s == s); // Set the bin.lib variable to indicate what's available. // @@ -474,11 +423,11 @@ namespace build2 // // - if there is no .o, are we going to check if the one derived // from target exist or can be built? A: No. - // What if there is a library. Probably ok if .a, not if .so. + // What if there is a library. Probably ok if static, not if shared, // (i.e., a utility library). // - type lt (link_type (t)); + otype lt (link_type (t)); // Scan prerequisites and see if we can work with what we've got. // @@ -495,22 +444,34 @@ namespace build2 { seen_c = seen_c || true; } + else if (p.is_a<obj> ()) + { + seen_obj = seen_obj || true; + } + else if (p.is_a<obje> ()) + { + if (lt != otype::e) + fail << "obje{} as prerequisite of " << t; + + seen_obj = seen_obj || true; + } else if (p.is_a<obja> ()) { - if (lt == type::so) - fail << "shared library " << t << " prerequisite " << p - << " is static object"; + if (lt != otype::a) + fail << "obja{} as prerequisite of " << t; seen_obj = seen_obj || true; } - else if (p.is_a<objso> () || - p.is_a<obj> ()) + else if (p.is_a<objs> ()) { + if (lt != otype::s) + fail << "objs{} as prerequisite of " << t; + seen_obj = seen_obj || true; } - else if (p.is_a<liba> () || - p.is_a<libso> () || - p.is_a<lib> ()) + else if (p.is_a<lib> () || + p.is_a<liba> () || + p.is_a<libs> ()) { seen_lib = seen_lib || true; } @@ -530,7 +491,7 @@ namespace build2 // "library meta-information protocol". Don't do this if we are // called from the install rule just to check if we would match. // - if (seen_lib && lt != type::e && + if (seen_lib && lt != otype::e && a.operation () != install_id && a.outer_operation () != install_id) { if (t.group != nullptr) @@ -540,7 +501,7 @@ namespace build2 for (prerequisite_member p: group_prerequisite_members (a, t)) { - if (p.is_a<lib> () || p.is_a<liba> () || p.is_a<libso> ()) + if (p.is_a<lib> () || p.is_a<liba> () || p.is_a<libs> ()) { target* pt (nullptr); @@ -583,9 +544,8 @@ namespace build2 const string& tsys (cast<string> (rs["cxx.target.system"])); const string& tclass (cast<string> (rs["cxx.target.class"])); - type lt (link_type (t)); - order lo (link_order (t)); - bool so (lt == type::so); + otype lt (link_type (t)); + lorder lo (link_order (bs, lt)); // Derive file name from target name. // @@ -596,7 +556,7 @@ namespace build2 switch (lt) { - case type::e: + case otype::e: { if (tclass == "windows") e = "exe"; @@ -605,7 +565,7 @@ namespace build2 break; } - case type::a: + case otype::a: { // To be anally precise, let's use the ar id to decide how to name // the library in case, for example, someone wants to archive @@ -626,7 +586,7 @@ namespace build2 break; } - case type::so: + case otype::s: { //@@ VC: DLL name. @@ -637,9 +597,9 @@ namespace build2 } else if (tclass == "windows") { - // On Windows libso{} is an ad hoc group. The libso{} itself is + // On Windows libs{} is an ad hoc group. The libs{} itself is // the import library and we add dll{} as a member (see below). - // While at first it may seem strange that libso{} is the import + // While at first it may seem strange that libs{} is the import // library and not the DLL, if you meditate on it, you will see // it makes a lot of sense: our main task here is building and // for that we need the import library, not the DLL. @@ -697,7 +657,7 @@ namespace build2 { // DLL // - if (so) + if (lt == otype::s) { file& dll (add_adhoc (t, "dll")); @@ -707,7 +667,7 @@ namespace build2 // PDB // - if (lt != type::a && + if (lt != otype::a && cid == "msvc" && find_option ("/DEBUG", t, "cxx.loptions", true)) { @@ -734,6 +694,10 @@ namespace build2 // When cleaning, ignore prerequisites that are not in the same // or a subdirectory of our project root. // + const target_type& ott (lt == otype::e ? obje::static_type : + lt == otype::a ? obja::static_type : + objs::static_type); + for (prerequisite_member p: group_prerequisite_members (a, t)) { target* pt (nullptr); @@ -758,11 +722,15 @@ namespace build2 // if (obj* o = pt->is_a<obj> ()) { - pt = so ? static_cast<target*> (o->so) : o->a; + switch (lt) + { + case otype::e: pt = o->e; break; + case otype::a: pt = o->a; break; + case otype::s: pt = o->s; break; + } if (pt == nullptr) - pt = &search (so ? objso::static_type : obja::static_type, - p.key ()); + pt = &search (ott, p.key ()); } else if (lib* l = pt->is_a<lib> ()) { @@ -785,10 +753,7 @@ namespace build2 bool group (!p.prerequisite.belongs (t)); // Group's prerequisite. const prerequisite_key& cp (p.key ()); // c(xx){} prerequisite key. - const target_type& otype ( - group - ? obj::static_type - : (so ? objso::static_type : obja::static_type)); + const target_type& tt (group ? obj::static_type : ott); // Come up with the obj*{} target. The c(xx){} prerequisite directory // can be relative (to the scope) or absolute. If it is relative, then @@ -807,7 +772,7 @@ namespace build2 { if (!cpd.sub (rs.src_path ())) fail << "out of project prerequisite " << cp << - info << "specify corresponding " << otype.name << "{} " + info << "specify corresponding " << tt.name << "{} " << "target explicitly"; d = rs.out_path () / cpd.leaf (rs.src_path ()); @@ -817,7 +782,7 @@ namespace build2 // obj*{} is always in the out tree. // target& ot ( - search (otype, d, dir_path (), *cp.tk.name, nullptr, cp.scope)); + search (tt, d, dir_path (), *cp.tk.name, nullptr, cp.scope)); // If we are cleaning, check that this target is in the same or // a subdirectory of our project root. @@ -838,11 +803,16 @@ namespace build2 if (group) { obj& o (static_cast<obj&> (ot)); - pt = so ? static_cast<target*> (o.so) : o.a; + + switch (lt) + { + case otype::e: pt = o.e; break; + case otype::a: pt = o.a; break; + case otype::s: pt = o.s; break; + } if (pt == nullptr) - pt = &search (so ? objso::static_type : obja::static_type, - o.dir, o.out, o.name, o.ext, nullptr); + pt = &search (ott, o.dir, o.out, o.name, o.ext, nullptr); } else pt = &ot; @@ -869,9 +839,9 @@ namespace build2 (p.is_a<cxx> () && (p1.is_a<hxx> () || p1.is_a<ixx> () || p1.is_a<txx> ())) || - p1.is_a<lib> () || + p1.is_a<lib> () || p1.is_a<liba> () || - p1.is_a<libso> ()) + p1.is_a<libs> ()) { continue; } @@ -893,7 +863,7 @@ namespace build2 << "be incompatible with existing target " << *pt << info << "existing prerequisite " << p1 << " does not match " << cp << - info << "specify corresponding " << otype.name << "{} target " + info << "specify corresponding " << tt.name << "{} target " << "explicitly"; found = true; @@ -918,7 +888,7 @@ namespace build2 // for (prerequisite& p: group_prerequisites (t)) { - if (p.is_a<lib> () || p.is_a<liba> () || p.is_a<libso> ()) + if (p.is_a<lib> () || p.is_a<liba> () || p.is_a<libs> ()) ot.prerequisites.emplace_back (p); } @@ -948,7 +918,7 @@ namespace build2 args.push_back (relative (pa->path ()).string ()); // string()&& append_libraries (args, *pa); } - else if (libso* ps = pt->is_a<libso> ()) + else if (libs* ps = pt->is_a<libs> ()) args.push_back (relative (ps->path ()).string ()); // string()&& } } @@ -963,17 +933,17 @@ namespace build2 cs.append (pa->path ().string ()); hash_libraries (cs, *pa); } - else if (libso* ps = pt->is_a<libso> ()) + else if (libs* ps = pt->is_a<libs> ()) cs.append (ps->path ().string ()); } } static void - append_rpath_link (strings& args, libso& t) + append_rpath_link (strings& args, libs& t) { for (target* pt: t.prerequisite_targets) { - if (libso* ls = pt->is_a<libso> ()) + if (libs* ls = pt->is_a<libs> ()) { args.push_back ("-Wl,-rpath-link," + ls->path ().directory ().string ()); @@ -1002,8 +972,7 @@ namespace build2 file& t (static_cast<file&> (xt)); - type lt (link_type (t)); - bool so (lt == type::so); + otype lt (link_type (t)); // Update prerequisites. // @@ -1020,7 +989,7 @@ namespace build2 path manifest; // Manifest itself (msvc) or compiled object file. timestamp rpath_timestamp (timestamp_nonexistent); // DLLs timestamp. - if (lt == type::e && tclass == "windows") + if (lt == otype::e && tclass == "windows") { // First determine if we need to add our rpath emulating assembly. The // assembly itself is generated later, after updating the target. Omit @@ -1130,7 +1099,7 @@ namespace build2 // Then the linker checksum (ar/ranlib or C++ compiler). // - if (lt == type::a) + if (lt == otype::a) { ranlib = rs["config.bin.ranlib"]; @@ -1195,7 +1164,7 @@ namespace build2 args.push_back (m); } - if (lt == type::a) + if (lt == otype::a) { if (cid == "msvc") ; else @@ -1238,7 +1207,7 @@ namespace build2 { // Set soname. // - if (so) + if (lt == otype::s) { const string& leaf (t.path ().leaf ().string ()); @@ -1277,7 +1246,7 @@ namespace build2 // for (target* pt: t.prerequisite_targets) { - if (libso* ls = pt->is_a<libso> ()) + if (libs* ls = pt->is_a<libs> ()) { if (a.outer_operation () != install_id) { @@ -1330,11 +1299,12 @@ namespace build2 path_target* ppt; liba* a (nullptr); - if ((ppt = pt->is_a<obja> ()) || - (ppt = pt->is_a<objso> ()) || - (lt != type::a && + if ((ppt = pt->is_a<obje> ()) || + (ppt = pt->is_a<obja> ()) || + (ppt = pt->is_a<objs> ()) || + (lt != otype::a && ((ppt = a = pt->is_a<liba> ()) || - (ppt = pt->is_a<libso> ())))) + (ppt = pt->is_a<libs> ())))) { cs.append (ppt->path ().string ()); @@ -1353,7 +1323,7 @@ namespace build2 // Treat them as inputs, not options. // - if (lt != type::a) + if (lt != otype::a) hash_options (cs, t, "cxx.libs"); if (dd.expect (cs.string ()) != nullptr) @@ -1387,7 +1357,7 @@ namespace build2 switch (lt) { - case type::e: + case otype::e: { if (cid == "msvc") { @@ -1449,7 +1419,7 @@ namespace build2 break; } - case type::a: + case otype::a: { args[0] = cast<path> (rs["config.bin.ar"]).string ().c_str (); @@ -1470,7 +1440,7 @@ namespace build2 break; } - case type::so: + case otype::s: { if (cid == "msvc") { @@ -1489,7 +1459,7 @@ namespace build2 if (tsys == "mingw32") { - // On Windows libso{} is the import stub and its first ad hoc + // On Windows libs{} is the import stub and its first ad hoc // group member is dll{}. // out = "-Wl,--out-implib=" + relt.string (); @@ -1514,13 +1484,13 @@ namespace build2 { path_target* ppt; liba* a (nullptr); - libso* so (nullptr); - if ((ppt = pt->is_a<obja> ()) || - (ppt = pt->is_a<objso> ()) || - (lt != type::a && + if ((ppt = pt->is_a<obje> ()) || + (ppt = pt->is_a<obja> ()) || + (ppt = pt->is_a<objs> ()) || + (lt != otype::a && ((ppt = a = pt->is_a<liba> ()) || - (ppt = so = pt->is_a<libso> ())))) + (ppt = pt->is_a<libs> ())))) { sargs.push_back (relative (ppt->path ()).string ()); // string()&& @@ -1543,7 +1513,7 @@ namespace build2 for (size_t i (0); i != sargs.size (); ++i) args.push_back (sargs[i].c_str ()); - if (lt != type::a) + if (lt != otype::a) append_options (args, t, "cxx.libs"); args.push_back (nullptr); @@ -1615,7 +1585,7 @@ namespace build2 // For Windows generate rpath-emulating assembly (unless updaing for // install). // - if (lt == type::e && tclass == "windows") + if (lt == otype::e && tclass == "windows") { if (a.outer_operation () != install_id) windows_rpath_assembly (t, rpath_timestamp, scratch); @@ -1644,12 +1614,12 @@ namespace build2 switch (link_type (t)) { - case type::a: + case otype::a: { e = {"+.d"}; break; } - case type::e: + case otype::e: { if (tclass == "windows") { @@ -1671,7 +1641,7 @@ namespace build2 break; } - case type::so: + case otype::s: { e = {"+.d"}; break; diff --git a/build2/cxx/module.cxx b/build2/cxx/module.cxx index 6a5469c..69e76a3 100644 --- a/build2/cxx/module.cxx +++ b/build2/cxx/module.cxx @@ -316,38 +316,40 @@ namespace build2 auto& r (b.rules); - r.insert<obja> (perform_update_id, "cxx.compile", compile::instance); + r.insert<obje> (perform_update_id, "cxx.compile", compile::instance); + r.insert<obje> (perform_clean_id, "cxx.compile", compile::instance); r.insert<obja> (perform_update_id, "cxx.compile", compile::instance); r.insert<obja> (perform_clean_id, "cxx.compile", compile::instance); - r.insert<objso> (perform_update_id, "cxx.compile", compile::instance); - r.insert<objso> (perform_clean_id, "cxx.compile", compile::instance); + r.insert<objs> (perform_update_id, "cxx.compile", compile::instance); + r.insert<objs> (perform_clean_id, "cxx.compile", compile::instance); - r.insert<exe> (perform_update_id, "cxx.link", link::instance); - r.insert<exe> (perform_clean_id, "cxx.link", link::instance); + r.insert<exe> (perform_update_id, "cxx.link", link::instance); + r.insert<exe> (perform_clean_id, "cxx.link", link::instance); r.insert<liba> (perform_update_id, "cxx.link", link::instance); r.insert<liba> (perform_clean_id, "cxx.link", link::instance); - r.insert<libso> (perform_update_id, "cxx.link", link::instance); - r.insert<libso> (perform_clean_id, "cxx.link", link::instance); + r.insert<libs> (perform_update_id, "cxx.link", link::instance); + r.insert<libs> (perform_clean_id, "cxx.link", link::instance); - // Register for configure so that we detect unresolved imports - // during configuration rather that later, e.g., during update. + // Register for configure so that we detect unresolved imports during + // configuration rather that later, e.g., during update. // + r.insert<obje> (configure_update_id, "cxx.compile", compile::instance); r.insert<obja> (configure_update_id, "cxx.compile", compile::instance); - r.insert<objso> (configure_update_id, "cxx.compile", compile::instance); + r.insert<objs> (configure_update_id, "cxx.compile", compile::instance); - r.insert<exe> (configure_update_id, "cxx.link", link::instance); + r.insert<exe> (configure_update_id, "cxx.link", link::instance); r.insert<liba> (configure_update_id, "cxx.link", link::instance); - r.insert<libso> (configure_update_id, "cxx.link", link::instance); + r.insert<libs> (configure_update_id, "cxx.link", link::instance); //@@ Should we check if install module was loaded (see bin)? // - r.insert<exe> (perform_install_id, "cxx.install", install::instance); + r.insert<exe> (perform_install_id, "cxx.install", install::instance); r.insert<liba> (perform_install_id, "cxx.install", install::instance); - r.insert<libso> (perform_install_id, "cxx.install", install::instance); + r.insert<libs> (perform_install_id, "cxx.install", install::instance); } // Configure "installability" of our target types. diff --git a/build2/cxx/utility.cxx b/build2/cxx/utility.cxx index ed57fd2..cf9c4d0 100644 --- a/build2/cxx/utility.cxx +++ b/build2/cxx/utility.cxx @@ -79,7 +79,7 @@ namespace build2 for (target* t: l.prerequisite_targets) { - if (t->is_a<lib> () || t->is_a<liba> () || t->is_a<libso> ()) + if (t->is_a<lib> () || t->is_a<liba> () || t->is_a<libs> ()) append_lib_options (args, *t, var); } @@ -93,7 +93,7 @@ namespace build2 for (target* t: l.prerequisite_targets) { - if (t->is_a<lib> () || t->is_a<liba> () || t->is_a<libso> ()) + if (t->is_a<lib> () || t->is_a<liba> () || t->is_a<libs> ()) hash_lib_options (csum, *t, var); } diff --git a/build2/cxx/windows-rpath.cxx b/build2/cxx/windows-rpath.cxx index 8f19f79..0bd4bc5 100644 --- a/build2/cxx/windows-rpath.cxx +++ b/build2/cxx/windows-rpath.cxx @@ -49,7 +49,7 @@ namespace build2 for (target* pt: t.prerequisite_targets) { - if (libso* ls = pt->is_a<libso> ()) + if (libs* ls = pt->is_a<libs> ()) { // This can be an installed library in which case we will have just // the import stub but may also have just the DLL. For now we don't @@ -84,7 +84,7 @@ namespace build2 { for (target* pt: t.prerequisite_targets) { - if (libso* ls = pt->is_a<libso> ()) + if (libs* ls = pt->is_a<libs> ()) { if (ls->member == nullptr) continue; diff --git a/build2/target b/build2/target index 955c2f9..28753df 100644 --- a/build2/target +++ b/build2/target @@ -192,7 +192,7 @@ namespace build2 // is an explicit mechanism for discovering the group's members. // // However, sometimes, we may want to create a group on the fly out of a - // normal target type. For example, we have the libso{} target type. But + // normal target type. For example, we have the libs{} target type. But // on Windows a shared library consist of (at least) two files: the import // library and the DLL itself. So we somehow need to be able to capture // that. One approach would be to imply the presence of the second file. |