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 +++++++++++++++++++++++++++++++++++------------- libbuild2/parser.cxx | 13 ++++++- 2 files changed, 84 insertions(+), 29 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& 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. diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx index 1b8e2d3..b79b65c 100644 --- a/libbuild2/parser.cxx +++ b/libbuild2/parser.cxx @@ -1447,7 +1447,12 @@ namespace build2 // And the same for the configure meta-operation to, for // example, make sure a hinted ad hoc rule matches. @@ Hm, // maybe we fixed this with action-specific hints? But the - // injection part above may still apply. + // injection part above may still apply. BTW, this is also + // required for see-through groups in order to resolve their + // member. + // + // Note also that the equivalent semantics for ad hoc recipes + // is provided by match_adhoc_recipe(). // if (a.meta_operation () == perform_id) { @@ -1469,7 +1474,8 @@ namespace build2 // see-through target group, then we may also need to // register update for other meta-operations (see, for // example, wildcard update registration in the cli - // module). + // module). BTW, we can now detect such a target via + // its target type flags. } } } @@ -2225,6 +2231,9 @@ namespace build2 } target_->adhoc_recipes.push_back (r); + + // Note that "registration" of configure_* and dist_* actions + // (similar to ad hoc rules) is provided by match_adhoc_recipe(). } } -- cgit v1.1