aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2020-10-20 15:16:28 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2020-10-20 15:16:28 +0200
commit51666badaa58d1cc70a05b362dbf9fbef64a7296 (patch)
tree2919f013c9c1c12c7d31ee0b60eb0fbcb4130558
parentecc0f934eff0443490202b614a73097e75b1e3db (diff)
Add operation callback for adhoc rule match and apply
-rw-r--r--libbuild2/adhoc-rule-buildscript.cxx5
-rw-r--r--libbuild2/adhoc-rule-buildscript.hxx5
-rw-r--r--libbuild2/adhoc-rule-cxx.cxx10
-rw-r--r--libbuild2/adhoc-rule-cxx.hxx4
-rw-r--r--libbuild2/algorithm.cxx44
-rw-r--r--libbuild2/forward.hxx2
-rw-r--r--libbuild2/install/operation.cxx8
-rw-r--r--libbuild2/operation.cxx6
-rw-r--r--libbuild2/operation.hxx15
-rw-r--r--libbuild2/recipe.hxx2
-rw-r--r--libbuild2/rule.cxx7
-rw-r--r--libbuild2/rule.hxx25
-rw-r--r--libbuild2/test/operation.cxx6
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<action> fb) const
+ match (action a, target& t, const string&, match_extra&,
+ optional<action> 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<action>) const override;
+ match (action, target&, const string&, match_extra&,
+ optional<action>) 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<action> 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<const string, reference_wrapper<const rule>>& r)
+ const pair<const string, reference_wrapper<const rule>>& 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<const adhoc_rule*> (&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
// <libbuild2/rule.hxx>
//
+ struct match_extra;
class rule;
+ class adhoc_rule;
// <libbuild2/context.hxx>
//
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 <libbuild2/utility.hxx>
#include <libbuild2/action.hxx>
+#include <libbuild2/recipe.hxx>
#include <libbuild2/target-state.hxx>
#include <libbuild2/export.hxx>
@@ -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<action>);
+
+ 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<action, 1> 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<action> fallback) const
+ match (action a, target& t, const string& h, match_extra& me,
+ optional<action> 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<action> fallback) const;
+ match (action, target&, const string&, match_extra&,
+ optional<action> 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
};
}
}