OLD | NEW |
| (Empty) |
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/target_generator.h" | |
6 | |
7 #include "base/files/file_path.h" | |
8 #include "base/logging.h" | |
9 #include "tools/gn/build_settings.h" | |
10 #include "tools/gn/config.h" | |
11 #include "tools/gn/config_values_generator.h" | |
12 #include "tools/gn/err.h" | |
13 #include "tools/gn/filesystem_utils.h" | |
14 #include "tools/gn/functions.h" | |
15 #include "tools/gn/input_file.h" | |
16 #include "tools/gn/item_node.h" | |
17 #include "tools/gn/ninja_target_writer.h" | |
18 #include "tools/gn/parse_tree.h" | |
19 #include "tools/gn/scheduler.h" | |
20 #include "tools/gn/scope.h" | |
21 #include "tools/gn/target_manager.h" | |
22 #include "tools/gn/token.h" | |
23 #include "tools/gn/value.h" | |
24 #include "tools/gn/value_extractors.h" | |
25 | |
26 namespace { | |
27 | |
28 bool TypeHasConfigs(Target::OutputType type) { | |
29 return type == Target::EXECUTABLE || | |
30 type == Target::SHARED_LIBRARY || | |
31 type == Target::STATIC_LIBRARY || | |
32 type == Target::LOADABLE_MODULE; | |
33 } | |
34 | |
35 bool TypeHasConfigValues(Target::OutputType type) { | |
36 return type == Target::EXECUTABLE || | |
37 type == Target::SHARED_LIBRARY || | |
38 type == Target::STATIC_LIBRARY || | |
39 type == Target::LOADABLE_MODULE; | |
40 } | |
41 | |
42 bool TypeHasSources(Target::OutputType type) { | |
43 return type != Target::NONE; | |
44 } | |
45 | |
46 bool TypeHasData(Target::OutputType type) { | |
47 return type != Target::NONE; | |
48 } | |
49 | |
50 bool TypeHasDestDir(Target::OutputType type) { | |
51 return type == Target::COPY_FILES; | |
52 } | |
53 | |
54 bool TypeHasOutputs(Target::OutputType type) { | |
55 return type == Target::CUSTOM; | |
56 } | |
57 | |
58 } // namespace | |
59 | |
60 TargetGenerator::TargetGenerator(Target* target, | |
61 Scope* scope, | |
62 const Token& function_token, | |
63 const std::vector<Value>& args, | |
64 const std::string& output_type, | |
65 Err* err) | |
66 : target_(target), | |
67 scope_(scope), | |
68 function_token_(function_token), | |
69 args_(args), | |
70 output_type_(output_type), | |
71 err_(err), | |
72 input_directory_(function_token.location().file()->dir()) { | |
73 } | |
74 | |
75 TargetGenerator::~TargetGenerator() { | |
76 } | |
77 | |
78 void TargetGenerator::Run() { | |
79 // Output type. | |
80 Target::OutputType output_type = GetOutputType(); | |
81 target_->set_output_type(output_type); | |
82 if (err_->has_error()) | |
83 return; | |
84 | |
85 if (TypeHasConfigs(output_type)) { | |
86 FillConfigs(); | |
87 FillAllDependentConfigs(); | |
88 FillDirectDependentConfigs(); | |
89 } | |
90 if (TypeHasSources(output_type)) | |
91 FillSources(); | |
92 if (TypeHasData(output_type)) | |
93 FillData(); | |
94 if (output_type == Target::CUSTOM) { | |
95 FillScript(); | |
96 FillScriptArgs(); | |
97 } | |
98 if (TypeHasOutputs(output_type)) | |
99 FillOutputs(); | |
100 FillDependencies(); // All types have dependencies. | |
101 | |
102 if (TypeHasConfigValues(output_type)) { | |
103 ConfigValuesGenerator gen(&target_->config_values(), scope_, | |
104 function_token_, input_directory_, err_); | |
105 gen.Run(); | |
106 if (err_->has_error()) | |
107 return; | |
108 } | |
109 | |
110 if (TypeHasDestDir(output_type)) | |
111 FillDestDir(); | |
112 | |
113 // Set the toolchain as a dependency of the target. | |
114 // TODO(brettw) currently we lock separately for each config, dep, and | |
115 // toolchain we add which is bad! Do this in one lock. | |
116 { | |
117 ItemTree* tree = &GetBuildSettings()->item_tree(); | |
118 base::AutoLock lock(tree->lock()); | |
119 ItemNode* tc_node = | |
120 tree->GetExistingNodeLocked(ToolchainLabelForScope(scope_)); | |
121 tree->GetExistingNodeLocked(target_->label())->AddDependency(tc_node); | |
122 } | |
123 | |
124 target_->SetGenerated(&function_token_); | |
125 GetBuildSettings()->target_manager().TargetGenerationComplete( | |
126 target_->label()); | |
127 } | |
128 | |
129 // static | |
130 void TargetGenerator::GenerateTarget(Scope* scope, | |
131 const Token& function_token, | |
132 const std::vector<Value>& args, | |
133 const std::string& output_type, | |
134 Err* err) { | |
135 // Name is the argument to the function. | |
136 if (args.size() != 1u || args[0].type() != Value::STRING) { | |
137 *err = Err(function_token, | |
138 "Target generator requires one string argument.", | |
139 "Otherwise I'm not sure what to call this target."); | |
140 return; | |
141 } | |
142 | |
143 // The location of the target is the directory name with no slash at the end. | |
144 // FIXME(brettw) validate name. | |
145 const Label& toolchain_label = ToolchainLabelForScope(scope); | |
146 Label label(function_token.location().file()->dir(), | |
147 args[0].string_value(), | |
148 toolchain_label.dir(), toolchain_label.name()); | |
149 | |
150 if (g_scheduler->verbose_logging()) | |
151 g_scheduler->Log("Generating target", label.GetUserVisibleName(true)); | |
152 | |
153 Target* t = scope->settings()->build_settings()->target_manager().GetTarget( | |
154 label, function_token.range(), NULL, err); | |
155 if (err->has_error()) | |
156 return; | |
157 | |
158 TargetGenerator gen(t, scope, function_token, args, output_type, err); | |
159 gen.Run(); | |
160 } | |
161 | |
162 Target::OutputType TargetGenerator::GetOutputType() const { | |
163 if (output_type_ == functions::kGroup) | |
164 return Target::NONE; | |
165 if (output_type_ == functions::kExecutable) | |
166 return Target::EXECUTABLE; | |
167 if (output_type_ == functions::kSharedLibrary) | |
168 return Target::SHARED_LIBRARY; | |
169 if (output_type_ == functions::kStaticLibrary) | |
170 return Target::STATIC_LIBRARY; | |
171 // TODO(brettw) what does loadable module mean? | |
172 //if (output_type_ == ???) | |
173 // return Target::LOADABLE_MODULE; | |
174 if (output_type_ == functions::kCopy) | |
175 return Target::COPY_FILES; | |
176 if (output_type_ == functions::kCustom) | |
177 return Target::CUSTOM; | |
178 | |
179 *err_ = Err(function_token_, "Not a known output type", | |
180 "I am very confused."); | |
181 return Target::NONE; | |
182 } | |
183 | |
184 void TargetGenerator::FillGenericConfigs( | |
185 const char* var_name, | |
186 void (Target::*setter)(std::vector<const Config*>*)) { | |
187 const Value* value = scope_->GetValue(var_name, true); | |
188 if (!value) | |
189 return; | |
190 | |
191 std::vector<Label> labels; | |
192 if (!ExtractListOfLabels(*value, input_directory_, | |
193 ToolchainLabelForScope(scope_), &labels, err_)) | |
194 return; | |
195 | |
196 std::vector<const Config*> dest_configs; | |
197 dest_configs.resize(labels.size()); | |
198 for (size_t i = 0; i < labels.size(); i++) { | |
199 dest_configs[i] = Config::GetConfig( | |
200 scope_->settings(), | |
201 value->list_value()[i].origin()->GetRange(), | |
202 labels[i], target_, err_); | |
203 if (err_->has_error()) | |
204 return; | |
205 } | |
206 (target_->*setter)(&dest_configs); | |
207 } | |
208 | |
209 void TargetGenerator::FillConfigs() { | |
210 FillGenericConfigs("configs", &Target::swap_in_configs); | |
211 } | |
212 | |
213 void TargetGenerator::FillAllDependentConfigs() { | |
214 FillGenericConfigs("all_dependent_configs", | |
215 &Target::swap_in_all_dependent_configs); | |
216 } | |
217 | |
218 void TargetGenerator::FillDirectDependentConfigs() { | |
219 FillGenericConfigs("direct_dependent_configs", | |
220 &Target::swap_in_direct_dependent_configs); | |
221 } | |
222 | |
223 void TargetGenerator::FillSources() { | |
224 const Value* value = scope_->GetValue("sources", true); | |
225 if (!value) | |
226 return; | |
227 | |
228 Target::FileList dest_sources; | |
229 if (!ExtractListOfRelativeFiles(*value, input_directory_, &dest_sources, | |
230 err_)) | |
231 return; | |
232 target_->swap_in_sources(&dest_sources); | |
233 } | |
234 | |
235 void TargetGenerator::FillData() { | |
236 const Value* value = scope_->GetValue("data", true); | |
237 if (!value) | |
238 return; | |
239 | |
240 Target::FileList dest_data; | |
241 if (!ExtractListOfRelativeFiles(*value, input_directory_, &dest_data, | |
242 err_)) | |
243 return; | |
244 target_->swap_in_data(&dest_data); | |
245 } | |
246 | |
247 void TargetGenerator::FillDependencies() { | |
248 const Value* value = scope_->GetValue("deps", true); | |
249 if (!value) | |
250 return; | |
251 | |
252 std::vector<Label> labels; | |
253 if (!ExtractListOfLabels(*value, input_directory_, | |
254 ToolchainLabelForScope(scope_), &labels, err_)) | |
255 return; | |
256 | |
257 std::vector<const Target*> dest_deps; | |
258 dest_deps.resize(labels.size()); | |
259 for (size_t i = 0; i < labels.size(); i++) { | |
260 dest_deps[i] = GetBuildSettings()->target_manager().GetTarget( | |
261 labels[i], value->list_value()[i].origin()->GetRange(), target_, err_); | |
262 if (err_->has_error()) | |
263 return; | |
264 } | |
265 | |
266 target_->swap_in_deps(&dest_deps); | |
267 } | |
268 | |
269 void TargetGenerator::FillDestDir() { | |
270 // Destdir is required for all targets that use it. | |
271 const Value* value = scope_->GetValue("destdir", true); | |
272 if (!value) { | |
273 *err_ = Err(function_token_, "This target type requires a \"destdir\"."); | |
274 return; | |
275 } | |
276 if (!value->VerifyTypeIs(Value::STRING, err_)) | |
277 return; | |
278 | |
279 if (!EnsureStringIsInOutputDir( | |
280 GetBuildSettings()->build_dir(), | |
281 value->string_value(), *value, err_)) | |
282 return; | |
283 target_->set_destdir(SourceDir(value->string_value())); | |
284 } | |
285 | |
286 void TargetGenerator::FillScript() { | |
287 // If this gets called, the target type requires a script, so error out | |
288 // if it doesn't have one. | |
289 const Value* value = scope_->GetValue("script", true); | |
290 if (!value) { | |
291 *err_ = Err(function_token_, "This target type requires a \"script\"."); | |
292 return; | |
293 } | |
294 if (!value->VerifyTypeIs(Value::STRING, err_)) | |
295 return; | |
296 | |
297 target_->set_script( | |
298 input_directory_.ResolveRelativeFile(value->string_value())); | |
299 } | |
300 | |
301 void TargetGenerator::FillScriptArgs() { | |
302 const Value* value = scope_->GetValue("args", true); | |
303 if (!value) | |
304 return; | |
305 | |
306 std::vector<std::string> args; | |
307 if (!ExtractListOfStringValues(*value, &args, err_)) | |
308 return; | |
309 target_->swap_in_script_args(&args); | |
310 } | |
311 | |
312 void TargetGenerator::FillOutputs() { | |
313 const Value* value = scope_->GetValue("outputs", true); | |
314 if (!value) | |
315 return; | |
316 | |
317 Target::FileList outputs; | |
318 if (!ExtractListOfRelativeFiles(*value, input_directory_, &outputs, err_)) | |
319 return; | |
320 | |
321 // Validate that outputs are in the output dir. | |
322 CHECK(outputs.size() == value->list_value().size()); | |
323 for (size_t i = 0; i < outputs.size(); i++) { | |
324 if (!EnsureStringIsInOutputDir( | |
325 GetBuildSettings()->build_dir(), | |
326 outputs[i].value(), value->list_value()[i], err_)) | |
327 return; | |
328 } | |
329 target_->swap_in_outputs(&outputs); | |
330 } | |
331 | |
332 const BuildSettings* TargetGenerator::GetBuildSettings() const { | |
333 return scope_->settings()->build_settings(); | |
334 } | |
OLD | NEW |