aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/cli/rule.cxx3
-rw-r--r--libbuild2/action.hxx14
-rw-r--r--libbuild2/algorithm.cxx4
-rw-r--r--libbuild2/rule.cxx82
4 files changed, 89 insertions, 14 deletions
diff --git a/build2/cli/rule.cxx b/build2/cli/rule.cxx
index 3109689..99b6bee 100644
--- a/build2/cli/rule.cxx
+++ b/build2/cli/rule.cxx
@@ -222,7 +222,8 @@ namespace build2
// Update prerequisites and determine if any relevant ones render us
// out-of-date. Note that currently we treat all the prerequisites as
- // potentially affecting the result (think prologues/epilogues, etc).
+ // potentially affecting the result (think prologues/epilogues, CLI
+ // compiler target itself, etc).
//
timestamp mt (t.load_mtime (tp));
auto pr (execute_prerequisites<cli> (a, t, mt));
diff --git a/libbuild2/action.hxx b/libbuild2/action.hxx
index c1e4697..5898ba8 100644
--- a/libbuild2/action.hxx
+++ b/libbuild2/action.hxx
@@ -11,11 +11,11 @@
namespace build2
{
- // While we are using uint8_t for the meta/operation ids, we assume
- // that each is limited to 4 bits (max 128 entries) so that we can
- // store the combined action id in uint8_t as well. This makes our
- // life easier when it comes to defining switch labels for action
- // ids (no need to mess with endian-ness).
+ // While we are using uint8_t for the meta/operation ids, we assume that
+ // each is limited to 4 bits (max 15 entries @@ this is probably too low) so
+ // that we can store the combined action id in uint8_t as well. This makes
+ // our life easier when it comes to defining switch labels for action ids
+ // (no need to mess with endian-ness).
//
// Note that 0 is not a valid meta/operation/action id.
//
@@ -140,6 +140,8 @@ namespace build2
// Id constants for build-in and pre-defined meta/operations.
//
+ // Note: currently max 15 (see above).
+ //
const meta_operation_id noop_id = 1; // nomop?
const meta_operation_id perform_id = 2;
const meta_operation_id configure_id = 3;
@@ -152,6 +154,8 @@ namespace build2
// that no operation was explicitly specified by the user. If adding
// something here remember to update the man page.
//
+ // Note: currently max 15 (see above).
+ //
const operation_id default_id = 1; // Shall be first.
const operation_id update_id = 2; // Shall be second.
const operation_id clean_id = 3;
diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx
index 9b2162e..b4ff22a 100644
--- a/libbuild2/algorithm.cxx
+++ b/libbuild2/algorithm.cxx
@@ -341,6 +341,10 @@ namespace build2
// it can distinguish between a pre/post operation (Y-for-X) and the
// actual operation (X).
//
+ // If you are then wondering how would a rule for Y ever match in case of
+ // Y-for-X, the answer is via a rule that matches for X and then, in case
+ // of Y-for-X, matches an inner rule for just Y (see match_inner()).
+ //
meta_operation_id mo (a.meta_operation ());
operation_id o (a.inner () ? a.operation () : a.outer_operation ());
diff --git a/libbuild2/rule.cxx b/libbuild2/rule.cxx
index a57aaaa..bbb854c 100644
--- a/libbuild2/rule.cxx
+++ b/libbuild2/rule.cxx
@@ -308,23 +308,89 @@ namespace build2
// adhoc_rule
//
- bool adhoc_rule::
- match (action a, target& t, const string&) const
+ static inline const adhoc_recipe*
+ find_recipe (action a, target& t)
{
- // @@ 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 ();
+ return i != t.adhoc_recipes.end () ? &*i : nullptr;
+ }
+
+ bool adhoc_rule::
+ match (action a, target& t, const string&) const
+ {
+ // TODO:
+ //
+ // @@ If action is Y-for-X, how would we distinguish between X and
+ // Y-for-X? See match_rule() for the hairy details. We could start with
+ // supporting just the inner case. Or we could try to just match an
+ // inner rule by default? I think need a clear use-case to see what's
+ // the correct semantics.
+
+ if (find_recipe (a, t))
+ return true;
+
+ // If this is clean for a file target and we have a recipe for update,
+ // then we will supply the standard clean.
+ //
+ if (a == perform_clean_id &&
+ t.is_a<file> () &&
+ find_recipe (action (perform_id, update_id), t))
+ return true;
+
+ return false;
}
recipe adhoc_rule::
- apply (action, target&) const
+ apply (action a, target& t) const
{
- return empty_recipe;
+ // Derive file names for the target and its ad hoc group members, if any.
+ //
+ for (target* m (&t); m != nullptr; m = m->adhoc_member)
+ {
+ if (auto* p = m->is_a<path_target> ())
+ p->derive_path ();
+ }
+
+ // Inject dependency on the output directory.
+ //
+ // We do it always instead of only if one of the targets is path-based in
+ // case the recipe creates temporary files or some such.
+ //
+ inject_fsdir (a, t);
+
+ // Match prerequisites.
+ //
+ match_prerequisite_members (a, t);
+
+ // For update inject dependency on the tool target.
+ //
+ // @@ We could see that it's a target and do it but not sure if we should
+ // bother. We dropped this idea of implicit targets in tests. Maybe we
+ // should verify path assigned, like we do there? I think we will have
+ // to.
+ //
+ // if (a == perform_update_id)
+ // inject (a, t, tgt);
+
+ if (const adhoc_recipe* r = find_recipe (a, t))
+ {
+ // @@ Perhaps we should have different implementations for file-based
+ // targets (depdb, timestamp, etc) and non.
+ //
+ return [r] (action a, const target& t)
+ {
+ // @@ TODO
+ text << t << ' ' << a << ' ' << r;
+ return target_state::unchanged;
+ };
+ }
+
+ // Otherwise this should be the standard clean.
+ //
+ return &perform_clean_depdb;
}
const adhoc_rule adhoc_rule::instance;