aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2019-04-17 13:42:37 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2019-04-17 13:42:37 +0200
commitca0f9c71be279aee845bf5328ac0af8c02c8849e (patch)
treef8e5ccf1722a90895af7aef36e775fac0088ee7e
parent9f537aca20984524a442e4829e5bba2e9f0df91b (diff)
Incorporate ad hoc prerequisite mtime into out-of-date determination
-rw-r--r--build2/algorithm.cxx35
-rw-r--r--build2/algorithm.hxx18
-rw-r--r--build2/cc/compile-rule.cxx3
-rw-r--r--build2/cc/link-rule.cxx35
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 <typename T>
@@ -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 <typename T>
pair<optional<target_state>, 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 <typename T>
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<file> (
(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<target_state> 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;