From 548bdfb7bdd7c4761b58bed18b0032afc05b3ce4 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 3 Dec 2020 10:59:34 +0200 Subject: Add match_rule() in addition to match_recipe() --- libbuild2/algorithm.cxx | 8 ++------ libbuild2/algorithm.hxx | 22 +++++++++++++++------- libbuild2/algorithm.ixx | 36 ++++++++++++++++++++++++++++++++---- libbuild2/rule.cxx | 1 + libbuild2/rule.hxx | 4 +++- 5 files changed, 53 insertions(+), 18 deletions(-) (limited to 'libbuild2') diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx index e535af3..d1a796d 100644 --- a/libbuild2/algorithm.cxx +++ b/libbuild2/algorithm.cxx @@ -682,9 +682,7 @@ namespace build2 // in its match() (provided that it matches) in order to, for // example, convey some information to apply(). // - s.vars.clear (); - t.prerequisite_targets[a].clear (); - if (a.inner ()) t.clear_data (); + clear_target (a, t); const rule_match* r (match_rule (a, t, nullptr, try_match)); @@ -723,9 +721,7 @@ namespace build2 // As a sanity measure clear the target data since it can be incomplete // or invalid (mark()/unmark() should give you some ideas). // - s.vars.clear (); - t.prerequisite_targets[a].clear (); - if (a.inner ()) t.clear_data (); + clear_target (a, t); s.state = target_state::failed; l.offset = target::offset_applied; diff --git a/libbuild2/algorithm.hxx b/libbuild2/algorithm.hxx index 2a07acf..34e844c 100644 --- a/libbuild2/algorithm.hxx +++ b/libbuild2/algorithm.hxx @@ -184,16 +184,18 @@ namespace build2 dependency_cycle (action, const target&); // If the target is already applied (for this action) or executed, then no - // lock is acquired. Otherwise, the target must not yet be matched for this - // action. + // lock is acquired. Otherwise, unless matched is true, the target must not + // be matched but not yet applied for this action (and if that's the case + // and matched is true, then you get a locked target that you should + // probably check for consistency, for exmaple, by comparing the matched + // rule). // // @@ MT fuzzy: what if it is already in the desired state, why assert? - // Currently we only use it with match_recipe() and if it is matched - // but not applied, then it's not clear why we are overriding that - // match. + // Currently we only use it with match_recipe/rule() and if it is matched + // but not applied, then it's not clear why we are overriding that match. // target_lock - lock (action, const target&); + lock (action, const target&, bool matched = false); // Add an ad hoc member to the end of the chain assuming that an already // existing member of this target type is the same. Return the newly added @@ -315,12 +317,18 @@ namespace build2 size_t start_count, atomic_count& task_count, bool fail = true); - // Match by specifying the recipe directly and without incrementing the + // Apply the specified recipe directly and without incrementing the // dependency counts. The target must be locked. // void match_recipe (target_lock&, recipe); + // Match (but do not apply) the specified rule directly and without + // incrementing the dependency counts. The target must be locked. + // + void + match_rule (target_lock&, const rule_match&); + // Match a "delegate rule" from withing another rules' apply() function // avoiding recursive matches (thus the third argument). Unless try_match is // true, fail if no rule is found. Otherwise return empty recipe. Note that diff --git a/libbuild2/algorithm.ixx b/libbuild2/algorithm.ixx index 97a8519..eb20ad0 100644 --- a/libbuild2/algorithm.ixx +++ b/libbuild2/algorithm.ixx @@ -221,14 +221,16 @@ namespace build2 } inline target_lock - lock (action a, const target& t) + lock (action a, const target& t, bool m) { - // We don't allow locking a target that has already been matched. + // We don't allow locking a target that has already been matched unless + // explicitly requested by the caller. // target_lock r (lock_impl (a, t, scheduler::work_none)); assert (!r || r.offset == target::offset_touched || - r.offset == target::offset_tried); + r.offset == target::offset_tried || + (m && r.offset == target::offset_matched)); return r; } @@ -371,6 +373,17 @@ namespace build2 return r; } + // Clear rule match-specific target data. + // + inline void + clear_target (action a, target& t) + { + t[a].vars.clear (); + t.prerequisite_targets[a].clear (); + if (a.inner ()) + t.clear_data (); + } + inline void set_recipe (target_lock& l, recipe&& r) { @@ -414,13 +427,28 @@ namespace build2 inline void match_recipe (target_lock& l, recipe r) { - assert (l.target != nullptr && l.target->ctx.phase == run_phase::match); + assert (l.target != nullptr && + l.offset != target::offset_matched && + l.target->ctx.phase == run_phase::match); + clear_target (l.action, *l.target); (*l.target)[l.action].rule = nullptr; // No rule. set_recipe (l, move (r)); l.offset = target::offset_applied; } + inline void + match_rule (target_lock& l, const rule_match& r) + { + assert (l.target != nullptr && + l.offset != target::offset_matched && + l.target->ctx.phase == run_phase::match); + + clear_target (l.action, *l.target); + (*l.target)[l.action].rule = &r; + l.offset = target::offset_matched; + } + inline recipe match_delegate (action a, target& t, const rule& dr, bool try_match) { diff --git a/libbuild2/rule.cxx b/libbuild2/rule.cxx index 6af074c..8b2b021 100644 --- a/libbuild2/rule.cxx +++ b/libbuild2/rule.cxx @@ -153,6 +153,7 @@ namespace build2 } const file_rule file_rule::instance; + const rule_match file_rule::rule_match ("file", file_rule::instance); // alias_rule // diff --git a/libbuild2/rule.hxx b/libbuild2/rule.hxx index e29c0b8..217632f 100644 --- a/libbuild2/rule.hxx +++ b/libbuild2/rule.hxx @@ -81,7 +81,9 @@ namespace build2 apply (action, target&) const override; file_rule () {} + static const file_rule instance; + static const build2::rule_match rule_match; }; class LIBBUILD2_SYMEXPORT alias_rule: public simple_rule @@ -197,7 +199,7 @@ namespace build2 // latter does. As a result, we use special-looking "" // names. // - build2::rule_match rule_match; + const build2::rule_match rule_match; static const dir_path recipes_build_dir; -- cgit v1.1