diff options
-rw-r--r-- | build2/cli/rule.cxx | 3 | ||||
-rw-r--r-- | libbuild2/action.hxx | 14 | ||||
-rw-r--r-- | libbuild2/algorithm.cxx | 4 | ||||
-rw-r--r-- | libbuild2/rule.cxx | 82 |
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; |