From ca0f9c71be279aee845bf5328ac0af8c02c8849e Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 17 Apr 2019 13:42:37 +0200 Subject: Incorporate ad hoc prerequisite mtime into out-of-date determination --- build2/algorithm.cxx | 35 ++++++++++++++++++----------------- build2/algorithm.hxx | 18 +++++++++++++----- build2/cc/compile-rule.cxx | 3 +++ build2/cc/link-rule.cxx | 35 +++++++++++++++++++++++++---------- 4 files changed, 59 insertions(+), 32 deletions(-) diff --git a/build2/algorithm.cxx b/build2/algorithm.cxx index 06ed922..fc72d74 100644 --- a/build2/algorithm.cxx +++ b/build2/algorithm.cxx @@ -1605,19 +1605,16 @@ namespace build2 return t.executed_state (a); } - static inline bool - adhoc_member (const target*&) + static inline void + blank_adhoc_member (const target*&) { - return false; } - static inline bool - adhoc_member (prerequisite_target& pt) + static inline void + blank_adhoc_member (prerequisite_target& pt) { if (pt.adhoc) pt.target = nullptr; - - return pt.adhoc; } template @@ -1669,7 +1666,7 @@ namespace build2 r |= mt.executed_state (a); - adhoc_member (ts[i]); + blank_adhoc_member (ts[i]); } return r; @@ -1718,7 +1715,7 @@ namespace build2 r |= mt.executed_state (a); - adhoc_member (ts[i]); + blank_adhoc_member (ts[i]); } return r; @@ -1786,10 +1783,12 @@ namespace build2 for (size_t i (0); i != n; ++i) { - if (pts[i] == nullptr) + prerequisite_target& p (pts[i]); + + if (p == nullptr) continue; - const target& pt (*pts[i]); + const target& pt (*p.target); const auto& tc (pt[a].task_count); if (tc.load (memory_order_acquire) >= target::count_busy ()) @@ -1800,7 +1799,7 @@ namespace build2 // Should we compare the timestamp to this target's? // - if (!e && (!ef || ef (pt, i))) + if (!e && (p.adhoc || !ef || ef (pt, i))) { // If this is an mtime-based target, then compare timestamps. // @@ -1823,11 +1822,13 @@ namespace build2 } } - if (adhoc_member (pts[i])) - continue; - - if (rt == nullptr && pt.is_a (*tt)) - rt = &pt; + if (p.adhoc) + p.target = nullptr; // Blank out. + else + { + if (rt == nullptr && pt.is_a (*tt)) + rt = &pt; + } } assert (rt != nullptr); diff --git a/build2/algorithm.hxx b/build2/algorithm.hxx index 4d6c4ff..c7839d1 100644 --- a/build2/algorithm.hxx +++ b/build2/algorithm.hxx @@ -463,6 +463,12 @@ namespace build2 // prerequisite_targets to NULL. If count is not 0, then only the first // count prerequisites are executed beginning from start. // + // Note that because after the call the ad hoc prerequisites are no longer + // easily accessible, this function shouldn't be used in rules that make a + // timestamp-based out-of-date'ness determination (which must take into + // account such prerequisites). Instead, consider the below versions that + // incorporate the timestamp check and do the right thing. + // target_state straight_execute_prerequisites (action, const target&, size_t count = 0, size_t start = 0); @@ -491,12 +497,13 @@ namespace build2 execute_prerequisites_inner (action, const target&, size_t count = 0); // A version of the above that also determines whether the action needs to - // be executed on the target based on the passed timestamp and filter. + // be executed on the target based on the passed timestamp and filter. If + // count is not 0, then only the first count prerequisites are executed. // // The filter is passed each prerequisite target and is expected to signal // which ones should be used for timestamp comparison. If the filter is - // NULL, then all the prerequisites are used. If count is not 0, then only - // the first count prerequisites are executed. + // NULL, then all the prerequisites are used. Note that ad hoc prerequisites + // are always used. // // Note that the return value is an optional target state. If the target // needs updating, then the value is absent. Otherwise it is the state that @@ -524,7 +531,7 @@ namespace build2 // on the passed timestamp and finds a prerequisite of the specified type // (e.g., a source file). If there are multiple prerequisites of this type, // then the first is returned (this can become important if additional - // prerequisites of the same type may get injected). + // prerequisites of the same type get injected). // template pair, const T&> @@ -552,7 +559,8 @@ namespace build2 // Similar in semantics to execute_prerequisites(). // // T can only be const target* or prerequisite_target. If it is the latter, - // the ad hoc semantics described in execute_prerequsites() is in effect. + // the ad hoc blank out semantics described in execute_prerequsites() is in + // effect. // template target_state diff --git a/build2/cc/compile-rule.cxx b/build2/cc/compile-rule.cxx index 3ed6075..298194a 100644 --- a/build2/cc/compile-rule.cxx +++ b/build2/cc/compile-rule.cxx @@ -4317,6 +4317,9 @@ namespace build2 // execute them to keep the dependency counts straight. Actually, no, we // may also have to update the modules. // + // Note that this also takes care of forcing update on any ad hoc + // prerequisite change. + // auto pr ( execute_prerequisites ( (mod ? *x_mod : x_src), diff --git a/build2/cc/link-rule.cxx b/build2/cc/link-rule.cxx index 28d4fc6..443f91d 100644 --- a/build2/cc/link-rule.cxx +++ b/build2/cc/link-rule.cxx @@ -1633,13 +1633,34 @@ namespace build2 bool binless (md.binless); assert (ot != otype::e || !binless); // Sanity check. - // Update prerequisites. We determine if any relevant ones render us - // out-of-date manually below. + // Determine if we are out-of-date. + // + bool update (false); + bool scratch (false); + timestamp mt (binless ? timestamp_unreal : t.load_mtime ()); + + // Update prerequisites. We determine if any relevant non-ad hoc ones + // render us out-of-date manually below. // - // Note that straight_execute_prerequisites() blanks out all the ad hoc + // Note that execute_prerequisites() blanks out all the ad hoc // prerequisites so we don't need to worry about them from now on. // - target_state ts (straight_execute_prerequisites (a, t)); + target_state ts; + + if (optional s = + execute_prerequisites (a, + t, + mt, + [] (const target&, size_t) {return false;})) + ts = *s; + else + { + // An ad hoc prerequisite renders us out-of-date. Let's update from + // scratch for good measure. + // + scratch = update = true; + ts = target_state::changed; + } // (Re)generate pkg-config's .pc file. While the target itself might be // up-to-date from a previous run, there is no guarantee that .pc exists @@ -1661,11 +1682,6 @@ namespace build2 return ts; } - // Determine if we are out-of-date. - // - bool update (false); - timestamp mt (t.load_mtime ()); - // Open the dependency database (do it before messing with Windows // manifests to diagnose missing output directory). // @@ -2120,7 +2136,6 @@ namespace build2 // target (interrupted update) then force the target update. Also note // this situation in the "from scratch" flag. // - bool scratch (false); if (dd.writing () || dd.mtime > mt) scratch = update = true; -- cgit v1.1