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 ++++++++ 6 files changed, 265 insertions(+), 49 deletions(-) create mode 100644 libbuild2/bin/types.hxx create mode 100644 libbuild2/bin/utility.cxx create mode 100644 libbuild2/bin/utility.ixx (limited to 'libbuild2/bin') 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}; + } + } +} -- cgit v1.1