aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/algorithm.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2022-02-24 10:03:43 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2022-03-02 13:26:51 +0200
commit634048a861658af2bc5c37507bf96116cf1968aa (patch)
treed6122830ed2744d86e1ddb389f0e76131e54d6be /libbuild2/algorithm.cxx
parentbe66fff5ff42eaab81d2a526d8b6296c28848775 (diff)
Add update operation-specific variable with unmatch|match additional values
Note that the unmatch (match but do not update) and match (update during match) values are only supported by certain rules (and potentially only for certain prerequisite types). Additionally: - All operation-specific variables are now checked for false as an override for the prerequisite-specific include value. In particular, this can now be used to disable a prerequisite for update, for example: ./: exe{test}: update = false - The cc::link_rule now supports the update=match value for headers and ad hoc prerequisites. In particular, this can be used to make sure all the library headers are updated before matching any of its (or dependent's) object files.
Diffstat (limited to 'libbuild2/algorithm.cxx')
-rw-r--r--libbuild2/algorithm.cxx68
1 files changed, 65 insertions, 3 deletions
diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx
index 9b6fd4e..cbf0495 100644
--- a/libbuild2/algorithm.cxx
+++ b/libbuild2/algorithm.cxx
@@ -2057,6 +2057,68 @@ namespace build2
return t.executed_state (a);
}
+ bool
+ update_during_match (tracer& trace, action a, const target& t, timestamp ts)
+ {
+ assert (a == perform_update_id);
+
+ // Note: this function is used to make sure header dependencies are up to
+ // date (and which is where it originated).
+ //
+ // There would normally be a lot of headers for every source file (think
+ // all the system headers) and just calling execute_direct() on all of
+ // them can get expensive. At the same time, most of these headers are
+ // existing files that we will never be updating (again, system headers,
+ // for example) and the rule that will match them is the fallback
+ // file_rule. That rule has an optimization: it returns noop_recipe (which
+ // causes the target state to be automatically set to unchanged) if the
+ // file is known to be up to date. So we do the update "smartly".
+ //
+ const path_target* pt (t.is_a<path_target> ());
+
+ if (pt == nullptr)
+ ts = timestamp_unknown;
+
+ target_state os (t.matched_state (a));
+
+ if (os == target_state::unchanged)
+ {
+ if (ts == timestamp_unknown)
+ return false;
+ else
+ {
+ // We expect the timestamp to be known (i.e., existing file).
+ //
+ timestamp mt (pt->mtime ());
+ assert (mt != timestamp_unknown);
+ return mt > ts;
+ }
+ }
+ else
+ {
+ // We only want to return true if our call to execute() actually caused
+ // an update. In particular, the target could already have been in
+ // target_state::changed because of the dynamic dependency extraction
+ // run for some other target.
+ //
+ // @@ MT perf: so we are going to switch the phase and execute for
+ // any generated header.
+ //
+ phase_switch ps (t.ctx, run_phase::execute);
+ target_state ns (execute_direct (a, t));
+
+ if (ns != os && ns != target_state::unchanged)
+ {
+ l6 ([&]{trace << "updated " << t
+ << "; old state " << os
+ << "; new state " << ns;});
+ return true;
+ }
+ else
+ return ts != timestamp_unknown ? pt->newer (ts, ns) : false;
+ }
+ }
+
static inline void
blank_adhoc_member (const target*&)
{
@@ -2065,7 +2127,7 @@ namespace build2
static inline void
blank_adhoc_member (prerequisite_target& pt)
{
- if (pt.adhoc)
+ if (pt.adhoc ())
pt.target = nullptr;
}
@@ -2254,7 +2316,7 @@ namespace build2
// Should we compare the timestamp to this target's?
//
- if (!e && (p.adhoc || !ef || ef (pt, i)))
+ if (!e && (p.adhoc () || !ef || ef (pt, i)))
{
// If this is an mtime-based target, then compare timestamps.
//
@@ -2272,7 +2334,7 @@ namespace build2
}
}
- if (p.adhoc)
+ if (p.adhoc ())
p.target = nullptr; // Blank out.
else
{