aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2022-06-24 05:31:55 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2022-06-24 05:33:49 +0200
commit52128dcc2d88a262238c07fe8acdbcfad684035c (patch)
tree14b2e27b18e09c6577100c21bf79659743059867
parent73c8c339c5c8fb468c4ddb1632d87d1aeb1cd497 (diff)
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.
-rw-r--r--libbuild2/bin/init.cxx6
-rw-r--r--libbuild2/bin/rule.cxx81
-rw-r--r--libbuild2/bin/rule.hxx26
-rw-r--r--libbuild2/bin/target.hxx3
-rw-r--r--libbuild2/bin/utility.cxx5
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<libul> (perform_update_id, "bin.libul", libul_);
r.insert<libul> (perform_clean_id, "bin.libul", libul_);
+ r.insert<libul> (perform_update_id, "bin.metadata", libul_metadata_);
+ r.insert<libul> (perform_clean_id, "bin.metadata", libul_metadata_);
+
// Similar to alias.
//
r.insert<lib> (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<libus> (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<libua> (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<libus> (t, t.dir, t.out, t.name);
+ else
+ m = la != nullptr ? la : &search<libua> (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