diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2021-09-20 15:59:39 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2021-09-20 15:59:39 +0200 |
commit | b7cb7f5510de019527f2a7b9e3f81dbb9813b5d9 (patch) | |
tree | b204239436d477224a8664c82d8cf08a9629a504 | |
parent | ab978916ef5d3a8f876953697c6eb9cdeedbc998 (diff) |
Add support for disabling clean through target-prerequisite relationship
Our current semantics is to clean any prerequisites that are in the same
project (root scope) as the target and it may seem more natural to rather only
clean prerequisites that are in the same base scope. While it's often true for
simple projects, in more complex cases it's not unusual to have common
intermediate build results (object files, utility libraries, etc) reside in
the parent and/or sibling directories. With such arrangements, cleaning only
in base (even from the project root) may leave such intermediate build results
laying around (since there is no reason to list them as prerequisites of any
directory aliases). So we clean in the root scope by default but now any
target-prerequisite relationship can be marked not to trigger a clean with the
clean=false prerequisite-specific value.
-rw-r--r-- | libbuild2/adhoc-rule-regex-pattern.cxx | 3 | ||||
-rw-r--r-- | libbuild2/algorithm.hxx | 16 | ||||
-rw-r--r-- | libbuild2/context.hxx | 12 | ||||
-rw-r--r-- | libbuild2/operation.hxx | 4 | ||||
-rw-r--r-- | libbuild2/target.cxx | 33 | ||||
-rw-r--r-- | libbuild2/target.hxx | 8 | ||||
-rw-r--r-- | libbuild2/target.ixx | 20 |
7 files changed, 59 insertions, 37 deletions
diff --git a/libbuild2/adhoc-rule-regex-pattern.cxx b/libbuild2/adhoc-rule-regex-pattern.cxx index c621b67..9550527 100644 --- a/libbuild2/adhoc-rule-regex-pattern.cxx +++ b/libbuild2/adhoc-rule-regex-pattern.cxx @@ -405,7 +405,8 @@ namespace build2 continue; // @@ TODO: it could be handy to mark a prerequisite (e.g., a tool) - // ad hoc so that it doesn't interfere with the $< list. + // ad hoc so that it doesn't interfere with the $< list. Also + // clean=false. // pts.push_back (prerequisite_target (&pt, false /* adhoc */)); } diff --git a/libbuild2/algorithm.hxx b/libbuild2/algorithm.hxx index 984b786..73705d8 100644 --- a/libbuild2/algorithm.hxx +++ b/libbuild2/algorithm.hxx @@ -375,6 +375,18 @@ namespace build2 // the target is a member of a group, then first do this to the group's // prerequisites. // + // Regarding clean, it may seem more natural to only clean prerequisites + // that are in the same base rather than root scope. While it's often true + // for simple projects, in more complex cases it's not unusual to have + // common intermediate build results (object files, utility libraries, etc) + // reside in the parent and/or sibling directories. With such arrangements, + // cleaning only in base (even from the project root) may leave such + // intermediate build results laying around (since there is no reason to + // list them as prerequisites of any directory aliases). So we clean in the + // root scope by default but any target-prerequisite relationship can be + // marked not to trigger a clean with the clean=false prerequisite-specific + // value (see the include variable for details). + // using match_search = function< prerequisite_target (action, const target&, @@ -386,8 +398,8 @@ namespace build2 // As above but go into group members. // - // Note that if we cleaning, this function doesn't go into group members, as - // an optimization (the group should clean everything up). + // Note that if we are cleaning, this function doesn't go into group + // members, as an optimization (the group should clean everything up). // using match_search_member = function< prerequisite_target (action, diff --git a/libbuild2/context.hxx b/libbuild2/context.hxx index c93c1c9..7ac4af4 100644 --- a/libbuild2/context.hxx +++ b/libbuild2/context.hxx @@ -411,6 +411,9 @@ namespace build2 // const variable* var_extension; + // Note that this variable can also be specified as prerequisite-specific + // (see the `include` variable for details). + // // [bool] target visibility // const variable* var_clean; @@ -450,6 +453,15 @@ namespace build2 // A rule with the "pass-through" semantics should treat the adhoc value // the same as true. // + // Sometimes it may be desirable to apply exclusions only to specific + // operations. The initial idea was to extend this value to allow + // specifying the operation (e.g., clean@false). However, later we + // realized that we could reuse the "operation variables" (clean, install, + // test) with a more natural-looking result. Note that currently we only + // recognize the built-in clean variable (for other variables we will need + // some kind of registration in an operation-to-variable map, probably in + // root scope). + // // To query this value in rule implementations use the include() helpers // from <libbuild2/prerequisites.hxx>. // diff --git a/libbuild2/operation.hxx b/libbuild2/operation.hxx index de3ae7c..e115ac0 100644 --- a/libbuild2/operation.hxx +++ b/libbuild2/operation.hxx @@ -124,8 +124,8 @@ namespace build2 void (*operation_post) (const values&, operation_id); void (*meta_operation_post) (const values&); - // Optional prerequisite inclusion/exclusion override callback. See - // include() for details. + // Optional prerequisite exclusion override callback. See include() for + // details. Note that it's not called for include_type::normal; // include_type (*include) (action, const target&, diff --git a/libbuild2/target.cxx b/libbuild2/target.cxx index 7db5c66..bc5dbba 100644 --- a/libbuild2/target.cxx +++ b/libbuild2/target.cxx @@ -544,25 +544,38 @@ namespace build2 include_type include_impl (action a, const target& t, - const string& v, const prerequisite& p, const target* m) { context& ctx (t.ctx); - include_type r (false); + include_type r (include_type::normal); - if (v == "false") r = include_type::excluded; - else if (v == "adhoc") r = include_type::adhoc; - else if (v == "true") r = include_type::normal; - else - fail << "invalid " << ctx.var_include->name << " variable value " - << "'" << v << "' specified for prerequisite " << p; + // If var_clean is defined, then it takes precedence over include for + // the clean operation. + // + lookup l; + if (a.operation () == clean_id && (l = p.vars[ctx.var_clean])) + { + r = cast<bool> (l) ? include_type::normal : include_type::excluded; + } + else if (const string* v = cast_null<string> (p.vars[ctx.var_include])) + { + if (*v == "false") r = include_type::excluded; + else if (*v == "adhoc") r = include_type::adhoc; + else if (*v == "true") r = include_type::normal; + else + fail << "invalid " << ctx.var_include->name << " variable value " + << "'" << *v << "' specified for prerequisite " << p; + } // Call the meta-operation override, if any (currently used by dist). // - if (auto f = ctx.current_mif->include) - r = f (a, t, prerequisite_member {p, m}, r); + if (r != include_type::normal) + { + if (auto f = ctx.current_mif->include) + r = f (a, t, prerequisite_member {p, m}, r); + } return r; } diff --git a/libbuild2/target.hxx b/libbuild2/target.hxx index 8193f35..a5940ab 100644 --- a/libbuild2/target.hxx +++ b/libbuild2/target.hxx @@ -874,15 +874,11 @@ namespace build2 uint8_t unmark (const target*&); - // Helper for dealing with the prerequisite inclusion/exclusion (the - // 'include' buildfile variable, see var_include in context.hxx). + // Helper for dealing with the prerequisite inclusion/exclusion (see + // var_include in context.hxx). // // Note that the include(prerequisite_member) overload is also provided. // - // @@ Maybe this filtering should be incorporated into *_prerequisites() and - // *_prerequisite_members() logic? Could make normal > adhoc > excluded and - // then pass the "threshold". - // include_type include (action, const target&, diff --git a/libbuild2/target.ixx b/libbuild2/target.ixx index 1c8dd8d..50750ca 100644 --- a/libbuild2/target.ixx +++ b/libbuild2/target.ixx @@ -287,27 +287,15 @@ namespace build2 // include() // LIBBUILD2_SYMEXPORT include_type - include_impl (action, - const target&, - const string&, - const prerequisite&, - const target*); + include_impl (action, const target&, const prerequisite&, const target*); inline include_type include (action a, const target& t, const prerequisite& p, const target* m) { - // Most of the time this variable will not be specified, so let's optimize - // for that. + // Most of the time no prerequisite-specific variables will be specified, + // so let's optimize for that. // - if (p.vars.empty ()) - return true; - - const string* v (cast_null<string> (p.vars[t.ctx.var_include])); - - if (v == nullptr) - return true; - - return include_impl (a, t, *v, p, m); + return p.vars.empty () ? include_type (true) : include_impl (a, t, p, m); } // group_prerequisites |