From 52128dcc2d88a262238c07fe8acdbcfad684035c Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 24 Jun 2022 05:31:55 +0200 Subject: Match rule to libul{} with explicit bin.metadata hint This rule picks, matches, and unmatches (if possible) a member for the purpose of making its metadata (for example, library's poptions, if it's one of the cc libraries) available. --- libbuild2/bin/init.cxx | 6 +++- libbuild2/bin/rule.cxx | 81 ++++++++++++++++++++++++++++++++++++++++++++--- libbuild2/bin/rule.hxx | 26 +++++++++++---- libbuild2/bin/target.hxx | 3 ++ libbuild2/bin/utility.cxx | 5 +++ 5 files changed, 110 insertions(+), 11 deletions(-) diff --git a/libbuild2/bin/init.cxx b/libbuild2/bin/init.cxx index 2b1df97..563a82f 100644 --- a/libbuild2/bin/init.cxx +++ b/libbuild2/bin/init.cxx @@ -29,7 +29,8 @@ namespace build2 namespace bin { static const obj_rule obj_; - static const libul_rule libul_; + static const libul_rule libul_ (false); + static const libul_rule libul_metadata_ (true); static const lib_rule lib_; static const def_rule def_; @@ -576,6 +577,9 @@ namespace build2 r.insert (perform_update_id, "bin.libul", libul_); r.insert (perform_clean_id, "bin.libul", libul_); + r.insert (perform_update_id, "bin.metadata", libul_metadata_); + r.insert (perform_clean_id, "bin.metadata", libul_metadata_); + // Similar to alias. // r.insert (perform_id, 0, "bin.lib", lib_); diff --git a/libbuild2/bin/rule.cxx b/libbuild2/bin/rule.cxx index 38a3d98..1d33961 100644 --- a/libbuild2/bin/rule.cxx +++ b/libbuild2/bin/rule.cxx @@ -35,14 +35,87 @@ namespace build2 // libul_rule // bool libul_rule:: - match (action a, target& t) const + match (action a, target& t, const string& h, match_extra&) const { - fail << diag_doing (a, t) << " target group" << - info << "explicitly select libua{} or libus{} member" << endf; + if (!metadata_) + { + fail << diag_doing (a, t) << " target group" << + info << "explicitly select libua{} or libus{} member" << + info << "or use bin.metadata rule hint if this is metadata library"; + } + + return (h == "bin.metadata"); } recipe libul_rule:: - apply (action, target&) const {return empty_recipe;} + apply (action a, target& t, match_extra&) const + { + assert (metadata_); + + // Pick one of the members. First looking for the one already matched. + // + const target* m (nullptr); + + const libus* ls (nullptr); + { + ls = search_existing (t.ctx, t.dir, t.out, t.name); + + if (ls != nullptr && ls->matched (a)) + m = ls; + } + + const libua* la (nullptr); + if (m == nullptr) + { + la = search_existing (t.ctx, t.dir, t.out, t.name); + + if (la != nullptr && la->matched (a)) + m = la; + } + + if (m == nullptr) + { + const scope& bs (t.base_scope ()); + + lmembers lm (link_members (*bs.root_scope ())); + + if (lm.s && lm.a) + { + // Use the bin.exe.lib order as a heuristics to pick the library + // (i.e., the most likely utility library to be built is the one + // most likely to be linked). + // + lorder lo (link_order (bs, otype::e)); + + (lo == lorder::s_a || lo == lorder::s ? lm.a : lm.s) = false; + } + + if (lm.s) + m = ls != nullptr ? ls : &search (t, t.dir, t.out, t.name); + else + m = la != nullptr ? la : &search (t, t.dir, t.out, t.name); + } + + // Save the member we picked in case others (e.g., $x.lib_poptions()) + // need this information. + // + t.prerequisite_targets[a].push_back (m); + + if (match_sync (a, *m, unmatch::safe).first) + return noop_recipe; + + return [] (action a, const target& t) + { + const target* m (t.prerequisite_targets[a].back ()); + + // For update always return unchanged so we are consistent whether we + // managed to unmatch or now. Note that for clean we may get postponed + // so let's return the actual target state. + // + target_state r (execute_sync (a, *m)); + return a == perform_update_id ? target_state::unchanged : r; + }; + } // lib_rule // diff --git a/libbuild2/bin/rule.hxx b/libbuild2/bin/rule.hxx index 8bc30c7..fcbd0ca 100644 --- a/libbuild2/bin/rule.hxx +++ b/libbuild2/bin/rule.hxx @@ -30,19 +30,33 @@ namespace build2 apply (action, target&) const override; }; - // "Fail rule" for libul{} that issues diagnostics if someone tries to - // build this group directly. + // If metadata is false, the this is a "fail rule" for libul{} that issues + // diagnostics if someone tries to build this group directly. // - class libul_rule: public simple_rule + // If metadata is true, then this rule only matches with the explicit + // `bin.metadata` hint. In this case it picks, matches, and unmatches (if + // possible) a member for the purpose of making its metadata (for example, + // library's poptions, if it's one of the cc libraries) available. + // + // The underlying idea here is that someone else (e.g., cc::link_rule) + // makes a more informed choice and we piggy back on that decision, + // falling back to making our own based on bin.lib and bin.exe.lib. Note + // that for update this rule always returns target_state::unchanged. + // + class libul_rule: public rule { public: - libul_rule () {} + explicit + libul_rule (bool md): metadata_ (md) {} virtual bool - match (action, target&) const override; + match (action, target&, const string&, match_extra&) const override; virtual recipe - apply (action, target&) const override; + apply (action, target&, match_extra&) const override; + + private: + bool metadata_; }; // Pass-through to group members rule, similar to alias. diff --git a/libbuild2/bin/target.hxx b/libbuild2/bin/target.hxx index 89e0f17..3ecabce 100644 --- a/libbuild2/bin/target.hxx +++ b/libbuild2/bin/target.hxx @@ -340,6 +340,9 @@ namespace build2 static const target_type static_type; }; + // @@ Ideally this shouldn't derive from mtime_target (via libx). Maybe + // get rid of libx? + // class LIBBUILD2_BIN_SYMEXPORT libul: public libx { public: diff --git a/libbuild2/bin/utility.cxx b/libbuild2/bin/utility.cxx index cb06287..2a87bbd 100644 --- a/libbuild2/bin/utility.cxx +++ b/libbuild2/bin/utility.cxx @@ -57,6 +57,11 @@ namespace build2 // prefer static over shared since it could be faster (but I am sure // someone will probably want this configurable). // + // Maybe we should use the bin.exe.lib order as a heuristics (i.e., + // the most likely utility library to be built is the one most likely + // to be linked)? Will need the variables rs-only, similar to + // bin.lib, which probably is a good thing. See also libul_rule. + // if (li.type == otype::e) { // Utility libraries are project-local which means the primarily -- cgit v1.1