• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 namespace {
17 
18 // Returns true if the list of files looks like it might have a {{ }} pattern
19 // in it. Used for error checking.
FileListHasPattern(const Target::FileList & files)20 bool FileListHasPattern(const Target::FileList& files) {
21   for (size_t i = 0; i < files.size(); i++) {
22     if (files[i].value().find("{{") != std::string::npos &&
23         files[i].value().find("}}") != std::string::npos)
24       return true;
25   }
26   return false;
27 }
28 
29 }  // namespace
30 
ActionTargetGenerator(Target * target,Scope * scope,const FunctionCallNode * function_call,Target::OutputType type,Err * err)31 ActionTargetGenerator::ActionTargetGenerator(
32     Target* target,
33     Scope* scope,
34     const FunctionCallNode* function_call,
35     Target::OutputType type,
36     Err* err)
37     : TargetGenerator(target, scope, function_call, err),
38       output_type_(type) {
39 }
40 
~ActionTargetGenerator()41 ActionTargetGenerator::~ActionTargetGenerator() {
42 }
43 
DoRun()44 void ActionTargetGenerator::DoRun() {
45   target_->set_output_type(output_type_);
46 
47   FillSources();
48   if (err_->has_error())
49     return;
50   if (output_type_ == Target::ACTION_FOREACH && target_->sources().empty()) {
51     // Foreach rules must always have some sources to have an effect.
52     *err_ = Err(function_call_, "action_foreach target has no sources.",
53         "If you don't specify any sources, there is nothing to run your\n"
54         "script over.");
55     return;
56   }
57 
58   FillInputs();
59   if (err_->has_error())
60     return;
61 
62   FillScript();
63   if (err_->has_error())
64     return;
65 
66   FillScriptArgs();
67   if (err_->has_error())
68     return;
69 
70   FillOutputs();
71   if (err_->has_error())
72     return;
73 
74   FillDepfile();
75   if (err_->has_error())
76     return;
77 
78   CheckOutputs();
79   if (err_->has_error())
80     return;
81 
82   // Action outputs don't depend on the current toolchain so we can skip adding
83   // that dependency.
84 }
85 
FillScript()86 void ActionTargetGenerator::FillScript() {
87   // If this gets called, the target type requires a script, so error out
88   // if it doesn't have one.
89   const Value* value = scope_->GetValue(variables::kScript, true);
90   if (!value) {
91     *err_ = Err(function_call_, "This target type requires a \"script\".");
92     return;
93   }
94   if (!value->VerifyTypeIs(Value::STRING, err_))
95     return;
96 
97   SourceFile script_file =
98       scope_->GetSourceDir().ResolveRelativeFile(value->string_value());
99   if (script_file.value().empty()) {
100     *err_ = Err(*value, "script name is empty");
101     return;
102   }
103   target_->action_values().set_script(script_file);
104 }
105 
FillScriptArgs()106 void ActionTargetGenerator::FillScriptArgs() {
107   const Value* value = scope_->GetValue(variables::kArgs, true);
108   if (!value)
109     return;
110 
111   std::vector<std::string> args;
112   if (!ExtractListOfStringValues(*value, &args, err_))
113     return;
114   target_->action_values().swap_in_args(&args);
115 }
116 
FillDepfile()117 void ActionTargetGenerator::FillDepfile() {
118   const Value* value = scope_->GetValue(variables::kDepfile, true);
119   if (!value)
120     return;
121   target_->action_values().set_depfile(
122       scope_->settings()->build_settings()->build_dir().ResolveRelativeFile(
123           value->string_value()));
124 }
125 
CheckOutputs()126 void ActionTargetGenerator::CheckOutputs() {
127   const Target::FileList& outputs = target_->action_values().outputs();
128   if (outputs.empty()) {
129     *err_ = Err(function_call_, "Action has no outputs.",
130         "If you have no outputs, the build system can not tell when your\n"
131         "script needs to be run.");
132     return;
133   }
134 
135   if (output_type_ == Target::ACTION) {
136     // Make sure the outputs for an action have no patterns in them.
137     if (FileListHasPattern(outputs)) {
138       *err_ = Err(function_call_, "Action has patterns in the output.",
139           "An action target should have the outputs completely specified. If\n"
140           "you want to provide a mapping from source to output, use an\n"
141           "\"action_foreach\" target.");
142       return;
143     }
144   } else if (output_type_ == Target::ACTION_FOREACH) {
145     // A foreach target should always have a pattern in the outputs.
146     if (!FileListHasPattern(outputs)) {
147       *err_ = Err(function_call_,
148           "action_foreach should have a pattern in the output.",
149           "An action_foreach target should have a source expansion pattern in\n"
150           "it to map source file to unique output file name. Otherwise, the\n"
151           "build system can't determine when your script needs to be run.");
152       return;
153     }
154   }
155 }
156