|  | // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "tools/gn/action_target_generator.h" | 
|  |  | 
|  | #include "base/stl_util.h" | 
|  | #include "tools/gn/build_settings.h" | 
|  | #include "tools/gn/err.h" | 
|  | #include "tools/gn/filesystem_utils.h" | 
|  | #include "tools/gn/functions.h" | 
|  | #include "tools/gn/parse_tree.h" | 
|  | #include "tools/gn/scope.h" | 
|  | #include "tools/gn/value.h" | 
|  | #include "tools/gn/value_extractors.h" | 
|  | #include "tools/gn/variables.h" | 
|  |  | 
|  | ActionTargetGenerator::ActionTargetGenerator( | 
|  | Target* target, | 
|  | Scope* scope, | 
|  | const FunctionCallNode* function_call, | 
|  | Target::OutputType type, | 
|  | Err* err) | 
|  | : TargetGenerator(target, scope, function_call, err), output_type_(type) {} | 
|  |  | 
|  | ActionTargetGenerator::~ActionTargetGenerator() = default; | 
|  |  | 
|  | void ActionTargetGenerator::DoRun() { | 
|  | target_->set_output_type(output_type_); | 
|  |  | 
|  | if (!FillSources()) | 
|  | return; | 
|  | if (output_type_ == Target::ACTION_FOREACH && target_->sources().empty()) { | 
|  | // Foreach rules must always have some sources to have an effect. | 
|  | *err_ = | 
|  | Err(function_call_, "action_foreach target has no sources.", | 
|  | "If you don't specify any sources, there is nothing to run your\n" | 
|  | "script over."); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (!FillInputs()) | 
|  | return; | 
|  |  | 
|  | if (!FillScript()) | 
|  | return; | 
|  |  | 
|  | if (!FillScriptArgs()) | 
|  | return; | 
|  |  | 
|  | if (!FillResponseFileContents()) | 
|  | return; | 
|  |  | 
|  | if (!FillOutputs(output_type_ == Target::ACTION_FOREACH)) | 
|  | return; | 
|  |  | 
|  | if (!FillDepfile()) | 
|  | return; | 
|  |  | 
|  | if (!FillPool()) | 
|  | return; | 
|  |  | 
|  | if (!FillCheckIncludes()) | 
|  | return; | 
|  |  | 
|  | if (!CheckOutputs()) | 
|  | return; | 
|  |  | 
|  | // Action outputs don't depend on the current toolchain so we can skip adding | 
|  | // that dependency. | 
|  |  | 
|  | // response_file_contents and {{response_file_name}} in the args must go | 
|  | // together. | 
|  | const auto& required_args_substitutions = | 
|  | target_->action_values().args().required_types(); | 
|  | bool has_rsp_file_name = base::ContainsValue(required_args_substitutions, | 
|  | SUBSTITUTION_RSP_FILE_NAME); | 
|  | if (target_->action_values().uses_rsp_file() && !has_rsp_file_name) { | 
|  | *err_ = Err( | 
|  | function_call_, "Missing {{response_file_name}} in args.", | 
|  | "This target defines response_file_contents but doesn't use\n" | 
|  | "{{response_file_name}} in the args, which means the response file\n" | 
|  | "will be unused."); | 
|  | return; | 
|  | } | 
|  | if (!target_->action_values().uses_rsp_file() && has_rsp_file_name) { | 
|  | *err_ = Err( | 
|  | function_call_, "Missing response_file_contents definition.", | 
|  | "This target uses {{response_file_name}} in the args, but does not\n" | 
|  | "define response_file_contents which means the response file\n" | 
|  | "will be empty."); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool ActionTargetGenerator::FillScript() { | 
|  | // If this gets called, the target type requires a script, so error out | 
|  | // if it doesn't have one. | 
|  | const Value* value = scope_->GetValue(variables::kScript, true); | 
|  | if (!value) { | 
|  | *err_ = Err(function_call_, "This target type requires a \"script\"."); | 
|  | return false; | 
|  | } | 
|  | if (!value->VerifyTypeIs(Value::STRING, err_)) | 
|  | return false; | 
|  |  | 
|  | SourceFile script_file = scope_->GetSourceDir().ResolveRelativeFile( | 
|  | *value, err_, scope_->settings()->build_settings()->root_path_utf8()); | 
|  | if (err_->has_error()) | 
|  | return false; | 
|  | target_->action_values().set_script(script_file); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ActionTargetGenerator::FillScriptArgs() { | 
|  | const Value* value = scope_->GetValue(variables::kArgs, true); | 
|  | if (!value) | 
|  | return true;  // Nothing to do. | 
|  |  | 
|  | if (!target_->action_values().args().Parse(*value, err_)) | 
|  | return false; | 
|  | if (!EnsureValidSubstitutions( | 
|  | target_->action_values().args().required_types(), | 
|  | &IsValidScriptArgsSubstitution, value->origin(), err_)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ActionTargetGenerator::FillResponseFileContents() { | 
|  | const Value* value = scope_->GetValue(variables::kResponseFileContents, true); | 
|  | if (!value) | 
|  | return true;  // Nothing to do. | 
|  |  | 
|  | if (!target_->action_values().rsp_file_contents().Parse(*value, err_)) | 
|  | return false; | 
|  | if (!EnsureValidSubstitutions( | 
|  | target_->action_values().rsp_file_contents().required_types(), | 
|  | &IsValidSourceSubstitution, value->origin(), err_)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ActionTargetGenerator::FillDepfile() { | 
|  | const Value* value = scope_->GetValue(variables::kDepfile, true); | 
|  | if (!value) | 
|  | return true; | 
|  |  | 
|  | SubstitutionPattern depfile; | 
|  | if (!depfile.Parse(*value, err_)) | 
|  | return false; | 
|  | if (!EnsureSubstitutionIsInOutputDir(depfile, *value)) | 
|  | return false; | 
|  |  | 
|  | target_->action_values().set_depfile(depfile); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ActionTargetGenerator::FillPool() { | 
|  | const Value* value = scope_->GetValue(variables::kPool, true); | 
|  | if (!value) | 
|  | return true; | 
|  |  | 
|  | Label label = Label::Resolve(scope_->GetSourceDir(), | 
|  | ToolchainLabelForScope(scope_), *value, err_); | 
|  | if (err_->has_error()) | 
|  | return false; | 
|  |  | 
|  | LabelPtrPair<Pool> pair(label); | 
|  | pair.origin = target_->defined_from(); | 
|  |  | 
|  | target_->action_values().set_pool(std::move(pair)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ActionTargetGenerator::CheckOutputs() { | 
|  | const SubstitutionList& outputs = target_->action_values().outputs(); | 
|  | if (outputs.list().empty()) { | 
|  | *err_ = | 
|  | Err(function_call_, "Action has no outputs.", | 
|  | "If you have no outputs, the build system can not tell when your\n" | 
|  | "script needs to be run."); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (output_type_ == Target::ACTION) { | 
|  | if (!outputs.required_types().empty()) { | 
|  | *err_ = Err( | 
|  | function_call_, "Action has patterns in the output.", | 
|  | "An action target should have the outputs completely specified. If\n" | 
|  | "you want to provide a mapping from source to output, use an\n" | 
|  | "\"action_foreach\" target."); | 
|  | return false; | 
|  | } | 
|  | } else if (output_type_ == Target::ACTION_FOREACH) { | 
|  | // A foreach target should always have a pattern in the outputs. | 
|  | if (outputs.required_types().empty()) { | 
|  | *err_ = Err( | 
|  | function_call_, "action_foreach should have a pattern in the output.", | 
|  | "An action_foreach target should have a source expansion pattern in\n" | 
|  | "it to map source file to unique output file name. Otherwise, the\n" | 
|  | "build system can't determine when your script needs to be run."); | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ActionTargetGenerator::FillInputs() { | 
|  | const Value* value = scope_->GetValue(variables::kInputs, true); | 
|  | if (!value) | 
|  | return true; | 
|  |  | 
|  | Target::FileList dest_inputs; | 
|  | if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value, | 
|  | scope_->GetSourceDir(), &dest_inputs, err_)) | 
|  | return false; | 
|  | target_->config_values().inputs().swap(dest_inputs); | 
|  | return true; | 
|  | } |