From 635f75c7b3fbb6053059827c73a4df52733850e0 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 11 Feb 2021 09:08:55 +0200 Subject: Generalize process_libraries() to allow no picking installed library member --- libbuild2/cc/common.cxx | 101 ++++++++++++++++++++++++++--------------- libbuild2/cc/common.hxx | 16 +++---- libbuild2/cc/compile-rule.cxx | 25 +++++----- libbuild2/cc/link-rule.cxx | 24 +++++----- libbuild2/cc/pkgconfig.cxx | 10 ++-- libbuild2/cc/windows-rpath.cxx | 12 ++--- 6 files changed, 107 insertions(+), 81 deletions(-) diff --git a/libbuild2/cc/common.cxx b/libbuild2/cc/common.cxx index d11b216..f307b77 100644 --- a/libbuild2/cc/common.cxx +++ b/libbuild2/cc/common.cxx @@ -46,31 +46,42 @@ namespace build2 // The first argument to proc_lib is a pointer to the last element of an // array that contains the current library dependency chain all the way to // the library passed to process_libraries(). The first element of this - // array is NULL. + // array is NULL. If this argument is NULL, then this is a library without + // a target (e.g., -lpthread) and its name is in the second argument. + // + // If proc_impl always returns false (that is, we are only interested in + // interfaces), then top_li can be absent. This makes process_libraries() + // not to pick the liba/libs{} member for installed libraries instead + // passing the lib{} group itself. This can be used to match the semantics + // of file_rule which, when matching prerequisites, does not pick the + // liba/libs{} member (naturally) but just matches the lib{} group. + // + // Note that if top_li is present, then the target passed to proc_impl, + // proc_lib, and proc_opt is always a file. // void common:: process_libraries ( action a, const scope& top_bs, - linfo top_li, + optional top_li, const dir_paths& top_sysd, - const file& l, + const mtime_target& l, // liba/libs{} or lib{} bool la, lflags lf, - const function& proc_impl, // Implementation? - const function& proc_lib, // True if system library. - const function& proc_opt, // *.export. bool self /*= false*/, // Call proc_lib on l? - small_vector* chain) const + small_vector* chain) const { - small_vector chain_storage; + small_vector chain_storage; if (chain == nullptr) { chain = &chain_storage; @@ -193,7 +204,8 @@ namespace build2 // stub the path to the DLL may not be known and so the path will be // empty (but proc_lib() will use the import stub). // - const path& p (l.path ()); + const file* f; + const path& p ((f = l.is_a ()) ? f->path () : empty_path); bool s (t != nullptr // If cc library (matched or imported). ? cast_false (l.vars[c_system]) @@ -203,7 +215,7 @@ namespace build2 } const scope& bs (t == nullptr || cc ? top_bs : l.base_scope ()); - optional li; // Calculate lazily. + optional> li; // Calculate lazily. const dir_paths* sysd (nullptr); // Resolve lazily. // Find system search directories corresponding to this library, i.e., @@ -225,7 +237,7 @@ namespace build2 { li = (t == nullptr || cc) ? top_li - : link_info (bs, link_type (l).type); + : optional (link_info (bs, link_type (l).type)); }; // Only go into prerequisites (implementation) if instructed and we are @@ -234,6 +246,8 @@ namespace build2 // if (impl && !c_e_libs.defined () && !x_e_libs.defined ()) { + assert (top_li); // Must pick a member if implementation (see above). + for (const prerequisite_target& pt: l.prerequisite_targets[a]) { // Note: adhoc prerequisites are not part of the library metadata @@ -303,7 +317,7 @@ namespace build2 { // This is something like -lpthread or shell32.lib so should be // a valid path. But it can also be an absolute library path - // (e.g., something that may come from our .static/shared.pc + // (e.g., something that may come from our .{static/shared}.pc // files). // if (proc_lib) @@ -316,7 +330,7 @@ namespace build2 if (sysd == nullptr) find_sysd (); if (!li) find_linfo (); - const file& t ( + const mtime_target& t ( resolve_library (a, bs, n, @@ -449,12 +463,16 @@ namespace build2 // will select exactly the same target as the library's matched rule and // that's the only way to guarantee it will be up-to-date. // - const file& common:: + // If li is absent, then don't pick the liba/libs{} member, returning the + // lib{} target itself. If li is present, then the returned target is + // always a file. + // + const mtime_target& common:: resolve_library (action a, const scope& s, const name& cn, const dir_path& out, - linfo li, + optional li, const dir_paths& sysd, optional& usrd) const { @@ -491,12 +509,16 @@ namespace build2 fail << "unable to find library " << pk; } - // If this is lib{}/libu*{}, pick appropriate member. + // If this is lib{}/libu*{}, pick appropriate member unless we were + // instructed not to. // - if (const libx* l = xt->is_a ()) - xt = link_member (*l, a, li); // Pick lib*{e,a,s}{}. + if (li) + { + if (const libx* l = xt->is_a ()) + xt = link_member (*l, a, *li); // Pick lib*{e,a,s}{}. + } - return xt->as (); + return xt->as (); } // Note that pk's scope should not be NULL (even if dir is absolute). @@ -868,6 +890,24 @@ namespace build2 return l; }; + // Mark as a "cc" library (unless already marked) and set the system + // flag. + // + auto mark_cc = [sys, this] (target& t) -> bool + { + auto p (t.vars.insert (c_type)); + + if (p.second) + { + p.first = string ("cc"); + + if (sys) + t.vars.assign (c_system) = true; + } + + return p.second; + }; + target_lock ll (lock (lt)); // Set lib{} group members to indicate what's available. Note that we @@ -879,6 +919,11 @@ namespace build2 { if (s != nullptr) {lt->s = s; mt = s->mtime ();} if (a != nullptr) {lt->a = a; mt = a->mtime ();} + + // Mark the group since sometimes we use it itself instead of one of + // the liba/libs{} members (see process_libraries() for details). + // + mark_cc (*lt); } target_lock al (lock (a)); @@ -890,24 +935,6 @@ namespace build2 if (a != nullptr) a->group = lt; if (s != nullptr) s->group = lt; - // Mark as a "cc" library (unless already marked) and set the system - // flag. - // - auto mark_cc = [sys, this] (target& t) -> bool - { - auto p (t.vars.insert (c_type)); - - if (p.second) - { - p.first = string ("cc"); - - if (sys) - t.vars.assign (c_system) = true; - } - - return p.second; - }; - // If the library already has cc.type, then assume it was either // already imported or was matched by a rule. // diff --git a/libbuild2/cc/common.hxx b/libbuild2/cc/common.hxx index 856c0ce..612d081 100644 --- a/libbuild2/cc/common.hxx +++ b/libbuild2/cc/common.hxx @@ -272,16 +272,16 @@ namespace build2 process_libraries ( action, const scope&, - linfo, + optional, const dir_paths&, - const file&, + const mtime_target&, bool, lflags, - const function&, - const function&, - const function&, + const function&, + const function&, + const function&, bool = false, - small_vector* = nullptr) const; + small_vector* = nullptr) const; const target* search_library (action a, @@ -308,12 +308,12 @@ namespace build2 } public: - const file& + const mtime_target& resolve_library (action, const scope&, const name&, const dir_path&, - linfo, + optional, const dir_paths&, optional&) const; diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx index 2c53a62..bd4b481 100644 --- a/libbuild2/cc/compile-rule.cxx +++ b/libbuild2/cc/compile-rule.cxx @@ -413,11 +413,13 @@ namespace build2 // See through utility libraries. // - auto imp = [] (const file& l, bool la) {return la && l.is_a ();}; + auto imp = [] (const target& l, bool la) {return la && l.is_a ();}; - auto opt = [&d, this] (const file& l, + auto opt = [&d, this] (const target& lt, const string& t, bool com, bool exp) { + const file& l (lt.as ()); + // Note that in our model *.export.poptions are always "interface", // even if set on liba{}/libs{}, unlike loptions. // @@ -504,10 +506,10 @@ namespace build2 target& t, linfo li) const { - auto imp = [] (const file& l, bool la) {return la && l.is_a ();}; + auto imp = [] (const target& l, bool la) {return la && l.is_a ();}; auto opt = [&m, this] ( - const file& l, const string& t, bool com, bool exp) + const target& l, const string& t, bool com, bool exp) { if (!exp) return; @@ -524,8 +526,8 @@ namespace build2 // The same logic as in append_library_options(). // - const function impf (imp); - const function optf (opt); + const function impf (imp); + const function optf (opt); for (prerequisite_member p: group_prerequisite_members (a, t)) { @@ -6097,10 +6099,7 @@ namespace build2 // Note that any such library would necessarily be an interface // dependency so we never need to go into implementations. // - auto imp = [] (const file&, bool) - { - return false; - }; + auto imp = [] (const target&, bool) { return false; }; // The same logic as in append_libraries(). // @@ -6111,7 +6110,7 @@ namespace build2 const file*& lt; } d {a, ht, lt}; - auto lib = [&d] (const file* const* lc, + auto lib = [&d] (const target* const* lc, const string&, lflags, bool) @@ -6121,7 +6120,7 @@ namespace build2 if (d.lt != nullptr) return; - const file* l (lc != nullptr ? *lc : nullptr); + const file* l (lc != nullptr ? &(*lc)->as () : nullptr); if (l == nullptr) return; @@ -6175,7 +6174,7 @@ namespace build2 process_libraries ( a, bs, li, sys_lib_dirs, *f, la, 0, // lflags unused. - imp, lib, {}, + imp, lib, nullptr, true); } } diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx index 8b81536..2b3f22a 100644 --- a/libbuild2/cc/link-rule.cxx +++ b/libbuild2/cc/link-rule.cxx @@ -1553,19 +1553,19 @@ namespace build2 compile_target_types tts; } d {ls, args, l, a, li, rel, compile_types (li.type)}; - auto imp = [] (const file&, bool la) + auto imp = [] (const target&, bool la) { return la; }; - auto lib = [&d, this] (const file* const* lc, + auto lib = [&d, this] (const target* const* lc, const string& p, lflags f, bool) { // Note: see also make_header_sidebuild(). - const file* l (lc != nullptr ? *lc : nullptr); + const file* l (lc != nullptr ? &(*lc)->as () : nullptr); // Suppress duplicates. // @@ -1745,11 +1745,13 @@ namespace build2 al.end = d.args.size (); // Close. }; - auto opt = [&d, this] (const file& l, + auto opt = [&d, this] (const target& lt, const string& t, bool com, bool exp) { + const file& l (lt.as ()); + // Don't try to pass any loptions when linking a static library. // // Note also that we used to pass non-export loptions but that didn't @@ -1806,17 +1808,17 @@ namespace build2 linfo li; } d {cs, bs.root_scope ()->out_path (), update, mt, li}; - auto imp = [] (const file&, bool la) + auto imp = [] (const target&, bool la) { return la; }; - auto lib = [&d, this] (const file* const* lc, + auto lib = [&d, this] (const target* const* lc, const string& p, lflags f, bool) { - const file* l (lc != nullptr ? *lc : nullptr); + const file* l (lc != nullptr ? &(*lc)->as () : nullptr); if (l == nullptr) { @@ -1868,7 +1870,7 @@ namespace build2 } }; - auto opt = [&d, this] (const file& l, + auto opt = [&d, this] (const target& l, const string& t, bool com, bool exp) @@ -1908,7 +1910,7 @@ namespace build2 return; } - auto imp = [link] (const file& l, bool la) + auto imp = [link] (const target& l, bool la) { // If we are not rpath-link'ing, then we only need to rpath interface // libraries (they will include rpath's for their implementations) @@ -1937,12 +1939,12 @@ namespace build2 bool link; } d {ls, args, link}; - auto lib = [&d, this] (const file* const* lc, + auto lib = [&d, this] (const target* const* lc, const string& f, lflags, bool sys) { - const file* l (lc != nullptr ? *lc : nullptr); + const file* l (lc != nullptr ? &(*lc)->as () : nullptr); // We don't rpath system libraries. Why, you may ask? There are many // good reasons and I have them written on a napkin somewhere... diff --git a/libbuild2/cc/pkgconfig.cxx b/libbuild2/cc/pkgconfig.cxx index 48219f2..d44b0ec 100644 --- a/libbuild2/cc/pkgconfig.cxx +++ b/libbuild2/cc/pkgconfig.cxx @@ -1633,15 +1633,15 @@ namespace build2 // pretty similar to link_rule::append_libraries()). // bool priv (false); - auto imp = [&priv] (const file&, bool la) {return priv && la;}; + auto imp = [&priv] (const target&, bool la) {return priv && la;}; auto lib = [&save_library_target, - &save_library_name] (const file* const* c, + &save_library_name] (const target* const* lc, const string& p, lflags, bool) { - const file* l (c != nullptr ? *c : nullptr); + const file* l (lc != nullptr ? &(*lc)->as () : nullptr); if (l != nullptr) { @@ -1652,9 +1652,7 @@ namespace build2 save_library_name (p); // Something "system'y", save as is. }; - auto opt = [] (const file&, - const string&, - bool, bool) + auto opt = [] (const target&, const string&, bool, bool) { //@@ TODO: should we filter -L similar to -I? //@@ TODO: how will the Libs/Libs.private work? diff --git a/libbuild2/cc/windows-rpath.cxx b/libbuild2/cc/windows-rpath.cxx index eddb9c4..70eef73 100644 --- a/libbuild2/cc/windows-rpath.cxx +++ b/libbuild2/cc/windows-rpath.cxx @@ -56,14 +56,14 @@ namespace build2 // We need to collect all the DLLs, so go into implementation of both // shared and static (in case they depend on shared). // - auto imp = [] (const file&, bool) {return true;}; + auto imp = [] (const target&, bool) {return true;}; - auto lib = [&r] (const file* const* lc, + auto lib = [&r] (const target* const* lc, const string& f, lflags, bool sys) { - const file* l (lc != nullptr ? *lc : nullptr); + const file* l (lc != nullptr ? &(*lc)->as () : nullptr); // We don't rpath system libraries. // @@ -137,14 +137,14 @@ namespace build2 { windows_dlls r; - auto imp = [] (const file&, bool) {return true;}; + auto imp = [] (const target&, bool) {return true;}; - auto lib = [&r, &bs] (const file* const* lc, + auto lib = [&r, &bs] (const target* const* lc, const string& f, lflags, bool sys) { - const file* l (lc != nullptr ? *lc : nullptr); + const file* l (lc != nullptr ? &(*lc)->as () : nullptr); if (sys) return; -- cgit v1.1