aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/algorithm.cxx36
-rw-r--r--build2/algorithm.hxx43
-rw-r--r--build2/algorithm.ixx58
-rw-r--r--build2/bin/init.cxx2
-rw-r--r--build2/bin/rule.cxx2
-rw-r--r--build2/cc/link-rule.cxx33
-rw-r--r--build2/cli/init.cxx2
-rw-r--r--build2/cli/rule.cxx6
-rw-r--r--build2/config/init.cxx22
-rw-r--r--build2/context.cxx3
-rw-r--r--build2/dist/init.cxx2
-rw-r--r--build2/operation.hxx6
-rw-r--r--build2/rule.cxx25
-rw-r--r--build2/rule.hxx26
-rw-r--r--build2/test/rule.cxx83
-rw-r--r--build2/test/rule.hxx2
16 files changed, 257 insertions, 94 deletions
diff --git a/build2/algorithm.cxx b/build2/algorithm.cxx
index 4e76e4a..58ddb24 100644
--- a/build2/algorithm.cxx
+++ b/build2/algorithm.cxx
@@ -1039,24 +1039,24 @@ namespace build2
template <typename T>
target_state
- straight_execute_members (action a, const target& t, T ts[], size_t n)
+ straight_execute_members (action a, atomic_count& tc,
+ T ts[], size_t n, size_t p)
{
target_state r (target_state::unchanged);
// Start asynchronous execution of prerequisites.
//
- wait_guard wg (target::count_busy (), t[a].task_count);
+ wait_guard wg (target::count_busy (), tc);
- for (size_t i (0); i != n; ++i)
+ n += p;
+ for (size_t i (p); i != n; ++i)
{
const target*& mt (ts[i]);
if (mt == nullptr) // Skipped.
continue;
- target_state s (
- execute_async (
- a, *mt, target::count_busy (), t[a].task_count));
+ target_state s (execute_async (a, *mt, target::count_busy (), tc));
if (s == target_state::postponed)
{
@@ -1071,7 +1071,7 @@ namespace build2
// or executed and synchronized (and we have blanked out all the postponed
// ones).
//
- for (size_t i (0); i != n; ++i)
+ for (size_t i (p); i != n; ++i)
{
if (ts[i] == nullptr)
continue;
@@ -1092,24 +1092,24 @@ namespace build2
template <typename T>
target_state
- reverse_execute_members (action a, const target& t, T ts[], size_t n)
+ reverse_execute_members (action a, atomic_count& tc,
+ T ts[], size_t n, size_t p)
{
// Pretty much as straight_execute_members() but in reverse order.
//
target_state r (target_state::unchanged);
- wait_guard wg (target::count_busy (), t[a].task_count);
+ wait_guard wg (target::count_busy (), tc);
- for (size_t i (n); i != 0; )
+ n = p - n;
+ for (size_t i (p); i != n; )
{
const target*& mt (ts[--i]);
if (mt == nullptr)
continue;
- target_state s (
- execute_async (
- a, *mt, target::count_busy (), t[a].task_count));
+ target_state s (execute_async (a, *mt, target::count_busy (), tc));
if (s == target_state::postponed)
{
@@ -1120,7 +1120,7 @@ namespace build2
wg.wait ();
- for (size_t i (n); i != 0; )
+ for (size_t i (p); i != n; )
{
if (ts[--i] == nullptr)
continue;
@@ -1141,19 +1141,19 @@ namespace build2
//
template target_state
straight_execute_members<const target*> (
- action, const target&, const target*[], size_t);
+ action, atomic_count&, const target*[], size_t, size_t);
template target_state
reverse_execute_members<const target*> (
- action, const target&, const target*[], size_t);
+ action, atomic_count&, const target*[], size_t, size_t);
template target_state
straight_execute_members<prerequisite_target> (
- action, const target&, prerequisite_target[], size_t);
+ action, atomic_count&, prerequisite_target[], size_t, size_t);
template target_state
reverse_execute_members<prerequisite_target> (
- action, const target&, prerequisite_target[], size_t);
+ action, atomic_count&, prerequisite_target[], size_t, size_t);
pair<optional<target_state>, const target*>
execute_prerequisites (const target_type* tt,
diff --git a/build2/algorithm.hxx b/build2/algorithm.hxx
index 8978eba..5287f23 100644
--- a/build2/algorithm.hxx
+++ b/build2/algorithm.hxx
@@ -389,10 +389,12 @@ namespace build2
// changed and target_state::unchanged otherwise. If a prerequisite's
// execution is postponed, then set its pointer in prerequisite_targets to
// NULL (since its state cannot be queried MT-safely). If count is not 0,
- // then only the first count prerequisites are executed.
+ // then only the first count prerequisites are executed beginning from
+ // start.
//
target_state
- straight_execute_prerequisites (action, const target&, size_t count = 0);
+ straight_execute_prerequisites (action, const target&,
+ size_t count = 0, size_t start = 0);
// As above but iterates over the prerequisites in reverse.
//
@@ -404,6 +406,19 @@ namespace build2
target_state
execute_prerequisites (action, const target&, size_t count = 0);
+ // As above but execute prerequisites for the inner action (that have
+ // been matched with match_inner()).
+ //
+ target_state
+ straight_execute_prerequisites_inner (action, const target&,
+ size_t count = 0, size_t start = 0);
+
+ target_state
+ reverse_execute_prerequisites_inner (action, const target&, size_t count = 0);
+
+ target_state
+ 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.
//
@@ -469,11 +484,27 @@ namespace build2
//
template <typename T>
target_state
- straight_execute_members (action, const target&, T[], size_t);
+ straight_execute_members (action, atomic_count&, T[], size_t, size_t);
template <typename T>
target_state
- reverse_execute_members (action, const target&, T[], size_t);
+ reverse_execute_members (action, atomic_count&, T[], size_t, size_t);
+
+ template <typename T>
+ inline target_state
+ straight_execute_members (action a, const target& t,
+ T ts[], size_t c, size_t s)
+ {
+ return straight_execute_members (a, t[a].task_count, ts, c, s);
+ }
+
+ template <typename T>
+ inline target_state
+ reverse_execute_members (action a, const target& t,
+ T ts[], size_t c, size_t s)
+ {
+ return reverse_execute_members (a, t[a].task_count, ts, c, s);
+ }
// Call straight or reverse depending on the current mode.
//
@@ -484,14 +515,14 @@ namespace build2
inline target_state
straight_execute_members (action a, const target& t, const target* (&ts)[N])
{
- return straight_execute_members (a, t, ts, N);
+ return straight_execute_members (a, t, ts, N, 0);
}
template <size_t N>
inline target_state
reverse_execute_members (action a, const target& t, const target* (&ts)[N])
{
- return reverse_execute_members (a, t, ts, N);
+ return reverse_execute_members (a, t, ts, N, N);
}
template <size_t N>
diff --git a/build2/algorithm.ixx b/build2/algorithm.ixx
index 7cad7ff..f0330f6 100644
--- a/build2/algorithm.ixx
+++ b/build2/algorithm.ixx
@@ -349,14 +349,14 @@ namespace build2
// In a sense this is like any other dependency.
//
assert (a.outer ());
- return match (action (a.meta_operation (), a.operation ()), t);
+ return match (a.inner_action (), t);
}
inline bool
match_inner (action a, const target& t, unmatch um)
{
assert (a.outer ());
- return match (action (a.meta_operation (), a.operation ()), t, um);
+ return match (a.inner_action (), t, um);
}
group_view
@@ -368,7 +368,7 @@ namespace build2
group_view r;
if (a.outer ())
- a = action (a.meta_operation (), a.operation ());
+ a = a.inner_action ();
// We can be called during execute though everything should have been
// already resolved.
@@ -480,21 +480,28 @@ namespace build2
execute_inner (action a, const target& t)
{
assert (a.outer ());
- return execute_wait (action (a.meta_operation (), a.operation ()), t);
+ return execute_wait (a.inner_action (), t);
}
inline target_state
- straight_execute_prerequisites (action a, const target& t, size_t c)
+ straight_execute_prerequisites (action a, const target& t,
+ size_t c, size_t s)
{
auto& p (t.prerequisite_targets[a]);
- return straight_execute_members (a, t, p.data (), c == 0 ? p.size () : c);
+ return straight_execute_members (a, t,
+ p.data (),
+ c == 0 ? p.size () - s: c,
+ s);
}
inline target_state
reverse_execute_prerequisites (action a, const target& t, size_t c)
{
auto& p (t.prerequisite_targets[a]);
- return reverse_execute_members (a, t, p.data (), c == 0 ? p.size () : c);
+ return reverse_execute_members (a, t,
+ p.data (),
+ c == 0 ? p.size () : c,
+ p.size ());
}
inline target_state
@@ -505,6 +512,39 @@ namespace build2
: reverse_execute_prerequisites (a, t, c);
}
+ inline target_state
+ straight_execute_prerequisites_inner (action a, const target& t,
+ size_t c, size_t s)
+ {
+ assert (a.outer ());
+ auto& p (t.prerequisite_targets[a]);
+ return straight_execute_members (a.inner_action (),
+ t[a].task_count,
+ p.data (),
+ c == 0 ? p.size () - s : c,
+ s);
+ }
+
+ inline target_state
+ reverse_execute_prerequisites_inner (action a, const target& t, size_t c)
+ {
+ assert (a.outer ());
+ auto& p (t.prerequisite_targets[a]);
+ return reverse_execute_members (a.inner_action (),
+ t[a].task_count,
+ p.data (),
+ c == 0 ? p.size () : c,
+ p.size ());
+ }
+
+ inline target_state
+ execute_prerequisites_inner (action a, const target& t, size_t c)
+ {
+ return current_mode == execution_mode::first
+ ? straight_execute_prerequisites_inner (a, t, c)
+ : reverse_execute_prerequisites_inner (a, t, c);
+ }
+
// If the first argument is NULL, then the result is treated as a boolean
// value.
//
@@ -559,7 +599,7 @@ namespace build2
execute_members (action a, const target& t, const target* ts[], size_t n)
{
return current_mode == execution_mode::first
- ? straight_execute_members (a, t, ts, n)
- : reverse_execute_members (a, t, ts, n);
+ ? straight_execute_members (a, t, ts, n, 0)
+ : reverse_execute_members (a, t, ts, n, n);
}
}
diff --git a/build2/bin/init.cxx b/build2/bin/init.cxx
index 565936f..e7509d3 100644
--- a/build2/bin/init.cxx
+++ b/build2/bin/init.cxx
@@ -462,6 +462,8 @@ namespace build2
// Similar to alias.
//
+
+ //@@ outer
r.insert<lib> (perform_id, 0, "bin.lib", lib_);
r.insert<lib> (configure_id, 0, "bin.lib", lib_);
diff --git a/build2/bin/rule.cxx b/build2/bin/rule.cxx
index 79270c3..cde2d9a 100644
--- a/build2/bin/rule.cxx
+++ b/build2/bin/rule.cxx
@@ -65,6 +65,8 @@ namespace build2
{
lib& t (xt.as<lib> ());
+ //@@ outer: also prerequisites (if outer) or not?
+
const target* m[] = {t.a, t.s};
match_members (a, t, m);
diff --git a/build2/cc/link-rule.cxx b/build2/cc/link-rule.cxx
index d06a835..b6b707d 100644
--- a/build2/cc/link-rule.cxx
+++ b/build2/cc/link-rule.cxx
@@ -56,6 +56,8 @@ namespace build2
//
if (lt.library ())
{
+ //@@ inner/outer race (see install-rule)?
+
if (t.group == nullptr)
t.group = &search (t,
lt.utility ? libu::static_type : lib::static_type,
@@ -621,7 +623,22 @@ namespace build2
//
if (p.is_a<obj> ()) pt = &search (t, tt.obj, p.key ());
else if (p.is_a<bmi> ()) pt = &search (t, tt.bmi, p.key ());
- else pt = &p.search (t);
+ //
+ // Something else. This could be something unrelated that the user
+ // tacked on (e.g., a doc{}). Or it could be some ad hoc input to
+ // the linker (say a linker script or some such).
+ //
+ else
+ {
+ // @@ Temporary hack until we get the default outer operation for
+ // update. This allows operations like test and install to skip
+ // such tacked on stuff.
+ //
+ if (current_outer_oif != nullptr)
+ continue;
+
+ pt = &p.search (t);
+ }
if (skip (pt))
continue;
@@ -676,7 +693,7 @@ namespace build2
// If this obj*{} already has prerequisites, then verify they are
// "compatible" with what we are doing here. Otherwise, synthesize
// the dependency. Note that we may also end up synthesizing with
- // someone beating up to it. In this case also verify.
+ // someone beating us to it. In this case also verify.
//
bool verify (true);
@@ -709,6 +726,9 @@ namespace build2
{
const target* pt (pts[j++]);
+ if (pt == nullptr)
+ continue;
+
if (p.is_a<libx> () ||
p.is_a<liba> () || p.is_a<libs> () || p.is_a<libux> () ||
p.is_a<bmi> () || p.is_a (tt.bmi))
@@ -1155,6 +1175,9 @@ namespace build2
for (const prerequisite_target& pt: t.prerequisite_targets[a])
{
+ if (pt == nullptr)
+ continue;
+
bool la;
const file* f;
@@ -1525,6 +1548,9 @@ namespace build2
{
const target* pt (p.target);
+ if (pt == nullptr)
+ continue;
+
// If this is bmi*{}, then obj*{} is its ad hoc member.
//
if (modules)
@@ -1810,6 +1836,9 @@ namespace build2
{
const target* pt (p.target);
+ if (pt == nullptr)
+ continue;
+
if (modules)
{
if (pt->is_a<bmie> () || pt->is_a<bmia> () || pt->is_a<bmis> ())
diff --git a/build2/cli/init.cxx b/build2/cli/init.cxx
index df123ba..ede0db1 100644
--- a/build2/cli/init.cxx
+++ b/build2/cli/init.cxx
@@ -319,6 +319,8 @@ namespace build2
// resolved/linked up. Looks like a general pattern: groups should
// resolve on *(update).
//
+ // @@ meta-op wildcard?
+ //
reg (configure_id, update_id);
reg (dist_id, update_id);
}
diff --git a/build2/cli/rule.cxx b/build2/cli/rule.cxx
index 42f2176..94b2d24 100644
--- a/build2/cli/rule.cxx
+++ b/build2/cli/rule.cxx
@@ -167,15 +167,15 @@ namespace build2
//
inject_fsdir (a, t);
- // Match prerequisite members.
+ // Match prerequisites.
//
match_prerequisite_members (a, t);
switch (a)
{
case perform_update_id: return &perform_update;
- case perform_clean_id: return &perform_clean_group; // Standard impl.
- default: return noop_recipe; // Configure update.
+ case perform_clean_id: return &perform_clean_group; // Standard impl.
+ default: return noop_recipe; // Configure update.
}
}
else
diff --git a/build2/config/init.cxx b/build2/config/init.cxx
index 2552e77..35bc94c 100644
--- a/build2/config/init.cxx
+++ b/build2/config/init.cxx
@@ -121,19 +121,25 @@ namespace build2
// Register alias and fallback rule for the configure meta-operation.
//
+ // We need this rule for out-of-any-project dependencies (e.g.,
+ // libraries imported from /usr/lib). We are registring it on the
+ // global scope similar to builtin rules.
+ //
{
- // We need this rule for out-of-any-project dependencies (e.g.,
- // libraries imported from /usr/lib). Registring it on the global
- // scope smells a bit but seems harmless.
- //
- rs.global ().rules.insert<mtime_target> (
+ auto& r (rs.global ().rules);
+ r.insert<mtime_target> (
configure_id, 0, "config.file", file_rule::instance);
-
+ }
+ {
auto& r (rs.rules);
- r.insert<target> (configure_id, 0, "config", fallback_rule::instance);
- r.insert<file> (configure_id, 0, "config.file", fallback_rule::instance);
+ //@@ outer
r.insert<alias> (configure_id, 0, "config.alias", alias_rule::instance);
+
+ // This allows a custom configure rule while doing nothing by default.
+ //
+ r.insert<target> (configure_id, 0, "config", noop_rule::instance);
+ r.insert<file> (configure_id, 0, "config.file", noop_rule::instance);
}
return true;
diff --git a/build2/context.cxx b/build2/context.cxx
index 3bb07a8..6f3abcc 100644
--- a/build2/context.cxx
+++ b/build2/context.cxx
@@ -697,8 +697,9 @@ namespace build2
// Register builtin rules.
//
{
- rule_map& r (gs.rules);
+ rule_map& r (gs.rules); // Note: global scope!
+ //@@ outer
r.insert<alias> (perform_id, 0, "alias", alias_rule::instance);
r.insert<fsdir> (perform_update_id, "fsdir", fsdir_rule::instance);
diff --git a/build2/dist/init.cxx b/build2/dist/init.cxx
index 818570a..fe0e9a9 100644
--- a/build2/dist/init.cxx
+++ b/build2/dist/init.cxx
@@ -94,7 +94,7 @@ namespace build2
// something like insert<target>(dist_id, test_id) taking precedence.
//
rs.rules.insert<target> (dist_id, 0, "dist", rule_);
- rs.rules.insert<alias> (dist_id, 0, "dist.alias", rule_);
+ rs.rules.insert<alias> (dist_id, 0, "dist.alias", rule_); //@@ outer?
// Configuration.
//
diff --git a/build2/operation.hxx b/build2/operation.hxx
index 8c9818e..e79a57c 100644
--- a/build2/operation.hxx
+++ b/build2/operation.hxx
@@ -70,6 +70,12 @@ namespace build2
bool inner () const {return outer_id == 0;}
bool outer () const {return outer_id != 0;}
+ action
+ inner_action () const
+ {
+ return action (meta_operation (), operation ());
+ }
+
// Implicit conversion operator to action_id for the switch() statement,
// etc. Most places only care about the inner operation.
//
diff --git a/build2/rule.cxx b/build2/rule.cxx
index ef1d3a4..e215846 100644
--- a/build2/rule.cxx
+++ b/build2/rule.cxx
@@ -98,6 +98,11 @@ namespace build2
recipe file_rule::
apply (action a, target& t) const
{
+ /*
+ @@ outer
+ return noop_recipe;
+ */
+
// Update triggers the update of this target's prerequisites so it would
// seem natural that we should also trigger their cleanup. However, this
// possibility is rather theoretical so until we see a real use-case for
@@ -220,6 +225,8 @@ namespace build2
// First update prerequisites (e.g. create parent directories) then create
// this directory.
//
+ // @@ outer: should we assume for simplicity its only prereqs are fsdir{}?
+ //
if (!t.prerequisite_targets[a].empty ())
ts = straight_execute_prerequisites (a, t);
@@ -232,6 +239,8 @@ namespace build2
// better performance by first checking if it indeed exists. See
// butl::try_mkdir() for details.
//
+ // @@ Also skip prerequisites? Can't we return noop in apply?
+ //
if (!exists (d) && fsdir_mkdir (t, d))
ts |= target_state::changed;
@@ -280,7 +289,19 @@ namespace build2
const fsdir_rule fsdir_rule::instance;
- // fallback_rule
+ // noop_rule
//
- const fallback_rule fallback_rule::instance;
+ bool noop_rule::
+ match (action, target&, const string&) const
+ {
+ return true;
+ }
+
+ recipe noop_rule::
+ apply (action, target&) const
+ {
+ return noop_recipe;
+ }
+
+ const noop_rule noop_rule::instance;
}
diff --git a/build2/rule.hxx b/build2/rule.hxx
index 8e43ca6..f4a7798 100644
--- a/build2/rule.hxx
+++ b/build2/rule.hxx
@@ -29,41 +29,38 @@ namespace build2
apply (action, target&) const = 0;
};
- // Fallback rule that only matches if the file exists.
+ // Fallback rule that only matches if the file exists. It will also match
+ // an mtime_target provided it has a set timestamp.
//
class file_rule: public rule
{
public:
- file_rule () {}
-
virtual bool
match (action, target&, const string&) const override;
virtual recipe
apply (action, target&) const override;
+ file_rule () {}
static const file_rule instance;
};
class alias_rule: public rule
{
public:
- alias_rule () {}
-
virtual bool
match (action, target&, const string&) const override;
virtual recipe
apply (action, target&) const override;
+ alias_rule () {}
static const alias_rule instance;
};
class fsdir_rule: public rule
{
public:
- fsdir_rule () {}
-
virtual bool
match (action, target&, const string&) const override;
@@ -82,26 +79,23 @@ namespace build2
static void
perform_update_direct (action, const target&);
+ fsdir_rule () {}
static const fsdir_rule instance;
};
// Fallback rule that always matches and does nothing.
//
- class fallback_rule: public build2::rule
+ class noop_rule: public rule
{
public:
- fallback_rule () {}
-
virtual bool
- match (action, target&, const string&) const override
- {
- return true;
- }
+ match (action, target&, const string&) const override;
virtual recipe
- apply (action, target&) const override {return noop_recipe;}
+ apply (action, target&) const override;
- static const fallback_rule instance;
+ noop_rule () {}
+ static const noop_rule instance;
};
}
diff --git a/build2/test/rule.cxx b/build2/test/rule.cxx
index 7c55445..86062f9 100644
--- a/build2/test/rule.cxx
+++ b/build2/test/rule.cxx
@@ -142,16 +142,32 @@ namespace build2
break;
}
- // If this is the test operation, collect testscripts after the
- // pass-through prerequisites.
+ // Collect testscripts after the pass-through prerequisites.
//
- // Note that we don't match nor execute them relying on update to
- // assign their paths and make sure they are up to date.
+ const target& pt (p.search (t));
+
+ // Note that for the test operation itself we don't match nor
+ // execute them relying on update to assign their paths.
+ //
+ // Causing update for test inputs/scripts is tricky: we cannot
+ // match for update_for_install because this same rule will match
+ // and since the target is not testable, it will return the noop
+ // recipe.
+ //
+ // So what we are going to do is directly match (and also execute;
+ // see below) a recipe for the inner update (who thought we could
+ // do that... but it seems we can). While at first it might feel
+ // iffy, it does make sense: the outer rule we would have matched
+ // would have simply delegated to the inner so we might as well
+ // take a shortcut. The only potential drawback of this approach
+ // is that we won't be able to provide any for_test customizations
+ // when updating test inputs/scripts. But such a need seems rather
+ // far fetched.
//
- if (a.operation () != test_id)
- break;
+ if (a.operation () == update_id)
+ match_inner (a, pt);
- pts.push_back (&p.search (t));
+ pts.push_back (&pt);
}
}
@@ -196,14 +212,9 @@ namespace build2
if (si || so || in)
{
- // Note that we don't match nor execute them relying on update
- // to assign their paths and make sure they are up to date.
- //
- const target& pt (p.search (t));
-
// Verify it is file-based.
//
- if (!pt.is_a<file> ())
+ if (!p.is_a<file> ())
{
fail << "test." << (si ? "stdin" : so ? "stdout" : "input")
<< " prerequisite " << p << " of target " << t
@@ -214,9 +225,6 @@ namespace build2
{
test = true;
- if (a.operation () != test_id)
- break;
-
// First matching prerequisite. Establish the structure in
// pts: the first element (after pass_n) is stdin (can be
// NULL), the second is stdout (can be NULL), and everything
@@ -226,13 +234,31 @@ namespace build2
pts.push_back (nullptr); // stdout
}
+ // Collect them after the pass-through prerequisites.
+ //
+ // Note that for the test operation itself we don't match nor
+ // execute them relying on update to assign their paths.
+ //
+ auto match = [a, &p, &t] () -> const target*
+ {
+ const target& pt (p.search (t));
+
+ // The same match_inner() rationale as for the testcript
+ // prerequisites above.
+ //
+ if (a.operation () == update_id)
+ match_inner (a, pt);
+
+ return &pt;
+ };
+
if (si)
{
if (pts[pass_n] != nullptr)
fail << "multiple test.stdin prerequisites for target "
<< t;
- pts[pass_n] = &pt;
+ pts[pass_n] = match ();
}
if (so)
@@ -241,11 +267,11 @@ namespace build2
fail << "multiple test.stdout prerequisites for target "
<< t;
- pts[pass_n + 1] = &pt;
+ pts[pass_n + 1] = match ();
}
if (in)
- pts.push_back (&pt);
+ pts.push_back (match ());
}
}
@@ -274,11 +300,13 @@ namespace build2
if (a.operation () == update_id)
{
// For the update pre-operation match the inner rule (actual update).
- // Note that here we assume it will update (if required) all the
- // testscript and input/output prerequisites.
//
match_inner (a, t);
- return &perform_update;
+
+ return [pass_n, this] (action a, const target& t)
+ {
+ return perform_update (a, t, pass_n);
+ };
}
else
{
@@ -300,15 +328,16 @@ namespace build2
}
target_state rule::
- perform_update (action a, const target& t)
+ perform_update (action a, const target& t, size_t pass_n)
{
- // First execute the inner recipe, then, if passing-through, execute
- // prerequisites.
+ // First execute the inner recipe then execute prerequisites.
//
target_state ts (execute_inner (a, t));
- if (t.prerequisite_targets[a].size () != 0)
- ts |= straight_execute_prerequisites (a, t);
+ if (pass_n != 0)
+ ts |= straight_execute_prerequisites (a, t, pass_n);
+
+ ts |= straight_execute_prerequisites_inner (a, t, 0, pass_n);
return ts;
}
diff --git a/build2/test/rule.hxx b/build2/test/rule.hxx
index 4f02390..85fa1cd 100644
--- a/build2/test/rule.hxx
+++ b/build2/test/rule.hxx
@@ -27,7 +27,7 @@ namespace build2
apply (action, target&) const override;
static target_state
- perform_update (action, const target&);
+ perform_update (action, const target&, size_t);
target_state
perform_test (action, const target&, size_t) const;