diff options
-rw-r--r-- | doc/concepts/built-in-rules.md | 29 | ||||
-rw-r--r-- | src/buildtool/build_engine/target_map/built_in_rules.cpp | 47 |
2 files changed, 62 insertions, 14 deletions
diff --git a/doc/concepts/built-in-rules.md b/doc/concepts/built-in-rules.md index 5591c174..fc644a03 100644 --- a/doc/concepts/built-in-rules.md +++ b/doc/concepts/built-in-rules.md @@ -91,20 +91,23 @@ precedence to the artifacts over the runfiles; conflicts within artifacts or runfiles are resolved in a latest-wins fashion using the order of the targets in the evaluated `"deps"` argument. -The fields `"cmds"`, `"out_dirs"`, `"outs"`, and `"env"` are evaluated -fields where `"cmds"`, `"out_dirs"`, and `"outs"` have to evaluate to a -list of strings, and `"env"` has to evaluate to a map of strings. During -their evaluation, the functions `"outs"` and `"runfiles"` -can be used to access the logical paths of the artifacts +The fields `"cmds"`, `"sh -c"`, `"out_dirs"`, `"outs"`, and `"env"` +are evaluated fields where `"cmds"`, `"out_dirs"`, and `"outs"` +have to evaluate to a list of strings, `"sh -c"` has to evalute to +a list of strings or `null`, and `"env"` has to evaluate to a map +of strings. During their evaluation, the functions `"outs"` and +`"runfiles"` can be used to access the logical paths of the artifacts and runfiles, respectively, of a target specified in `"deps"`. Here, -`"env"` specifies the environment in which the action is carried out. -`"out_dirs"` and `"outs"` define the output directories and files, -respectively, the action has to produce. Since some artifacts are to be -produced, at least one of `"out_dirs"` or `"outs"` must be a non-empty -list of strings. It is an error if one or more paths are present in both -the `"out_dirs"` and `"outs"`. Finally, the strings in `"cmds"` are -extended by a newline character and joined, and command of the action is -interpreting this string by `sh`. +`"env"` specifies the environment in which the action is carried +out. `"out_dirs"` and `"outs"` define the output directories and +files, respectively, the action has to produce. Since some artifacts +are to be produced, at least one of `"out_dirs"` or `"outs"` must +be a non-empty list of strings. It is an error if one or more paths +are present in both the `"out_dirs"` and `"outs"`. Finally, the +strings in `"cmds"` are extended by a newline character and joined, +and command of the action is the result of evaluating the field +`"sh -c"` (or `["sh", "-c"]` if `"sh -c"` evaluates to `null` or +`[]`) extended by this string. The artifacts of this target are the outputs (as declared by `"out_dirs"` and `"outs"`) of this action. Runfiles and provider map are diff --git a/src/buildtool/build_engine/target_map/built_in_rules.cpp b/src/buildtool/build_engine/target_map/built_in_rules.cpp index 29eba7bf..7a057927 100644 --- a/src/buildtool/build_engine/target_map/built_in_rules.cpp +++ b/src/buildtool/build_engine/target_map/built_in_rules.cpp @@ -43,6 +43,7 @@ auto const kGenericRuleFields = "deps", "env", "execution properties", + "sh -c", "tainted", "timeout scaling", "type", @@ -1092,6 +1093,43 @@ void GenericRuleWithDeps( } } + auto sh_exp = desc->ReadOptionalExpression("sh -c", Expression::kEmptyList); + if (not sh_exp) { + return; + } + auto sh_val = sh_exp.Evaluate( + param_config, string_fields_fcts, [&logger](auto const& msg) { + (*logger)(fmt::format("While evaluating sh:\n{}", msg), true); + }); + if (not sh_val) { + return; + } + if (sh_val->IsNone()) { + sh_val = Expression::kEmptyList; + } + if (not sh_val->IsList()) { + (*logger)(fmt::format("sh has evaluate to list of strings or null, but " + "found {}", + sh_val->ToString()), + true); + return; + } + for (auto const& entry : sh_val->List()) { + if (not entry->IsString()) { + (*logger)(fmt::format("sh has evaluate to list of strings or null, " + "but found {}\nwith non-string entry {}", + sh_val->ToString(), + entry->ToString()), + true); + return; + } + } + static ExpressionPtr const kShC = + Expression::FromJson(R"( ["sh", "-c"] )"_json); + if (sh_val->List().empty()) { + sh_val = kShC; + } + auto scale_exp = desc->ReadOptionalExpression("timeout scaling", Expression::kOne); if (not scale_exp) { @@ -1159,11 +1197,18 @@ void GenericRuleWithDeps( inputs = ExpressionPtr{Expression::map_t{inputs, (*dep)->Artifacts()}}; } + std::vector<std::string> argv{}; + argv.reserve(sh_val->List().size() + 1); + for (auto const& entry : sh_val->List()) { + argv.emplace_back(entry->String()); + } + argv.emplace_back(cmd_ss.str()); + // Construct our single action, and its artifacts auto action = BuildMaps::Target::Utils::createAction( outs, out_dirs, - {"sh", "-c", cmd_ss.str()}, + argv, env_val, std::nullopt, false, |