From 378b2598a305d4e332e52460ca89dd867546a58b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 7 Feb 2018 10:00:46 +0200 Subject: Initial work for default update outer operation While update still uses the old "all update rules update all their prerequisites" assumption, test and install have been fixed not to rely on this. --- build2/test/rule.cxx | 83 +++++++++++++++++++++++++++++++++++----------------- build2/test/rule.hxx | 2 +- 2 files changed, 57 insertions(+), 28 deletions(-) (limited to 'build2/test') 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 ()) + if (!p.is_a ()) { 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; -- cgit v1.1