From af73b1603d851dcb2ce7ae84bd57df0c2f9a716d Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 16 Jun 2020 09:43:59 +0200 Subject: Add $bin.link_member() function Given a linker output target type ("exe", "lib[as]", or "libu[eas]") return the target type of lib{} group member ("liba" or "libs") that will be picked when linking a lib{} group to this target type. --- libbuild2/bin/functions.cxx | 68 +++++++++++++++++++++++++++++++++++++++++ libbuild2/bin/init.cxx | 16 ++++++++-- libbuild2/bin/utility.cxx | 27 ++++------------ libbuild2/bin/utility.hxx | 24 ++++++++++++--- libbuild2/bin/utility.ixx | 35 ++++++++++++++++++--- libbuild2/install/functions.cxx | 2 -- 6 files changed, 138 insertions(+), 34 deletions(-) create mode 100644 libbuild2/bin/functions.cxx diff --git a/libbuild2/bin/functions.cxx b/libbuild2/bin/functions.cxx new file mode 100644 index 0000000..59fcdf2 --- /dev/null +++ b/libbuild2/bin/functions.cxx @@ -0,0 +1,68 @@ +// file : libbuild2/bin/functions.cxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#include +#include + +#include + +namespace build2 +{ + namespace bin + { + void + functions (function_map& m) + { + function_family f (m, "bin"); + + // Given a linker output target type ("exe", "lib[as]", or "libu[eas]") + // and a lib{} target group, return the type of library member ("liba" + // or "libs") that will be picked when linking this library group to + // this target type. + // + // The lib{} target is only used to resolve the scope to lookup the + // bin.lib value on. As a result, it can be omitted in which case the + // function call scope is used (covers project-local lib{} targets). + // + // @@ TODO: support for target (note that if it's out of project, then + // it's imported, which means it might still be qualified.) + // + // @@ TODO: support utility libraries (see link_member()). + // + f[".link_member"] = [] (const scope* bs, names ns) + { + string t (convert (move (ns))); + + if (bs == nullptr) + fail << "bin.link_member() called out of scope"; + + const scope* rs (bs->root_scope ()); + + if (rs == nullptr) + fail << "bin.link_member() called out of root scope"; + + const target_type* tt (bs->find_target_type (t)); + + if (tt == nullptr) + fail << "unknown target type '" << t << "'"; + + otype ot (link_type (*tt).type); + + switch (ot) + { + case otype::e: + case otype::a: + case otype::s: + break; + default: + fail << "target type " << t << " is not linker output"; + } + + lorder lo (link_order (*bs, ot)); + lmembers lm (link_members (*rs)); + + return link_member (lm, lo).first == otype::s ? "libs" : "liba"; + }; + } + } +} diff --git a/libbuild2/bin/init.cxx b/libbuild2/bin/init.cxx index a1ac61e..0d2d9b5 100644 --- a/libbuild2/bin/init.cxx +++ b/libbuild2/bin/init.cxx @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -137,6 +138,9 @@ namespace build2 return true; } + void + functions (function_map&); // functions.cxx + bool config_init (scope& rs, scope& bs, @@ -153,6 +157,14 @@ namespace build2 if (rs != bs) fail (loc) << "bin.config module must be loaded in project root"; + context& ctx (rs.ctx); + + // Register the bin function family if this is the first instance of the + // bin modules. + // + if (!function_family::defined (ctx.functions, "bin")) + functions (ctx.functions); + // Load bin.vars. // load_module (rs, rs, "bin.vars", loc); @@ -267,7 +279,7 @@ namespace build2 // config.bin.target // { - const variable& var (rs.ctx.var_pool["config.bin.target"]); + const variable& var (ctx.var_pool["config.bin.target"]); // We first see if the value was specified via the configuration // mechanism. @@ -343,7 +355,7 @@ namespace build2 // config.bin.pattern // { - const variable& var (rs.ctx.var_pool["config.bin.pattern"]); + const variable& var (ctx.var_pool["config.bin.pattern"]); // We first see if the value was specified via the configuration // mechanism. diff --git a/libbuild2/bin/utility.cxx b/libbuild2/bin/utility.cxx index 8032b79..6b0c4de 100644 --- a/libbuild2/bin/utility.cxx +++ b/libbuild2/bin/utility.cxx @@ -87,29 +87,14 @@ namespace build2 group_view gv (resolve_members (a, l)); assert (gv.members != nullptr); - lorder lo (li.order); + pair r ( + link_member (lmembers {l.a != nullptr, l.s != nullptr}, 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"; - } - } - } + if (!r.second) + fail << (r.first == otype::s ? "shared" : "static") + << " variant of " << l << " is not available"; - return ls ? static_cast (l.s) : l.a; + return r.first == otype::s ? static_cast (l.s) : l.a; } } diff --git a/libbuild2/bin/utility.hxx b/libbuild2/bin/utility.hxx index 91b51f8..5d7eed4 100644 --- a/libbuild2/bin/utility.hxx +++ b/libbuild2/bin/utility.hxx @@ -19,10 +19,16 @@ namespace build2 // @@ Here we conflate the term "link" to mean both linker output and // linking of a library. - // Linker output type from binary (exe{}, lib*{}) target. + // Linker output type from a target (exe{}, lib*{}). // ltype - link_type (const target&); + link_type (const target_type&); + + inline ltype + link_type (const target& t) + { + return link_type (t.type ()); + } // Library group (lib{}) members to build according to the bin.lib value. // @@ -39,12 +45,12 @@ namespace build2 // directory have to have the same link order. // LIBBUILD2_BIN_SYMEXPORT lorder - link_order (const scope& base, otype); + link_order (const scope& bs, otype); inline linfo - link_info (const scope& base, otype ot) + link_info (const scope& bs, otype ot) { - return linfo {ot, link_order (base, ot)}; + return linfo {ot, link_order (bs, ot)}; } // Given the link order return the library member to link. That is, liba{} @@ -56,6 +62,14 @@ namespace build2 LIBBUILD2_BIN_SYMEXPORT const target* link_member (const libx&, action, linfo, bool existing = false); + // As above but return otype::a or otype::s as well as an indication if + // the member is available. + // + // @@ TODO: support utility libraries (see above version). + // + pair + link_member (lmembers, linfo); + // Lookup the bin.pattern value and split it into the pattern and the // search paths. // diff --git a/libbuild2/bin/utility.ixx b/libbuild2/bin/utility.ixx index 91c919b..65dffa8 100644 --- a/libbuild2/bin/utility.ixx +++ b/libbuild2/bin/utility.ixx @@ -6,16 +6,43 @@ namespace build2 namespace bin { inline ltype - link_type (const target& t) + link_type (const target_type& tt) { 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 : + tt.is_a () || (u = tt.is_a ()) ? otype::e : + tt.is_a () || (u = tt.is_a ()) ? otype::a : + tt.is_a () || (u = tt.is_a ()) ? otype::s : static_cast (0xFF)); return ltype {o, u}; } + + inline pair + link_member (lmembers lm, lorder lo) + { + bool r (true); + + bool s (true); + switch (lo) + { + case lorder::a: + case lorder::a_s: + s = false; // Fall through. + case lorder::s: + case lorder::s_a: + { + if (s ? !lm.s : !lm.a) + { + if (lo == lorder::a_s || lo == lorder::s_a) + s = !s; + else + r = false; // Not available. + } + } + } + + return make_pair (s ? otype::s : otype::a, r); + } } } diff --git a/libbuild2/install/functions.cxx b/libbuild2/install/functions.cxx index d8b07a4..c780061 100644 --- a/libbuild2/install/functions.cxx +++ b/libbuild2/install/functions.cxx @@ -6,8 +6,6 @@ #include -using namespace std; - namespace build2 { namespace install -- cgit v1.1