From 05ae6014aa01a8347844cce89085bdcb591160f0 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 28 Apr 2020 08:48:53 +0200 Subject: Add ad hoc recipes plumbing --- libbuild2/algorithm.cxx | 26 +++++++++++++++++++++----- libbuild2/algorithm.ixx | 4 ++-- libbuild2/recipe.hxx | 8 ++++++++ libbuild2/rule.cxx | 24 ++++++++++++++++++++++++ libbuild2/rule.hxx | 18 ++++++++++++++++++ libbuild2/target.hxx | 5 +++++ 6 files changed, 78 insertions(+), 7 deletions(-) diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx index ef1a78d..9b2162e 100644 --- a/libbuild2/algorithm.cxx +++ b/libbuild2/algorithm.cxx @@ -318,12 +318,28 @@ namespace build2 // Return the matching rule or NULL if no match and try_match is true. // const rule_match* - match_impl (action a, target& t, const rule* skip, bool try_match) + match_rule (action a, target& t, const rule* skip, bool try_match) { + // First check for an ad hoc recipe. + // + if (!t.adhoc_recipes.empty ()) + { + auto df = make_diag_frame ( + [a, &t](const diag_record& dr) + { + if (verb != 0) + dr << info << "while matching ad hoc recipe to " << diag_do (a, t); + }); + + if (adhoc_rule::instance.match (a, t, string () /* hint */)) + return &adhoc_rule::match_instance; + } + // If this is an outer operation (Y-for-X), then we look for rules - // registered for the outer id (X). Note that we still pass the original - // action to the rule's match() function so that it can distinguish - // between a pre/post operation (Y-for-X) and the actual operation (X). + // registered for the outer id (X; yes, it's really outer). Note that we + // still pass the original action to the rule's match() function so that + // it can distinguish between a pre/post operation (Y-for-X) and the + // actual operation (X). // meta_operation_id mo (a.meta_operation ()); operation_id o (a.inner () ? a.operation () : a.outer_operation ()); @@ -561,7 +577,7 @@ namespace build2 t.prerequisite_targets[a].clear (); if (a.inner ()) t.clear_data (); - const rule_match* r (match_impl (a, t, nullptr, try_match)); + const rule_match* r (match_rule (a, t, nullptr, try_match)); assert (l.offset != target::offset_tried); // Should have failed. diff --git a/libbuild2/algorithm.ixx b/libbuild2/algorithm.ixx index 7231fec..5f9143a 100644 --- a/libbuild2/algorithm.ixx +++ b/libbuild2/algorithm.ixx @@ -263,7 +263,7 @@ namespace build2 } LIBBUILD2_SYMEXPORT const rule_match* - match_impl (action, target&, const rule* skip, bool try_match = false); + match_rule (action, target&, const rule* skip, bool try_match = false); LIBBUILD2_SYMEXPORT recipe apply_impl (action, target&, const rule_match&); @@ -424,7 +424,7 @@ namespace build2 // Note: we don't touch any of the t[a] state since that was/will be set // for the delegating rule. // - const rule_match* r (match_impl (a, t, &dr, try_match)); + const rule_match* r (match_rule (a, t, &dr, try_match)); return r != nullptr ? apply_impl (a, t, *r) : empty_recipe; } diff --git a/libbuild2/recipe.hxx b/libbuild2/recipe.hxx index 508c059..a4933dd 100644 --- a/libbuild2/recipe.hxx +++ b/libbuild2/recipe.hxx @@ -48,6 +48,14 @@ namespace build2 LIBBUILD2_SYMEXPORT extern const recipe noop_recipe; LIBBUILD2_SYMEXPORT extern const recipe default_recipe; LIBBUILD2_SYMEXPORT extern const recipe group_recipe; + + // Ad hoc recipe. + // + struct adhoc_recipe + { + build2::action action; + }; + } #endif // LIBBUILD2_RECIPE_HXX diff --git a/libbuild2/rule.cxx b/libbuild2/rule.cxx index 3a32eed..a57aaaa 100644 --- a/libbuild2/rule.cxx +++ b/libbuild2/rule.cxx @@ -305,4 +305,28 @@ namespace build2 } const noop_rule noop_rule::instance; + + // adhoc_rule + // + bool adhoc_rule:: + match (action a, target& t, const string&) const + { + // @@ Should we be looking for outer/inner and then just inner, like in + // rule match? See match_rule() for the normal rule semantics. + // + auto i (find_if (t.adhoc_recipes.begin (), + t.adhoc_recipes.end (), + [a] (const adhoc_recipe& r) {return r.action == a;})); + + return i != t.adhoc_recipes.end (); + } + + recipe adhoc_rule:: + apply (action, target&) const + { + return empty_recipe; + } + + const adhoc_rule adhoc_rule::instance; + const rule_match adhoc_rule::match_instance {"adhoc", adhoc_rule::instance}; } diff --git a/libbuild2/rule.hxx b/libbuild2/rule.hxx index 9eab1f6..c15064e 100644 --- a/libbuild2/rule.hxx +++ b/libbuild2/rule.hxx @@ -108,6 +108,24 @@ namespace build2 noop_rule () {} static const noop_rule instance; }; + + // Ad hoc recipe rule. + // + // Note: should not be used directly (e.g., registered, etc). + // + class LIBBUILD2_SYMEXPORT adhoc_rule: public rule + { + public: + virtual bool + match (action, target&, const string&) const override; + + virtual recipe + apply (action, target&) const override; + + adhoc_rule () {} + static const adhoc_rule instance; + static const rule_match match_instance; + }; } #endif // LIBBUILD2_RULE_HXX diff --git a/libbuild2/target.hxx b/libbuild2/target.hxx index 9975f33..b237f1f 100644 --- a/libbuild2/target.hxx +++ b/libbuild2/target.hxx @@ -410,6 +410,11 @@ namespace build2 value& append (const variable&); + // Ad hoc recipes. + // + public: + vector adhoc_recipes; + // Target operation state. // public: -- cgit v1.1