aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/cc
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2022-04-19 11:10:53 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2022-04-19 11:10:53 +0200
commit9034f7c51ef6437ce9d4547ba5bde217b4740fb2 (patch)
treebfaa297fda78b6cafe4487e2281420a4cf77c81a /libbuild2/cc
parent457f65414031f45174f3c35230a0c0e1de88b51a (diff)
Use target recipe for auxiliary data storage during match-apply
In particular, we now have separate auxiliary data storage for inner and outer operations.
Diffstat (limited to 'libbuild2/cc')
-rw-r--r--libbuild2/cc/compile-rule.cxx41
-rw-r--r--libbuild2/cc/compile-rule.hxx5
-rw-r--r--libbuild2/cc/install-rule.cxx26
-rw-r--r--libbuild2/cc/link-rule.cxx29
-rw-r--r--libbuild2/cc/link-rule.hxx26
5 files changed, 84 insertions, 43 deletions
diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx
index f680001..ada0cc6 100644
--- a/libbuild2/cc/compile-rule.cxx
+++ b/libbuild2/cc/compile-rule.cxx
@@ -229,10 +229,16 @@ namespace build2
return nullopt;
}
+ // Note that we don't really need this for clean (where we only need
+ // unrefined unit type) so we could make this update-only. But let's keep
+ // it simple for now.
+ //
struct compile_rule::match_data
{
- match_data (unit_type t, const prerequisite_member& s)
- : type (t), src (s) {}
+ match_data (const compile_rule& r,
+ unit_type t,
+ const prerequisite_member& s)
+ : type (t), src (s), rule (r) {}
unit_type type;
preprocessed pp = preprocessed::none;
@@ -245,6 +251,14 @@ namespace build2
path dd; // Dependency database path.
size_t header_units = 0; // Number of imported header units.
module_positions modules = {0, 0, 0}; // Positions of imported modules.
+
+ const compile_rule& rule;
+
+ target_state
+ operator() (action a, const target& t)
+ {
+ return rule.perform_update (a, t, *this);
+ }
};
compile_rule::
@@ -464,7 +478,7 @@ namespace build2
{
// Save in the target's auxiliary storage.
//
- t.data (match_data (ut, p));
+ t.data (a, match_data (*this, ut, p));
return true;
}
}
@@ -809,7 +823,7 @@ namespace build2
file& t (xt.as<file> ()); // Either obj*{} or bmi*{}.
- match_data& md (t.data<match_data> ());
+ match_data& md (t.data<match_data> (a));
context& ctx (t.ctx);
@@ -1497,10 +1511,7 @@ namespace build2
switch (a)
{
- case perform_update_id: return [this] (action a, const target& t)
- {
- return perform_update (a, t);
- };
+ case perform_update_id: return move (md);
case perform_clean_id: return [this] (action a, const target& t)
{
return perform_clean (a, t);
@@ -5439,10 +5450,11 @@ namespace build2
// 1. There is no good place in prerequisite_targets to store the
// exported flag (no, using the marking facility across match/execute
// is a bad idea). So what we are going to do is put re-exported
- // bmi{}s at the back and store (in the target's data pad) the start
- // position. One bad aspect about this part is that we assume those
- // bmi{}s have been matched by the same rule. But let's not kid
- // ourselves, there will be no other rule that matches bmi{}s.
+ // bmi{}s at the back and store (in the target's auxiliary data
+ // storage) the start position. One bad aspect about this part is
+ // that we assume those bmi{}s have been matched by the same
+ // rule. But let's not kid ourselves, there will be no other rule
+ // that matches bmi{}s.
//
// @@ I think now we could use prerequisite_targets::data for this?
//
@@ -5833,7 +5845,7 @@ namespace build2
// Copy over bmi{}s from our prerequisites weeding out duplicates.
//
- if (size_t j = bt->data<match_data> ().modules.start)
+ if (size_t j = bt->data<match_data> (a).modules.start)
{
// Hard to say whether we should reserve or not. We will probably
// get quite a bit of duplications.
@@ -6578,12 +6590,11 @@ namespace build2
}
target_state compile_rule::
- perform_update (action a, const target& xt) const
+ perform_update (action a, const target& xt, match_data& md) const
{
const file& t (xt.as<file> ());
const path& tp (t.path ());
- match_data md (move (t.data<match_data> ()));
unit_type ut (md.type);
context& ctx (t.ctx);
diff --git a/libbuild2/cc/compile-rule.hxx b/libbuild2/cc/compile-rule.hxx
index 16b33fa..49d33eb 100644
--- a/libbuild2/cc/compile-rule.hxx
+++ b/libbuild2/cc/compile-rule.hxx
@@ -44,6 +44,8 @@ namespace build2
dyndep_rule
{
public:
+ struct match_data;
+
compile_rule (data&&, const scope&);
virtual bool
@@ -53,7 +55,7 @@ namespace build2
apply (action, target&) const override;
target_state
- perform_update (action, const target&) const;
+ perform_update (action, const target&, match_data&) const;
target_state
perform_clean (action, const target&) const;
@@ -74,7 +76,6 @@ namespace build2
functions (function_family&, const char*); // functions.cxx
private:
- struct match_data;
using environment = small_vector<const char*, 2>;
template <typename T>
diff --git a/libbuild2/cc/install-rule.cxx b/libbuild2/cc/install-rule.cxx
index d83bf70..0b4d1e1 100644
--- a/libbuild2/cc/install-rule.cxx
+++ b/libbuild2/cc/install-rule.cxx
@@ -160,6 +160,20 @@ namespace build2
file_rule::match (a, t);
}
+ // Wrap the file_rule's recipe into a data-carrying recipe.
+ //
+ struct install_match_data
+ {
+ build2::recipe recipe;
+ link_rule::libs_paths libs_paths;
+
+ target_state
+ operator() (action a, const target& t)
+ {
+ return recipe (a, t);
+ }
+ };
+
recipe install_rule::
apply (action a, target& t) const
{
@@ -173,7 +187,7 @@ namespace build2
// Signal to the link rule that this is update for install. And if the
// update has already been executed, verify it was done for install.
//
- auto& md (t.data<link_rule::match_data> ());
+ auto& md (t.data<link_rule::match_data> (a.inner_action ()));
if (md.for_install)
{
@@ -198,10 +212,12 @@ namespace build2
{
const string* p (cast_null<string> (t["bin.lib.prefix"]));
const string* s (cast_null<string> (t["bin.lib.suffix"]));
- t.data (
+
+ return install_match_data {
+ move (r),
link_.derive_libs_paths (*f,
p != nullptr ? p->c_str (): nullptr,
- s != nullptr ? s->c_str (): nullptr));
+ s != nullptr ? s->c_str (): nullptr)};
}
}
}
@@ -219,7 +235,7 @@ namespace build2
// Here we may have a bunch of symlinks that we need to install.
//
const scope& rs (t.root_scope ());
- auto& lp (t.data<link_rule::libs_paths> ());
+ auto& lp (t.data<install_match_data> (perform_install_id).libs_paths);
auto ln = [&rs, &id] (const path& f, const path& l)
{
@@ -253,7 +269,7 @@ namespace build2
// Here we may have a bunch of symlinks that we need to uninstall.
//
const scope& rs (t.root_scope ());
- auto& lp (t.data<link_rule::libs_paths> ());
+ auto& lp (t.data<install_match_data> (perform_uninstall_id).libs_paths);
auto rm = [&rs, &id] (const path& l)
{
diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx
index f2e3775..de47822 100644
--- a/libbuild2/cc/link-rule.cxx
+++ b/libbuild2/cc/link-rule.cxx
@@ -875,8 +875,11 @@ namespace build2
// Note that for_install is signalled by install_rule and therefore
// can only be relied upon during execute.
//
- t.data (match_data ());
- match_data& md (t.data<match_data> ());
+ // Note that we don't really need to set it as target data: while there
+ // are calls to get it, they should only happen after the target has
+ // been matched.
+ //
+ match_data md (*this);
const scope& bs (t.base_scope ());
const scope& rs (*bs.root_scope ());
@@ -2008,14 +2011,11 @@ namespace build2
switch (a)
{
- case perform_update_id: return [this] (action a, const target& t)
- {
- return perform_update (a, t);
- };
- case perform_clean_id: return [this] (action a, const target& t)
- {
- return perform_clean (a, t);
- };
+ // Keep the recipe (which is match_data) after execution to allow the
+ // install rule to examine it.
+ //
+ case perform_update_id: t.keep_data (a); // Fall through.
+ case perform_clean_id: return move (md);
default: return noop_recipe; // Configure update.
}
}
@@ -2158,7 +2158,7 @@ namespace build2
*type != "cc" &&
type->compare (0, 3, "cc,") != 0)
{
- auto& md (l->data<link_rule::match_data> ());
+ auto& md (l->data<link_rule::match_data> (d.a));
assert (md.for_install); // Must have been executed.
// The user will get the target name from the context info.
@@ -2556,7 +2556,7 @@ namespace build2
msvc_machine (const string& cpu); // msvc.cxx
target_state link_rule::
- perform_update (action a, const target& xt) const
+ perform_update (action a, const target& xt, match_data& md) const
{
tracer trace (x, "link_rule::perform_update");
@@ -2568,8 +2568,6 @@ namespace build2
const scope& bs (t.base_scope ());
const scope& rs (*bs.root_scope ());
- match_data& md (t.data<match_data> ());
-
// Unless the outer install rule signalled that this is update for
// install, signal back that we've performed plain update.
//
@@ -4078,12 +4076,11 @@ namespace build2
}
target_state link_rule::
- perform_clean (action a, const target& xt) const
+ perform_clean (action a, const target& xt, match_data& md) const
{
const file& t (xt.as<file> ());
ltype lt (link_type (t));
- const match_data& md (t.data<match_data> ());
clean_extras extras;
clean_adhoc_extras adhoc_extras;
diff --git a/libbuild2/cc/link-rule.hxx b/libbuild2/cc/link-rule.hxx
index f0052e9..14a70d2 100644
--- a/libbuild2/cc/link-rule.hxx
+++ b/libbuild2/cc/link-rule.hxx
@@ -23,6 +23,8 @@ namespace build2
public:
link_rule (data&&);
+ struct match_data;
+
struct match_result
{
bool seen_x = false;
@@ -52,10 +54,10 @@ namespace build2
apply (action, target&, match_extra&) const override;
target_state
- perform_update (action, const target&) const;
+ perform_update (action, const target&, match_data&) const;
target_state
- perform_clean (action, const target&) const;
+ perform_clean (action, const target&, match_data&) const;
public:
// Library handling.
@@ -226,9 +228,9 @@ namespace build2
static void
functions (function_family&, const char*); // functions.cxx
- private:
- friend class install_rule;
- friend class libux_install_rule;
+ // Implementation details.
+ //
+ public:
// Shared library paths.
//
@@ -271,6 +273,9 @@ namespace build2
struct match_data
{
+ explicit
+ match_data (const link_rule& r): rule (r) {}
+
// The "for install" condition is signalled to us by install_rule when
// it is matched for the update operation. It also verifies that if we
// have already been executed, then it was for install.
@@ -305,10 +310,21 @@ namespace build2
size_t start; // Parallel prerequisites/prerequisite_targets start.
link_rule::libs_paths libs_paths;
+
+ const link_rule& rule;
+
+ target_state
+ operator() (action a, const target& t)
+ {
+ return a == perform_update_id
+ ? rule.perform_update (a, t, *this)
+ : rule.perform_clean (a, t, *this);
+ }
};
// Windows rpath emulation (windows-rpath.cxx).
//
+ private:
struct windows_dll
{
reference_wrapper<const string> dll;