aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2020-04-28 08:48:53 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2020-05-27 08:35:29 +0200
commit05ae6014aa01a8347844cce89085bdcb591160f0 (patch)
tree75432dccbc84dc70a55e0672c8594fc9907227fb
parent3552356a87402727e663131994fa87f48b3cd4fb (diff)
Add ad hoc recipes plumbing
-rw-r--r--libbuild2/algorithm.cxx26
-rw-r--r--libbuild2/algorithm.ixx4
-rw-r--r--libbuild2/recipe.hxx8
-rw-r--r--libbuild2/rule.cxx24
-rw-r--r--libbuild2/rule.hxx18
-rw-r--r--libbuild2/target.hxx5
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_recipe> adhoc_recipes;
+
// Target operation state.
//
public: