aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2020-12-03 10:59:34 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2020-12-03 10:59:34 +0200
commit548bdfb7bdd7c4761b58bed18b0032afc05b3ce4 (patch)
tree60394a7ffbfc7ff1509c9f9f62be6d66d8bea2ae
parenta34582df17e2ca4a4e1b204152c82d935bca7467 (diff)
Add match_rule() in addition to match_recipe()
-rw-r--r--libbuild2/algorithm.cxx8
-rw-r--r--libbuild2/algorithm.hxx22
-rw-r--r--libbuild2/algorithm.ixx36
-rw-r--r--libbuild2/rule.cxx1
-rw-r--r--libbuild2/rule.hxx4
5 files changed, 53 insertions, 18 deletions
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 "<ad hoc X recipe>"
// names.
//
- build2::rule_match rule_match;
+ const build2::rule_match rule_match;
static const dir_path recipes_build_dir;