From 51666badaa58d1cc70a05b362dbf9fbef64a7296 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 20 Oct 2020 15:16:28 +0200 Subject: Add operation callback for adhoc rule match and apply --- libbuild2/adhoc-rule-buildscript.cxx | 5 ++-- libbuild2/adhoc-rule-buildscript.hxx | 5 ++-- libbuild2/adhoc-rule-cxx.cxx | 10 ++++---- libbuild2/adhoc-rule-cxx.hxx | 4 ++-- libbuild2/algorithm.cxx | 44 +++++++++++++++++++++++++++--------- libbuild2/forward.hxx | 2 ++ libbuild2/install/operation.cxx | 8 ++++++- libbuild2/operation.cxx | 6 +++++ libbuild2/operation.hxx | 15 ++++++++++-- libbuild2/recipe.hxx | 2 -- libbuild2/rule.cxx | 7 +++--- libbuild2/rule.hxx | 25 ++++++++++---------- libbuild2/test/operation.cxx | 6 ++++- 13 files changed, 95 insertions(+), 44 deletions(-) diff --git a/libbuild2/adhoc-rule-buildscript.cxx b/libbuild2/adhoc-rule-buildscript.cxx index c68f4b2..ed53c95 100644 --- a/libbuild2/adhoc-rule-buildscript.cxx +++ b/libbuild2/adhoc-rule-buildscript.cxx @@ -99,7 +99,8 @@ namespace build2 } bool adhoc_buildscript_rule:: - match (action a, target& t, const string&, optional fb) const + match (action a, target& t, const string&, match_extra&, + optional fb) const { if (!fb) ; @@ -122,7 +123,7 @@ namespace build2 } recipe adhoc_buildscript_rule:: - apply (action a, target& t) const + apply (action a, target& t, match_extra&) const { // If this is an outer operation (e.g., update-for-test), then delegate to // the inner. diff --git a/libbuild2/adhoc-rule-buildscript.hxx b/libbuild2/adhoc-rule-buildscript.hxx index b863d77..d7543c4 100644 --- a/libbuild2/adhoc-rule-buildscript.hxx +++ b/libbuild2/adhoc-rule-buildscript.hxx @@ -22,10 +22,11 @@ namespace build2 { public: virtual bool - match (action, target&, const string&, optional) const override; + match (action, target&, const string&, match_extra&, + optional) const override; virtual recipe - apply (action, target&) const override; + apply (action, target&, match_extra&) const override; target_state perform_update_file (action, const target&) const; diff --git a/libbuild2/adhoc-rule-cxx.cxx b/libbuild2/adhoc-rule-cxx.cxx index 8d9b788..3f52b53 100644 --- a/libbuild2/adhoc-rule-cxx.cxx +++ b/libbuild2/adhoc-rule-cxx.cxx @@ -63,7 +63,7 @@ namespace build2 #if defined(BUILD2_BOOTSTRAP) || defined(LIBBUILD2_STATIC_BUILD) bool adhoc_cxx_rule:: - match (action, target&, const string&) const + match (action, target&, const string&, match_extra&) const { // Note that we wait until match() (instead of, say, failing in the // parser) to allow the presence of ad hoc C++ recipes for other @@ -92,7 +92,7 @@ namespace build2 load_module_library (const path& lib, const string& sym, string& err); bool adhoc_cxx_rule:: - match (action a, target& t, const string& hint) const + match (action a, target& t, const string& hint, match_extra& me) const { tracer trace ("adhoc_cxx_rule::match"); @@ -653,13 +653,13 @@ namespace build2 } } - return impl->match (a, t, hint); + return impl->match (a, t, hint, me); } #endif // BUILD2_BOOTSTRAP || LIBBUILD2_STATIC_BUILD recipe adhoc_cxx_rule:: - apply (action a, target& t) const + apply (action a, target& t, match_extra& me) const { - return impl.load (memory_order_relaxed)->apply (a, t); + return impl.load (memory_order_relaxed)->apply (a, t, me); } } diff --git a/libbuild2/adhoc-rule-cxx.hxx b/libbuild2/adhoc-rule-cxx.hxx index fbcdd4f..038d2e1 100644 --- a/libbuild2/adhoc-rule-cxx.hxx +++ b/libbuild2/adhoc-rule-cxx.hxx @@ -51,10 +51,10 @@ namespace build2 { public: virtual bool - match (action, target&, const string&) const override; + match (action, target&, const string&, match_extra&) const override; virtual recipe - apply (action, target&) const override; + apply (action, target&, match_extra&) const override; adhoc_cxx_rule (const location&, size_t, uint64_t ver, diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx index 53aac4e..b540138 100644 --- a/libbuild2/algorithm.cxx +++ b/libbuild2/algorithm.cxx @@ -326,6 +326,18 @@ namespace build2 dr << info << "while matching ad hoc recipe to " << diag_do (a, t); }); + auto match = [a, &t] (const adhoc_rule& r, optional ra) + { + match_extra me; + + if (auto* f = (a.outer () + ? t.ctx.current_outer_oif + : t.ctx.current_inner_oif)->adhoc_match) + return f (r, a, t, string () /* hint */, me, ra); + else + return r.match (a, t, string () /* hint */, me, ra); + }; + // The action could be Y-for-X while the ad hoc recipes are always for // X. So strip the Y-for part for comparison (but not for the match() // calls; see below for the hairy inner/outer semantics details). @@ -337,17 +349,17 @@ namespace build2 auto b (t.adhoc_recipes.begin ()), e (t.adhoc_recipes.end ()); auto i (find_if ( b, e, - [a, ca, &t] (const adhoc_recipe& r) + [&match, ca] (const adhoc_recipe& r) { auto& as (r.actions); return (find (as.begin (), as.end (), ca) != as.end () && - r.rule->match (a, t, string () /* hint */, nullopt)); + match (*r.rule, nullopt)); })); if (i == e) i = find_if ( b, e, - [a, ca, &t] (const adhoc_recipe& r) + [&match, ca] (const adhoc_recipe& r) { // See the adhoc_rule::match() documentation for details on what's // going on here. @@ -356,7 +368,7 @@ namespace build2 if (find (as.begin (), as.end (), ca) == as.end ()) { for (auto ra: as) - if (r.rule->match (a, t, string () /* hint */, ra)) + if (match (*r.rule, ra)) return true; } return false; @@ -450,7 +462,7 @@ namespace build2 << diag_do (a, t); }); - rule::match_extra me; + match_extra me; if (!ru.match (a, t, hint, me)) continue; } @@ -480,7 +492,7 @@ namespace build2 // // @@ Can't we temporarily swap things out in target? // - rule::match_extra me1; + match_extra me1; if (!ru1.match (a, t, hint, me1)) continue; } @@ -568,18 +580,28 @@ namespace build2 recipe apply_impl (action a, target& t, - const pair>& r) + const pair>& m) { auto df = make_diag_frame ( - [a, &t, &r](const diag_record& dr) + [a, &t, &m](const diag_record& dr) { if (verb != 0) - dr << info << "while applying rule " << r.first << " to " + dr << info << "while applying rule " << m.first << " to " << diag_do (a, t); }); - rule::match_extra me; - return r.second.get ().apply (a, t, me); + const rule& r (m.second); + match_extra me; + + if (auto* f = (a.outer () + ? t.ctx.current_outer_oif + : t.ctx.current_inner_oif)->adhoc_apply) + { + if (auto* ar = dynamic_cast (&r)) + return f (*ar, a, t, me); + } + + return r.apply (a, t, me); } // If step is true then perform only one step of the match/apply sequence. diff --git a/libbuild2/forward.hxx b/libbuild2/forward.hxx index 94eb006..cd0f3c3 100644 --- a/libbuild2/forward.hxx +++ b/libbuild2/forward.hxx @@ -65,7 +65,9 @@ namespace build2 // // + struct match_extra; class rule; + class adhoc_rule; // // diff --git a/libbuild2/install/operation.cxx b/libbuild2/install/operation.cxx index 61908c7..54d5b9a 100644 --- a/libbuild2/install/operation.cxx +++ b/libbuild2/install/operation.cxx @@ -40,6 +40,8 @@ namespace build2 execution_mode::first, 0 /* concurrency */, // Run serially. &install_pre, + nullptr, + nullptr, nullptr }; @@ -63,6 +65,8 @@ namespace build2 execution_mode::last, 0 /* concurrency */, // Run serially &install_pre, + nullptr, + nullptr, nullptr }; @@ -79,7 +83,9 @@ namespace build2 op_update.mode, op_update.concurrency, op_update.pre, - op_update.post + op_update.post, + op_update.adhoc_match, + op_update.adhoc_apply }; } } diff --git a/libbuild2/operation.cxx b/libbuild2/operation.cxx index 1594d8b..12aba0c 100644 --- a/libbuild2/operation.cxx +++ b/libbuild2/operation.cxx @@ -606,6 +606,8 @@ namespace build2 execution_mode::first, 1 /* concurrency */, nullptr, + nullptr, + nullptr, nullptr }; @@ -630,6 +632,8 @@ namespace build2 execution_mode::first, 1 /* concurrency */, nullptr, + nullptr, + nullptr, nullptr }; @@ -644,6 +648,8 @@ namespace build2 execution_mode::last, 1 /* concurrency */, nullptr, + nullptr, + nullptr, nullptr }; } diff --git a/libbuild2/operation.hxx b/libbuild2/operation.hxx index b1cdf21..cfd6a95 100644 --- a/libbuild2/operation.hxx +++ b/libbuild2/operation.hxx @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -67,7 +68,7 @@ namespace build2 // const bool bootstrap_outer; - // The first argument in all the callback is the meta-operation + // The first argument in all the callbacks is the meta-operation // parameters. // // If the meta-operation expects parameters, then it should have a @@ -215,7 +216,7 @@ namespace build2 // const size_t concurrency; - // The first argument in all the callback is the operation parameters. + // The first argument in all the callbacks is the operation parameters. // // If the operation expects parameters, then it should have a non-NULL // pre(). Failed that, any parameters will be diagnosed as unexpected. @@ -226,6 +227,16 @@ namespace build2 // operation_id (*pre) (const values&, meta_operation_id, const location&); operation_id (*post) (const values&, meta_operation_id); + + // Operation-specific ad hoc rule callbacks. Essentially, if not NULL, + // then every ad hoc rule match and apply call for this operation is + // proxied through these functions. + // + bool (*adhoc_match) (const adhoc_rule&, + action, target&, const string&, match_extra&, + optional); + + recipe (*adhoc_apply) (const adhoc_rule&, action, target&, match_extra&); }; // Built-in operations. diff --git a/libbuild2/recipe.hxx b/libbuild2/recipe.hxx index 823f804..b88311c 100644 --- a/libbuild2/recipe.hxx +++ b/libbuild2/recipe.hxx @@ -54,8 +54,6 @@ namespace build2 // A recipe is a fragment of a rule so we handle ad hoc recipies by // "completing" them to rules. // - class adhoc_rule; - struct adhoc_recipe { small_vector actions; diff --git a/libbuild2/rule.cxx b/libbuild2/rule.cxx index ac5b310..a671b04 100644 --- a/libbuild2/rule.cxx +++ b/libbuild2/rule.cxx @@ -332,13 +332,14 @@ namespace build2 const dir_path adhoc_rule::recipes_build_dir ("recipes"); bool adhoc_rule:: - match (action a, target& t, const string& h, optional fallback) const + match (action a, target& t, const string& h, match_extra& me, + optional fallback) const { - return !fallback && match (a, t, h); + return !fallback && match (a, t, h, me); } bool adhoc_rule:: - match (action, target&, const string&) const + match (action, target&, const string&, match_extra&) const { return true; } diff --git a/libbuild2/rule.hxx b/libbuild2/rule.hxx index ae9c865..fa61bc5 100644 --- a/libbuild2/rule.hxx +++ b/libbuild2/rule.hxx @@ -24,17 +24,17 @@ namespace build2 // // Note: match() is only called once but may not be followed by apply(). // + // The match_extra argument is used to pass additional information that is + // only needed by some rule implementations. It is also a way for us to + // later pass more information without breaking source compatibility. + // + struct match_extra + { + }; + class LIBBUILD2_SYMEXPORT rule { public: - // The match_extra argument is used to pass additional information that is - // only needed by some rule implementations. It is also a way for us to - // later pass more information without breaking source compatibility. - // - struct match_extra - { - }; - virtual bool match (action, target&, const string& hint, match_extra&) const = 0; @@ -144,7 +144,7 @@ namespace build2 // // Note: not exported. // - class adhoc_rule: public simple_rule + class adhoc_rule: public rule { public: location_value loc; // Buildfile location of the recipe. @@ -174,12 +174,11 @@ namespace build2 // interface. // virtual bool - match (action, target&, const string&, optional fallback) const; + match (action, target&, const string&, match_extra&, + optional fallback) const; virtual bool - match (action, target&, const string&) const override; - - using simple_rule::match; // To make Clang happy. + match (action, target&, const string&, match_extra&) const override; // Dump support. // diff --git a/libbuild2/test/operation.cxx b/libbuild2/test/operation.cxx index d06bd7c..e9635cf 100644 --- a/libbuild2/test/operation.cxx +++ b/libbuild2/test/operation.cxx @@ -34,6 +34,8 @@ namespace build2 execution_mode::first, 1 /* concurrency */, &test_pre, + nullptr, + nullptr, nullptr }; @@ -50,7 +52,9 @@ namespace build2 op_update.mode, op_update.concurrency, op_update.pre, - op_update.post + op_update.post, + op_update.adhoc_match, + op_update.adhoc_apply }; } } -- cgit v1.1