aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/algorithm.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2023-05-31 07:51:43 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2023-05-31 07:51:43 +0200
commit54797bb6feb5f94a7f65b69c5b3b16da5410a2bc (patch)
tree6f3574d8173a30105e627de8b99ecff11d2be0d8 /libbuild2/algorithm.cxx
parente588fd9ba279c7e5d8c94b2b3fbcb55d6197f5c4 (diff)
Provide implied configure_* and dist_* action registration for ad hoc recipes
This makes it consistent with the existing ad hoc rules semantics.
Diffstat (limited to 'libbuild2/algorithm.cxx')
-rw-r--r--libbuild2/algorithm.cxx100
1 files changed, 73 insertions, 27 deletions
diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx
index 581da2e..670355c 100644
--- a/libbuild2/algorithm.cxx
+++ b/libbuild2/algorithm.cxx
@@ -466,39 +466,85 @@ namespace build2
? a
: action (a.meta_operation (), a.outer_operation ()));
- auto b (t.adhoc_recipes.begin ()), e (t.adhoc_recipes.end ());
- auto i (find_if (
- b, e,
- [&match, ca] (const shared_ptr<adhoc_rule>& r)
- {
- auto& as (r->actions);
- return (find (as.begin (), as.end (), ca) != as.end () &&
- match (*r, false));
- }));
-
- if (i == e)
+ // If returned rule_match is NULL, then the second half indicates whether
+ // the rule was found (but did not match).
+ //
+ auto find_match = [&t, &match] (action ca) -> pair<const rule_match*, bool>
{
- // See if we have a fallback implementation.
- //
- // See the adhoc_rule::reverse_fallback() documentation for details on
- // what's going on here.
+ // Note that there can be at most one recipe for any action.
//
- i = find_if (
- b, e,
- [&match, ca, &t] (const shared_ptr<adhoc_rule>& r)
+ auto b (t.adhoc_recipes.begin ()), e (t.adhoc_recipes.end ());
+ auto i (find_if (
+ b, e,
+ [ca] (const shared_ptr<adhoc_rule>& r)
+ {
+ auto& as (r->actions);
+ return find (as.begin (), as.end (), ca) != as.end ();
+ }));
+
+ bool f (i != e);
+ if (f)
+ {
+ if (!match (**i, false /* fallback */))
+ i = e;
+ }
+ else
+ {
+ // See if we have a fallback implementation.
+ //
+ // See the adhoc_rule::reverse_fallback() documentation for details on
+ // what's going on here.
+ //
+ // Note that it feels natural not to look for a fallback if a custom
+ // recipe was provided but did not match.
+ //
+ const target_type& tt (t.type ());
+ i = find_if (
+ b, e,
+ [ca, &tt] (const shared_ptr<adhoc_rule>& r)
+ {
+ // Only the rule that provides the "forward" action can provide
+ // "reverse", so there can be at most one such rule.
+ //
+ return r->reverse_fallback (ca, tt);
+ });
+
+ f = (i != e);
+ if (f)
{
- auto& as (r->actions);
+ if (!match (**i, true /* fallback */))
+ i = e;
+ }
+ }
- // Note that the rule could be there but not match (see above),
- // thus this extra check.
- //
- return (find (as.begin (), as.end (), ca) == as.end () &&
- r->reverse_fallback (ca, t.type ()) &&
- match (*r, true));
- });
+ return pair<const rule_match*, bool> (
+ i != e ? &(*i)->rule_match : nullptr,
+ f);
+ };
+
+ pair<const rule_match*, bool> r (find_match (ca));
+
+ // Provide the "add dist_* and configure_* actions for every perform_*
+ // action unless there is a custom one" semantics (see the equivalent ad
+ // hoc rule registration code in the parser for background).
+ //
+ // Note that handling this in the parser by adding the extra actions is
+ // difficult because we store recipe actions in the recipe itself (
+ // adhoc_rule::actions) and a recipe could be shared among multiple
+ // targets, some of which may provide a "custom one" as another recipe. On
+ // the other hand, handling it here is relatively straightforward.
+ //
+ if (r.first == nullptr && !r.second)
+ {
+ meta_operation_id mo (ca.meta_operation ());
+ if (mo == configure_id || mo == dist_id)
+ {
+ action pa (perform_id, ca.operation ());
+ r = find_match (pa);
+ }
}
- return i != e ? &(*i)->rule_match : nullptr;
+ return r.first;
}
// Return the matching rule or NULL if no match and try_match is true.