1// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "tools/gn/action_target_generator.h" 6 7#include "tools/gn/build_settings.h" 8#include "tools/gn/err.h" 9#include "tools/gn/filesystem_utils.h" 10#include "tools/gn/parse_tree.h" 11#include "tools/gn/scope.h" 12#include "tools/gn/value.h" 13#include "tools/gn/value_extractors.h" 14#include "tools/gn/variables.h" 15 16ActionTargetGenerator::ActionTargetGenerator( 17 Target* target, 18 Scope* scope, 19 const FunctionCallNode* function_call, 20 Target::OutputType type, 21 Err* err) 22 : TargetGenerator(target, scope, function_call, err), 23 output_type_(type) { 24} 25 26ActionTargetGenerator::~ActionTargetGenerator() { 27} 28 29void ActionTargetGenerator::DoRun() { 30 target_->set_output_type(output_type_); 31 32 if (!FillSources()) 33 return; 34 if (output_type_ == Target::ACTION_FOREACH && target_->sources().empty()) { 35 // Foreach rules must always have some sources to have an effect. 36 *err_ = Err(function_call_, "action_foreach target has no sources.", 37 "If you don't specify any sources, there is nothing to run your\n" 38 "script over."); 39 return; 40 } 41 42 if (!FillInputs()) 43 return; 44 45 if (!FillScript()) 46 return; 47 48 if (!FillScriptArgs()) 49 return; 50 51 if (!FillOutputs(output_type_ == Target::ACTION_FOREACH)) 52 return; 53 54 if (!FillDepfile()) 55 return; 56 57 if (!CheckOutputs()) 58 return; 59 60 // Action outputs don't depend on the current toolchain so we can skip adding 61 // that dependency. 62} 63 64bool ActionTargetGenerator::FillScript() { 65 // If this gets called, the target type requires a script, so error out 66 // if it doesn't have one. 67 const Value* value = scope_->GetValue(variables::kScript, true); 68 if (!value) { 69 *err_ = Err(function_call_, "This target type requires a \"script\"."); 70 return false; 71 } 72 if (!value->VerifyTypeIs(Value::STRING, err_)) 73 return false; 74 75 SourceFile script_file = 76 scope_->GetSourceDir().ResolveRelativeFile(value->string_value()); 77 if (script_file.value().empty()) { 78 *err_ = Err(*value, "script name is empty"); 79 return false; 80 } 81 target_->action_values().set_script(script_file); 82 return true; 83} 84 85bool ActionTargetGenerator::FillScriptArgs() { 86 const Value* value = scope_->GetValue(variables::kArgs, true); 87 if (!value) 88 return true; 89 return target_->action_values().args().Parse(*value, err_); 90} 91 92bool ActionTargetGenerator::FillDepfile() { 93 const Value* value = scope_->GetValue(variables::kDepfile, true); 94 if (!value) 95 return true; 96 97 SubstitutionPattern depfile; 98 if (!depfile.Parse(*value, err_)) 99 return false; 100 if (!EnsureSubstitutionIsInOutputDir(depfile, *value)) 101 return false; 102 103 target_->action_values().set_depfile(depfile); 104 return true; 105} 106 107bool ActionTargetGenerator::CheckOutputs() { 108 const SubstitutionList& outputs = target_->action_values().outputs(); 109 if (outputs.list().empty()) { 110 *err_ = Err(function_call_, "Action has no outputs.", 111 "If you have no outputs, the build system can not tell when your\n" 112 "script needs to be run."); 113 return false; 114 } 115 116 if (output_type_ == Target::ACTION) { 117 if (!outputs.required_types().empty()) { 118 *err_ = Err(function_call_, "Action has patterns in the output.", 119 "An action target should have the outputs completely specified. If\n" 120 "you want to provide a mapping from source to output, use an\n" 121 "\"action_foreach\" target."); 122 return false; 123 } 124 } else if (output_type_ == Target::ACTION_FOREACH) { 125 // A foreach target should always have a pattern in the outputs. 126 if (outputs.required_types().empty()) { 127 *err_ = Err(function_call_, 128 "action_foreach should have a pattern in the output.", 129 "An action_foreach target should have a source expansion pattern in\n" 130 "it to map source file to unique output file name. Otherwise, the\n" 131 "build system can't determine when your script needs to be run."); 132 return false; 133 } 134 } 135 return true; 136} 137