From ecfae2da0b23631cee3e723a562f64f8aace6879 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 16 Jun 2020 09:43:27 +0200 Subject: Move common functionality from cc to bin --- libbuild2/bin/rule.cxx | 22 ++------ libbuild2/bin/rule.hxx | 12 ---- libbuild2/bin/types.hxx | 58 ++++++++++++++++++++ libbuild2/bin/utility.cxx | 134 +++++++++++++++++++++++++++++++++++++++++++++ libbuild2/bin/utility.hxx | 67 ++++++++++++++++------- libbuild2/bin/utility.ixx | 21 +++++++ libbuild2/cc/link-rule.cxx | 2 +- libbuild2/cc/types.hxx | 43 +++------------ libbuild2/cc/utility.cxx | 94 ------------------------------- libbuild2/cc/utility.hxx | 41 +++----------- libbuild2/cc/utility.ixx | 15 ----- 11 files changed, 283 insertions(+), 226 deletions(-) create mode 100644 libbuild2/bin/types.hxx create mode 100644 libbuild2/bin/utility.cxx create mode 100644 libbuild2/bin/utility.ixx diff --git a/libbuild2/bin/rule.cxx b/libbuild2/bin/rule.cxx index a2cdf8c..0abfcb5 100644 --- a/libbuild2/bin/rule.cxx +++ b/libbuild2/bin/rule.cxx @@ -9,6 +9,7 @@ #include #include +#include using namespace std; @@ -36,29 +37,14 @@ namespace build2 // The whole logic is pretty much as if we had our two group members as // our prerequisites. // - lib_rule::members lib_rule:: - build_members (const scope& rs) - { - const string& type (cast (rs["bin.lib"])); - - bool a (type == "static" || type == "both"); - bool s (type == "shared" || type == "both"); - - if (!a && !s) - fail << "unknown library type: " << type << - info << "'static', 'shared', or 'both' expected"; - - return members {a, s}; - } - bool lib_rule:: match (action a, target& xt, const string&) const { lib& t (xt.as ()); - members bm (a.meta_operation () != dist_id - ? build_members (t.root_scope ()) - : members {true, true}); + lmembers bm (a.meta_operation () != dist_id + ? link_members (t.root_scope ()) + : lmembers {true, true}); t.a = bm.a ? &search (t, t.dir, t.out, t.name) : nullptr; t.s = bm.s ? &search (t, t.dir, t.out, t.name) : nullptr; diff --git a/libbuild2/bin/rule.hxx b/libbuild2/bin/rule.hxx index 57c784f..074b46d 100644 --- a/libbuild2/bin/rule.hxx +++ b/libbuild2/bin/rule.hxx @@ -45,18 +45,6 @@ namespace build2 static target_state perform (action, const target&); - - // Return library types to build according to the bin.lib value (set - // on project's root scope by init()). - // - struct members - { - bool a; // static - bool s; // shared - }; - - static members - build_members (const scope&); }; } } diff --git a/libbuild2/bin/types.hxx b/libbuild2/bin/types.hxx new file mode 100644 index 0000000..773ef20 --- /dev/null +++ b/libbuild2/bin/types.hxx @@ -0,0 +1,58 @@ +// file : libbuild2/bin/types.hxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#ifndef LIBBUILD2_BIN_TYPES_HXX +#define LIBBUILD2_BIN_TYPES_HXX + +#include +#include + +namespace build2 +{ + namespace bin + { + // Compiler/linker output type (executable, static, or shared). + // + enum class otype {e, a, s}; + + struct ltype + { + otype type; + bool utility; // True for utility libraries. + + bool executable () const {return type == otype::e && !utility;} + bool library () const {return type != otype::e || utility;} + bool static_library () const {return type == otype::a || utility;} + bool shared_library () const {return type == otype::s && !utility;} + bool member_library () const {return type != otype::e;} + }; + + // Library group (lib{}) members to build. + // + struct lmembers + { + bool a; + bool s; + }; + + // Library link order. + // + enum class lorder {a, s, a_s, s_a}; + + // Link information: output type and link order. + // + struct linfo + { + otype type; + lorder order; + }; + + // Prerequisite target link flags (saved in prerequisite_target::data). + // + using lflags = uintptr_t; + + const lflags lflag_whole = 0x00000001U; // Link whole liba{}/libu*{}. + } +} + +#endif // LIBBUILD2_BIN_TYPES_HXX diff --git a/libbuild2/bin/utility.cxx b/libbuild2/bin/utility.cxx new file mode 100644 index 0000000..8032b79 --- /dev/null +++ b/libbuild2/bin/utility.cxx @@ -0,0 +1,134 @@ +// file : libbuild2/bin/utility.cxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#include + +#include +#include +#include // search() + +namespace build2 +{ + namespace bin + { + lorder + link_order (const scope& bs, otype ot) + { + // Initialize to suppress 'may be used uninitialized' warning produced + // by MinGW GCC 5.4.0. + // + const char* var (nullptr); + + 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 (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; + } + + lmembers + link_members (const scope& rs) + { + const string& type (cast (rs["bin.lib"])); + + bool a (type == "static" || type == "both"); + bool s (type == "shared" || type == "both"); + + if (!a && !s) + fail << "unknown library type: " << type << + info << "'static', 'shared', or 'both' expected"; + + return lmembers {a, s}; + } + + const target* + link_member (const libx& x, action a, linfo li, bool exist) + { + if (x.is_a ()) + { + // For libul{} that is linked to an executable the member choice + // should be dictated by the members of lib{} this libul{} is + // "primarily" for. If both are being built, then it seems natural to + // prefer static over shared since it could be faster (but I am sure + // someone will probably want this configurable). + // + if (li.type == otype::e) + { + // Utility libraries are project-local which means the primarily + // target should be in the same project as us. + // + li.type = link_members (x.root_scope ()).a ? otype::a : otype::s; + } + + const target_type& tt (li.type == otype::a + ? libua::static_type + : libus::static_type); + + // Called by the compile rule during execute. + // + return x.ctx.phase == run_phase::match && !exist + ? &search (x, tt, x.dir, x.out, x.name) + : search_existing (x.ctx, tt, x.dir, x.out, x.name); + } + else + { + assert (!exist); + + const lib& l (x.as ()); + + // Make sure group members are resolved. + // + group_view gv (resolve_members (a, l)); + assert (gv.members != nullptr); + + lorder lo (li.order); + + bool ls (true); + switch (lo) + { + case lorder::a: + case lorder::a_s: + ls = false; // Fall through. + case lorder::s: + case lorder::s_a: + { + if (ls ? l.s == nullptr : l.a == nullptr) + { + if (lo == lorder::a_s || lo == lorder::s_a) + ls = !ls; + else + fail << (ls ? "shared" : "static") << " variant of " << l + << " is not available"; + } + } + } + + return ls ? static_cast (l.s) : l.a; + } + } + + pattern_paths + lookup_pattern (const scope& rs) + { + pattern_paths r; + + // Theoretically, we could have both the pattern and the search paths, + // for example, the pattern can come first followed by the paths. + // + if (const string* v = cast_null (rs["bin.pattern"])) + { + (path::traits_type::is_separator (v->back ()) + ? r.paths + : r.pattern) = v->c_str (); + } + + return r; + } + } +} diff --git a/libbuild2/bin/utility.hxx b/libbuild2/bin/utility.hxx index 8fe0037..91b51f8 100644 --- a/libbuild2/bin/utility.hxx +++ b/libbuild2/bin/utility.hxx @@ -7,13 +7,55 @@ #include #include -#include -#include +#include + +#include +#include namespace build2 { namespace bin { + // @@ Here we conflate the term "link" to mean both linker output and + // linking of a library. + + // Linker output type from binary (exe{}, lib*{}) target. + // + ltype + link_type (const target&); + + // Library group (lib{}) members to build according to the bin.lib value. + // + LIBBUILD2_BIN_SYMEXPORT lmembers + link_members (const scope& rs); + + // Library link order. + // + // 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 + // metadata 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. + // + LIBBUILD2_BIN_SYMEXPORT lorder + link_order (const scope& base, otype); + + inline linfo + link_info (const scope& base, otype ot) + { + return linfo {ot, link_order (base, ot)}; + } + + // Given the link order return the library member to link. That is, liba{} + // or libs{} for lib{} and libua{} or libus{} for libul{}. + // + // If existing is true, then only return the member target if it exists + // (currently only used and supported for utility libraries). + // + LIBBUILD2_BIN_SYMEXPORT const target* + link_member (const libx&, action, linfo, bool existing = false); + // Lookup the bin.pattern value and split it into the pattern and the // search paths. // @@ -23,24 +65,11 @@ namespace build2 const char* paths = nullptr; }; - inline pattern_paths - lookup_pattern (const scope& rs) - { - pattern_paths r; - - // Theoretically, we could have both the pattern and the search paths, - // for example, the pattern can come first followed by the paths. - // - if (const string* v = cast_null (rs["bin.pattern"])) - { - (path::traits_type::is_separator (v->back ()) - ? r.paths - : r.pattern) = v->c_str (); - } - - return r; - } + LIBBUILD2_BIN_SYMEXPORT pattern_paths + lookup_pattern (const scope& rs); } } +#include + #endif // LIBBUILD2_BIN_UTILITY_HXX diff --git a/libbuild2/bin/utility.ixx b/libbuild2/bin/utility.ixx new file mode 100644 index 0000000..91c919b --- /dev/null +++ b/libbuild2/bin/utility.ixx @@ -0,0 +1,21 @@ +// file : libbuild2/bin/utility.ixx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +namespace build2 +{ + namespace bin + { + inline ltype + link_type (const target& t) + { + bool u (false); + otype o ( + t.is_a () || (u = t.is_a ()) ? otype::e : + t.is_a () || (u = t.is_a ()) ? otype::a : + t.is_a () || (u = t.is_a ()) ? otype::s : + static_cast (0xFF)); + + return ltype {o, u}; + } + } +} diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx index bc8eb8e..9b526ee 100644 --- a/libbuild2/cc/link-rule.cxx +++ b/libbuild2/cc/link-rule.cxx @@ -1050,7 +1050,7 @@ namespace build2 // Note also that the order in which we are adding these members // is important (see add_addhoc_member() for details). // - if (ot == otype::a || !lib_rule::build_members (rs).a) + if (ot == otype::a || !link_members (rs).a) { auto& pc (add_adhoc_member (t)); diff --git a/libbuild2/cc/types.hxx b/libbuild2/cc/types.hxx index f74fc94..0a6b6cc 100644 --- a/libbuild2/cc/types.hxx +++ b/libbuild2/cc/types.hxx @@ -9,10 +9,19 @@ #include +#include + namespace build2 { namespace cc { + using bin::otype; + using bin::ltype; + using bin::lorder; + using bin::linfo; + using bin::lflags; + using bin::lflag_whole; + // Translation unit information. // // We use absolute and normalized header path as the header unit module @@ -67,22 +76,6 @@ namespace build2 return os << (l == lang::c ? "C" : "C++"); } - // Compile/link output type (executable, static, or shared). - // - enum class otype {e, a, s}; - - struct ltype - { - otype type; - bool utility; // True for utility libraries. - - bool executable () const {return type == otype::e && !utility;} - bool library () const {return type != otype::e || utility;} - bool static_library () const {return type == otype::a || utility;} - bool shared_library () const {return type == otype::s && !utility;} - bool member_library () const {return type != otype::e;} - }; - // Compile target types. // struct compile_target_types @@ -91,24 +84,6 @@ namespace build2 const target_type& bmi; const target_type& hbmi; }; - - // Library link order. - // - enum class lorder {a, s, a_s, s_a}; - - // Link information: output type and link order. - // - struct linfo - { - otype type; - lorder order; - }; - - // Prerequisite link flags. - // - using lflags = uintptr_t; // To match prerequisite_target::data. - - const lflags lflag_whole = 0x00000001U; // Link whole liba{}/libu*}. } } diff --git a/libbuild2/cc/utility.cxx b/libbuild2/cc/utility.cxx index 93f94ae..283e1b4 100644 --- a/libbuild2/cc/utility.cxx +++ b/libbuild2/cc/utility.cxx @@ -4,11 +4,6 @@ #include #include -#include -#include // search() - -#include -#include using namespace std; @@ -22,94 +17,5 @@ namespace build2 const dir_path module_build_dir (dir_path (module_dir) /= "build"); const dir_path module_build_modules_dir ( dir_path (module_build_dir) /= "modules"); - - lorder - link_order (const scope& bs, otype ot) - { - // Initialize to suppress 'may be used uninitialized' warning produced - // by MinGW GCC 5.4.0. - // - const char* var (nullptr); - - 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 (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; - } - - const target* - link_member (const bin::libx& x, action a, linfo li, bool exist) - { - if (x.is_a ()) - { - // For libul{} that is linked to an executable the member choice - // should be dictated by the members of lib{} this libul{} is - // "primarily" for. If both are being built, then it seems natural to - // prefer static over shared since it could be faster (but I am sure - // someone will probably want this configurable). - // - if (li.type == otype::e) - { - // Utility libraries are project-local which means the primarily - // target should be in the same project as us. - // - li.type = lib_rule::build_members (x.root_scope ()).a - ? otype::a - : otype::s; - } - - const target_type& tt (li.type == otype::a - ? libua::static_type - : libus::static_type); - - // Called by the compile rule during execute. - // - return x.ctx.phase == run_phase::match && !exist - ? &search (x, tt, x.dir, x.out, x.name) - : search_existing (x.ctx, tt, x.dir, x.out, x.name); - } - else - { - assert (!exist); - - const lib& l (x.as ()); - - // Make sure group members are resolved. - // - group_view gv (resolve_members (a, l)); - assert (gv.members != nullptr); - - lorder lo (li.order); - - bool ls (true); - switch (lo) - { - case lorder::a: - case lorder::a_s: - ls = false; // Fall through. - case lorder::s: - case lorder::s_a: - { - if (ls ? l.s == nullptr : l.a == nullptr) - { - if (lo == lorder::a_s || lo == lorder::s_a) - ls = !ls; - else - fail << (ls ? "shared" : "static") << " variant of " << l - << " is not available"; - } - } - } - - return ls ? static_cast (l.s) : l.a; - } - } } } diff --git a/libbuild2/cc/utility.hxx b/libbuild2/cc/utility.hxx index 5aef14c..458aa25 100644 --- a/libbuild2/cc/utility.hxx +++ b/libbuild2/cc/utility.hxx @@ -9,7 +9,9 @@ #include #include + #include +#include #include @@ -17,6 +19,11 @@ namespace build2 { namespace cc { + using bin::link_type; + using bin::link_order; + using bin::link_info; + using bin::link_member; + // To form the complete path do: // // root.out_path () / root.root_extra->build_dir / X_dir @@ -25,45 +32,13 @@ namespace build2 extern const dir_path module_build_dir; // cc/build/ extern const dir_path module_build_modules_dir; // cc/build/modules/ - // Compile output type. + // Compile output type from source target. // otype compile_type (const target&, unit_type); compile_target_types compile_types (otype); - - // Link output type. - // - ltype - link_type (const target&); - - // Library link order. - // - // 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 - // metadata 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 (const scope& base, otype); - - inline linfo - link_info (const scope& base, otype ot) - { - return linfo {ot, link_order (base, ot)}; - } - - // Given the link order return the library member to link. That is, liba{} - // or libs{} for lib{} and libua{} or libus{} for libul{}. - // - // If existing is true, then only return the member target if it exists - // (currently only used and supported for utility libraries). - // - const target* - link_member (const bin::libx&, action, linfo, bool existing = false); } } diff --git a/libbuild2/cc/utility.ixx b/libbuild2/cc/utility.ixx index d69b898..0b94780 100644 --- a/libbuild2/cc/utility.ixx +++ b/libbuild2/cc/utility.ixx @@ -23,21 +23,6 @@ namespace build2 otype::s; } - inline ltype - link_type (const target& t) - { - using namespace bin; - - bool u (false); - otype o ( - t.is_a () || (u = t.is_a ()) ? otype::e : - t.is_a () || (u = t.is_a ()) ? otype::a : - t.is_a () || (u = t.is_a ()) ? otype::s : - static_cast (0xFF)); - - return ltype {o, u}; - } - inline compile_target_types compile_types (otype t) { -- cgit v1.1