From 4b15244f65eb246d4e5d98ebfc1aa3137dc7275e Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 13 Jul 2020 09:30:52 +0200 Subject: Add ability to extend rule interface in source-compatible manner --- build2/cli/rule.hxx | 2 +- libbuild2/adhoc-rule-cxx.hxx | 2 +- libbuild2/algorithm.cxx | 9 ++++++--- libbuild2/bin/rule.hxx | 4 ++-- libbuild2/cc/compile-rule.hxx | 2 +- libbuild2/cc/link-rule.hxx | 2 +- libbuild2/dist/rule.hxx | 2 +- libbuild2/in/rule.hxx | 2 +- libbuild2/install/rule.hxx | 6 +++--- libbuild2/rule.cxx | 14 ++++++++++++++ libbuild2/rule.hxx | 44 +++++++++++++++++++++++++++++++++++-------- libbuild2/test/rule.hxx | 2 +- 12 files changed, 68 insertions(+), 23 deletions(-) diff --git a/build2/cli/rule.hxx b/build2/cli/rule.hxx index 64f1614..b3ecc2c 100644 --- a/build2/cli/rule.hxx +++ b/build2/cli/rule.hxx @@ -23,7 +23,7 @@ namespace build2 // @@ Redo as two separate rules? // - class compile_rule: public rule, virtual data + class compile_rule: public simple_rule, virtual data { public: compile_rule (data&& d): data (move (d)) {} diff --git a/libbuild2/adhoc-rule-cxx.hxx b/libbuild2/adhoc-rule-cxx.hxx index 9b94783..fbcdd4f 100644 --- a/libbuild2/adhoc-rule-cxx.hxx +++ b/libbuild2/adhoc-rule-cxx.hxx @@ -18,7 +18,7 @@ namespace build2 // // Note: exported but should not be used directly (i.e., registered). // - class LIBBUILD2_SYMEXPORT cxx_rule: public rule + class LIBBUILD2_SYMEXPORT cxx_rule: public simple_rule { // For now this class is provided purely as an alias for rule in case the // implementation (which is also called rule) needs to refer to something diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx index de68be2..e1f30e0 100644 --- a/libbuild2/algorithm.cxx +++ b/libbuild2/algorithm.cxx @@ -450,7 +450,8 @@ namespace build2 << diag_do (a, t); }); - if (!ru.match (a, t, hint)) + rule::match_extra me; + if (!ru.match (a, t, hint, me)) continue; } @@ -479,7 +480,8 @@ namespace build2 // // @@ Can't we temporarily swap things out in target? // - if (!ru1.match (a, t, hint)) + rule::match_extra me1; + if (!ru1.match (a, t, hint, me1)) continue; } @@ -527,7 +529,8 @@ namespace build2 << diag_do (a, t); }); - return r.second.get ().apply (a, t); + rule::match_extra me; + return r.second.get ().apply (a, t, me); } // If step is true then perform only one step of the match/apply sequence. diff --git a/libbuild2/bin/rule.hxx b/libbuild2/bin/rule.hxx index 074b46d..51693a7 100644 --- a/libbuild2/bin/rule.hxx +++ b/libbuild2/bin/rule.hxx @@ -18,7 +18,7 @@ namespace build2 // "Fail rule" for obj{}, [h]bmi{}, and libu{} that issues diagnostics if // someone tries to build any of these groups directly. // - class fail_rule: public rule + class fail_rule: public simple_rule { public: fail_rule () {} @@ -32,7 +32,7 @@ namespace build2 // Pass-through to group members rule, similar to alias. // - class LIBBUILD2_BIN_SYMEXPORT lib_rule: public rule + class LIBBUILD2_BIN_SYMEXPORT lib_rule: public simple_rule { public: lib_rule () {} diff --git a/libbuild2/cc/compile-rule.hxx b/libbuild2/cc/compile-rule.hxx index 051b2e3..d6cb002 100644 --- a/libbuild2/cc/compile-rule.hxx +++ b/libbuild2/cc/compile-rule.hxx @@ -36,7 +36,7 @@ namespace build2 size_t copied; // First copied-over bmi*{}, 0 if none. }; - class LIBBUILD2_CC_SYMEXPORT compile_rule: public rule, virtual common + class LIBBUILD2_CC_SYMEXPORT compile_rule: public simple_rule, virtual common { public: compile_rule (data&&); diff --git a/libbuild2/cc/link-rule.hxx b/libbuild2/cc/link-rule.hxx index ce514b5..7a357a6 100644 --- a/libbuild2/cc/link-rule.hxx +++ b/libbuild2/cc/link-rule.hxx @@ -20,7 +20,7 @@ namespace build2 { namespace cc { - class LIBBUILD2_CC_SYMEXPORT link_rule: public rule, virtual common + class LIBBUILD2_CC_SYMEXPORT link_rule: public simple_rule, virtual common { public: link_rule (data&&); diff --git a/libbuild2/dist/rule.hxx b/libbuild2/dist/rule.hxx index 28caa68..e63016d 100644 --- a/libbuild2/dist/rule.hxx +++ b/libbuild2/dist/rule.hxx @@ -23,7 +23,7 @@ namespace build2 // bin::lib_rule for an example). Note that in the latter case the rule // should "see" all its members for the dist case. // - class rule: public build2::rule + class rule: public simple_rule { public: rule () {} diff --git a/libbuild2/in/rule.hxx b/libbuild2/in/rule.hxx index 653818f..cf67060 100644 --- a/libbuild2/in/rule.hxx +++ b/libbuild2/in/rule.hxx @@ -23,7 +23,7 @@ namespace build2 // Note also that currently this rule ignores the dry-run mode (see // perform_update() for the rationale). // - class LIBBUILD2_IN_SYMEXPORT rule: public build2::rule + class LIBBUILD2_IN_SYMEXPORT rule: public simple_rule { public: // The rule id is used to form the rule name/version entry in depdb. The diff --git a/libbuild2/install/rule.hxx b/libbuild2/install/rule.hxx index 916fc6d..73f2486 100644 --- a/libbuild2/install/rule.hxx +++ b/libbuild2/install/rule.hxx @@ -18,7 +18,7 @@ namespace build2 { namespace install { - class LIBBUILD2_SYMEXPORT alias_rule: public rule + class LIBBUILD2_SYMEXPORT alias_rule: public simple_rule { public: virtual bool @@ -46,7 +46,7 @@ namespace build2 static const alias_rule instance; }; - class fsdir_rule: public rule + class fsdir_rule: public simple_rule { public: virtual bool @@ -95,7 +95,7 @@ namespace build2 struct install_dir; - class LIBBUILD2_SYMEXPORT file_rule: public rule + class LIBBUILD2_SYMEXPORT file_rule: public simple_rule { public: virtual bool diff --git a/libbuild2/rule.cxx b/libbuild2/rule.cxx index 9028096..7ccee4e 100644 --- a/libbuild2/rule.cxx +++ b/libbuild2/rule.cxx @@ -22,6 +22,20 @@ namespace build2 { } + // simple_rule + // + bool simple_rule:: + match (action a, target& t, const string& h, match_extra&) const + { + return match (a, t, h); + } + + recipe simple_rule:: + apply (action a, target& t, match_extra&) const + { + return apply (a, t); + } + // file_rule // // Note that this rule is special. It is the last, fallback rule. If diff --git a/libbuild2/rule.hxx b/libbuild2/rule.hxx index 8390ea7..298ed6b 100644 --- a/libbuild2/rule.hxx +++ b/libbuild2/rule.hxx @@ -16,20 +16,30 @@ namespace build2 { + // Rule interface (see also simple_rule below for a simplified version). + // // Once a rule is registered (for a scope), it is treated as immutable. If // you need to modify some state (e.g., counters or some such), then make - // sure it is MT-safe. + // sure things are MT-safe. // // Note: match() is only called once but may not be followed by apply(). // 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) const = 0; + match (action, target&, const string& hint, match_extra&) const = 0; virtual recipe - apply (action, target&) const = 0; + apply (action, target&, match_extra&) const = 0; rule () = default; @@ -40,10 +50,28 @@ namespace build2 rule& operator= (const rule&) = delete; }; + // Simplified interface for rules that don't care about the extras. + // + class LIBBUILD2_SYMEXPORT simple_rule: public rule + { + public: + virtual bool + match (action, target&, const string& hint) const = 0; + + virtual recipe + apply (action, target&) const = 0; + + virtual bool + match (action, target&, const string&, match_extra&) const override; + + virtual recipe + apply (action, target&, match_extra&) const override; + }; + // Fallback rule that only matches if the file exists. It will also match // an mtime_target provided it has a set timestamp. // - class LIBBUILD2_SYMEXPORT file_rule: public rule + class LIBBUILD2_SYMEXPORT file_rule: public simple_rule { public: virtual bool @@ -56,7 +84,7 @@ namespace build2 static const file_rule instance; }; - class LIBBUILD2_SYMEXPORT alias_rule: public rule + class LIBBUILD2_SYMEXPORT alias_rule: public simple_rule { public: virtual bool @@ -72,7 +100,7 @@ namespace build2 // Note that this rule ignores the dry_run flag; see mkdir() in filesystem // for the rationale. // - class LIBBUILD2_SYMEXPORT fsdir_rule: public rule + class LIBBUILD2_SYMEXPORT fsdir_rule: public simple_rule { public: virtual bool @@ -99,7 +127,7 @@ namespace build2 // Fallback rule that always matches and does nothing. // - class LIBBUILD2_SYMEXPORT noop_rule: public rule + class LIBBUILD2_SYMEXPORT noop_rule: public simple_rule { public: virtual bool @@ -116,7 +144,7 @@ namespace build2 // // Note: not exported. // - class adhoc_rule: public rule + class adhoc_rule: public simple_rule { public: location_value loc; // Buildfile location of the recipe. diff --git a/libbuild2/test/rule.hxx b/libbuild2/test/rule.hxx index bc39f50..e96b68b 100644 --- a/libbuild2/test/rule.hxx +++ b/libbuild2/test/rule.hxx @@ -16,7 +16,7 @@ namespace build2 { namespace test { - class rule: public build2::rule, protected virtual common + class rule: public simple_rule, protected virtual common { public: virtual bool -- cgit v1.1