From 54797bb6feb5f94a7f65b69c5b3b16da5410a2bc Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 31 May 2023 07:51:43 +0200 Subject: Provide implied configure_* and dist_* action registration for ad hoc recipes This makes it consistent with the existing ad hoc rules semantics. --- libbuild2/algorithm.cxx | 100 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 73 insertions(+), 27 deletions(-) (limited to 'libbuild2/algorithm.cxx') 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& 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 { - // 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& r) + auto b (t.adhoc_recipes.begin ()), e (t.adhoc_recipes.end ()); + auto i (find_if ( + b, e, + [ca] (const shared_ptr& 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& 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 ( + i != e ? &(*i)->rule_match : nullptr, + f); + }; + + pair 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. -- cgit v1.1