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 "gn/target_generator.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10 #include <utility>
11
12 #include "gn/action_target_generator.h"
13 #include "gn/binary_target_generator.h"
14 #include "gn/build_settings.h"
15 #include "gn/bundle_data_target_generator.h"
16 #include "gn/config.h"
17 #include "gn/copy_target_generator.h"
18 #include "gn/create_bundle_target_generator.h"
19 #include "gn/err.h"
20 #include "gn/filesystem_utils.h"
21 #include "gn/functions.h"
22 #include "gn/generated_file_target_generator.h"
23 #include "gn/group_target_generator.h"
24 #include "gn/metadata.h"
25 #include "gn/parse_tree.h"
26 #include "gn/scheduler.h"
27 #include "gn/scope.h"
28 #include "gn/token.h"
29 #include "gn/value.h"
30 #include "gn/value_extractors.h"
31 #include "gn/variables.h"
32
TargetGenerator(Target * target,Scope * scope,const FunctionCallNode * function_call,Err * err)33 TargetGenerator::TargetGenerator(Target* target,
34 Scope* scope,
35 const FunctionCallNode* function_call,
36 Err* err)
37 : target_(target),
38 scope_(scope),
39 function_call_(function_call),
40 err_(err) {}
41
42 TargetGenerator::~TargetGenerator() = default;
43
Run()44 void TargetGenerator::Run() {
45 // All target types use these.
46 if (!FillDependentConfigs())
47 return;
48
49 if (!FillData())
50 return;
51
52 if (!FillDependencies())
53 return;
54
55 if (!FillMetadata())
56 return;
57
58 if (!FillTestonly())
59 return;
60
61 if (!FillAssertNoDeps())
62 return;
63
64 if (!Visibility::FillItemVisibility(target_, scope_, err_))
65 return;
66
67 if (!FillWriteRuntimeDeps())
68 return;
69
70 // Do type-specific generation.
71 DoRun();
72 }
73
74 // static
GenerateTarget(Scope * scope,const FunctionCallNode * function_call,const std::vector<Value> & args,const std::string & output_type,Err * err)75 void TargetGenerator::GenerateTarget(Scope* scope,
76 const FunctionCallNode* function_call,
77 const std::vector<Value>& args,
78 const std::string& output_type,
79 Err* err) {
80 // Name is the argument to the function.
81 if (args.size() != 1u || args[0].type() != Value::STRING) {
82 *err = Err(function_call, "Target generator requires one string argument.",
83 "Otherwise I'm not sure what to call this target.");
84 return;
85 }
86
87 // The location of the target is the directory name with no slash at the end.
88 // FIXME(brettw) validate name.
89 const Label& toolchain_label = ToolchainLabelForScope(scope);
90 Label label(scope->GetSourceDir(), args[0].string_value(),
91 toolchain_label.dir(), toolchain_label.name());
92
93 if (g_scheduler->verbose_logging())
94 g_scheduler->Log("Defining target", label.GetUserVisibleName(true));
95
96 std::unique_ptr<Target> target = std::make_unique<Target>(
97 scope->settings(), label, scope->build_dependency_files());
98 target->set_defined_from(function_call);
99
100 // Create and call out to the proper generator.
101 if (output_type == functions::kBundleData) {
102 BundleDataTargetGenerator generator(target.get(), scope, function_call,
103 err);
104 generator.Run();
105 } else if (output_type == functions::kCreateBundle) {
106 CreateBundleTargetGenerator generator(target.get(), scope, function_call,
107 err);
108 generator.Run();
109 } else if (output_type == functions::kCopy) {
110 CopyTargetGenerator generator(target.get(), scope, function_call, err);
111 generator.Run();
112 } else if (output_type == functions::kAction) {
113 ActionTargetGenerator generator(target.get(), scope, function_call,
114 Target::ACTION, err);
115 generator.Run();
116 } else if (output_type == functions::kActionForEach) {
117 ActionTargetGenerator generator(target.get(), scope, function_call,
118 Target::ACTION_FOREACH, err);
119 generator.Run();
120 } else if (output_type == functions::kExecutable) {
121 BinaryTargetGenerator generator(target.get(), scope, function_call,
122 Target::EXECUTABLE, err);
123 generator.Run();
124 } else if (output_type == functions::kGroup) {
125 GroupTargetGenerator generator(target.get(), scope, function_call, err);
126 generator.Run();
127 } else if (output_type == functions::kLoadableModule) {
128 BinaryTargetGenerator generator(target.get(), scope, function_call,
129 Target::LOADABLE_MODULE, err);
130 generator.Run();
131 } else if (output_type == functions::kSharedLibrary) {
132 BinaryTargetGenerator generator(target.get(), scope, function_call,
133 Target::SHARED_LIBRARY, err);
134 generator.Run();
135 } else if (output_type == functions::kSourceSet) {
136 BinaryTargetGenerator generator(target.get(), scope, function_call,
137 Target::SOURCE_SET, err);
138 generator.Run();
139 } else if (output_type == functions::kStaticLibrary) {
140 BinaryTargetGenerator generator(target.get(), scope, function_call,
141 Target::STATIC_LIBRARY, err);
142 generator.Run();
143 } else if (output_type == functions::kGeneratedFile) {
144 GeneratedFileTargetGenerator generator(target.get(), scope, function_call,
145 Target::GENERATED_FILE, err);
146 generator.Run();
147 } else if (output_type == functions::kRustLibrary) {
148 BinaryTargetGenerator generator(target.get(), scope, function_call,
149 Target::RUST_LIBRARY, err);
150 generator.Run();
151 } else if (output_type == functions::kRustProcMacro) {
152 BinaryTargetGenerator generator(target.get(), scope, function_call,
153 Target::RUST_PROC_MACRO, err);
154 generator.Run();
155 } else {
156 *err = Err(function_call, "Not a known target type",
157 "I am very confused by the target type \"" + output_type + "\"");
158 }
159
160 if (err->has_error())
161 return;
162
163 // Save this target for the file.
164 Scope::ItemVector* collector = scope->GetItemCollector();
165 if (!collector) {
166 *err = Err(function_call, "Can't define a target in this context.");
167 return;
168 }
169 collector->push_back(std::move(target));
170 }
171
GetBuildSettings() const172 const BuildSettings* TargetGenerator::GetBuildSettings() const {
173 return scope_->settings()->build_settings();
174 }
175
FillSources()176 bool TargetGenerator::FillSources() {
177 const Value* value = scope_->GetValue(variables::kSources, true);
178 if (!value)
179 return true;
180
181 Target::FileList dest_sources;
182 if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
183 scope_->GetSourceDir(), &dest_sources, err_))
184 return false;
185 target_->sources() = std::move(dest_sources);
186 return true;
187 }
188
FillPublic()189 bool TargetGenerator::FillPublic() {
190 const Value* value = scope_->GetValue(variables::kPublic, true);
191 if (!value)
192 return true;
193
194 // If the public headers are defined, don't default to public.
195 target_->set_all_headers_public(false);
196
197 Target::FileList dest_public;
198 if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
199 scope_->GetSourceDir(), &dest_public, err_))
200 return false;
201 target_->public_headers() = std::move(dest_public);
202 return true;
203 }
204
FillConfigs()205 bool TargetGenerator::FillConfigs() {
206 return FillGenericConfigs(variables::kConfigs, &target_->configs());
207 }
208
FillDependentConfigs()209 bool TargetGenerator::FillDependentConfigs() {
210 if (!FillGenericConfigs(variables::kAllDependentConfigs,
211 &target_->all_dependent_configs()))
212 return false;
213
214 if (!FillGenericConfigs(variables::kPublicConfigs,
215 &target_->public_configs()))
216 return false;
217
218 return true;
219 }
220
FillData()221 bool TargetGenerator::FillData() {
222 const Value* value = scope_->GetValue(variables::kData, true);
223 if (!value)
224 return true;
225 if (!value->VerifyTypeIs(Value::LIST, err_))
226 return false;
227
228 const std::vector<Value>& input_list = value->list_value();
229 std::vector<std::string>& output_list = target_->data();
230 output_list.reserve(input_list.size());
231
232 const SourceDir& dir = scope_->GetSourceDir();
233 const std::string& root_path =
234 scope_->settings()->build_settings()->root_path_utf8();
235
236 for (size_t i = 0; i < input_list.size(); i++) {
237 const Value& input = input_list[i];
238 if (!input.VerifyTypeIs(Value::STRING, err_))
239 return false;
240 const std::string input_str = input.string_value();
241
242 // Treat each input as either a file or a directory, depending on the
243 // last character.
244 bool as_dir = !input_str.empty() && input_str[input_str.size() - 1] == '/';
245
246 std::string resolved =
247 dir.ResolveRelativeAs(!as_dir, input, err_, root_path, &input_str);
248 if (err_->has_error())
249 return false;
250
251 output_list.push_back(resolved);
252 }
253 return true;
254 }
255
FillDependencies()256 bool TargetGenerator::FillDependencies() {
257 if (!FillGenericDeps(variables::kDeps, &target_->private_deps()))
258 return false;
259 if (!FillGenericDeps(variables::kPublicDeps, &target_->public_deps()))
260 return false;
261 if (!FillGenericDeps(variables::kDataDeps, &target_->data_deps()))
262 return false;
263
264 // "data_deps" was previously named "datadeps". For backwards-compat, read
265 // the old one if no "data_deps" were specified.
266 if (!scope_->GetValue(variables::kDataDeps, false)) {
267 if (!FillGenericDeps("datadeps", &target_->data_deps()))
268 return false;
269 }
270
271 return true;
272 }
273
FillMetadata()274 bool TargetGenerator::FillMetadata() {
275 // Need to get a mutable value to mark all values in the scope as used. This
276 // cannot be done on a const Scope.
277 Value* value = scope_->GetMutableValue(variables::kMetadata,
278 Scope::SEARCH_CURRENT, true);
279
280 if (!value)
281 return true;
282
283 if (!value->VerifyTypeIs(Value::SCOPE, err_))
284 return false;
285
286 Scope* scope_value = value->scope_value();
287
288 scope_value->GetCurrentScopeValues(&target_->metadata().contents());
289 scope_value->MarkAllUsed();
290
291 // Metadata values should always hold lists of Values, such that they can be
292 // collected and concatenated. Any additional specific type verification is
293 // done at walk time.
294 for (const auto& iter : target_->metadata().contents()) {
295 if (!iter.second.VerifyTypeIs(Value::LIST, err_))
296 return false;
297 }
298
299 target_->metadata().set_source_dir(scope_->GetSourceDir());
300 target_->metadata().set_origin(value->origin());
301 return true;
302 }
303
FillTestonly()304 bool TargetGenerator::FillTestonly() {
305 const Value* value = scope_->GetValue(variables::kTestonly, true);
306 if (value) {
307 if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
308 return false;
309 target_->set_testonly(value->boolean_value());
310 }
311 return true;
312 }
313
FillAssertNoDeps()314 bool TargetGenerator::FillAssertNoDeps() {
315 const Value* value = scope_->GetValue(variables::kAssertNoDeps, true);
316 if (value) {
317 return ExtractListOfLabelPatterns(scope_->settings()->build_settings(),
318 *value, scope_->GetSourceDir(),
319 &target_->assert_no_deps(), err_);
320 }
321 return true;
322 }
323
FillOutputs(bool allow_substitutions)324 bool TargetGenerator::FillOutputs(bool allow_substitutions) {
325 const Value* value = scope_->GetValue(variables::kOutputs, true);
326 if (!value)
327 return true;
328
329 SubstitutionList& outputs = target_->action_values().outputs();
330 if (!outputs.Parse(*value, err_))
331 return false;
332
333 if (!allow_substitutions) {
334 // Verify no substitutions were actually used.
335 if (!outputs.required_types().empty()) {
336 *err_ =
337 Err(*value, "Source expansions not allowed here.",
338 "The outputs of this target used source {{expansions}} but this "
339 "target type\ndoesn't support them. Just express the outputs "
340 "literally.");
341 return false;
342 }
343 }
344
345 // Check the substitutions used are valid for this purpose.
346 if (!EnsureValidSubstitutions(outputs.required_types(),
347 &IsValidSourceSubstitution, value->origin(),
348 err_))
349 return false;
350
351 // Validate that outputs are in the output dir.
352 CHECK(outputs.list().size() == value->list_value().size());
353 for (size_t i = 0; i < outputs.list().size(); i++) {
354 if (!EnsureSubstitutionIsInOutputDir(outputs.list()[i],
355 value->list_value()[i]))
356 return false;
357 }
358 return true;
359 }
360
FillCheckIncludes()361 bool TargetGenerator::FillCheckIncludes() {
362 const Value* value = scope_->GetValue(variables::kCheckIncludes, true);
363 if (!value)
364 return true;
365 if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
366 return false;
367 target_->set_check_includes(value->boolean_value());
368 return true;
369 }
370
FillOutputExtension()371 bool TargetGenerator::FillOutputExtension() {
372 const Value* value = scope_->GetValue(variables::kOutputExtension, true);
373 if (!value)
374 return true;
375 if (!value->VerifyTypeIs(Value::STRING, err_))
376 return false;
377 target_->set_output_extension(value->string_value());
378 return true;
379 }
380
EnsureSubstitutionIsInOutputDir(const SubstitutionPattern & pattern,const Value & original_value)381 bool TargetGenerator::EnsureSubstitutionIsInOutputDir(
382 const SubstitutionPattern& pattern,
383 const Value& original_value) {
384 if (pattern.ranges().empty()) {
385 // Pattern is empty, error out (this prevents weirdness below).
386 *err_ = Err(original_value, "This has an empty value in it.");
387 return false;
388 }
389
390 if (pattern.ranges()[0].type == &SubstitutionLiteral) {
391 // If the first thing is a literal, it must start with the output dir.
392 if (!EnsureStringIsInOutputDir(GetBuildSettings()->build_dir(),
393 pattern.ranges()[0].literal,
394 original_value.origin(), err_))
395 return false;
396 } else {
397 // Otherwise, the first subrange must be a pattern that expands to
398 // something in the output directory.
399 if (!SubstitutionIsInOutputDir(pattern.ranges()[0].type)) {
400 *err_ =
401 Err(original_value, "File is not inside output directory.",
402 "The given file should be in the output directory. Normally you\n"
403 "would specify\n\"$target_out_dir/foo\" or "
404 "\"{{source_gen_dir}}/foo\".");
405 return false;
406 }
407 }
408
409 return true;
410 }
411
FillGenericConfigs(const char * var_name,UniqueVector<LabelConfigPair> * dest)412 bool TargetGenerator::FillGenericConfigs(const char* var_name,
413 UniqueVector<LabelConfigPair>* dest) {
414 const Value* value = scope_->GetValue(var_name, true);
415 if (value) {
416 ExtractListOfUniqueLabels(scope_->settings()->build_settings(), *value,
417 scope_->GetSourceDir(),
418 ToolchainLabelForScope(scope_), dest, err_);
419 }
420 return !err_->has_error();
421 }
422
FillGenericDeps(const char * var_name,LabelTargetVector * dest)423 bool TargetGenerator::FillGenericDeps(const char* var_name,
424 LabelTargetVector* dest) {
425 const Value* value = scope_->GetValue(var_name, true);
426 if (value) {
427 ExtractListOfLabels(scope_->settings()->build_settings(), *value,
428 scope_->GetSourceDir(), ToolchainLabelForScope(scope_),
429 dest, err_);
430 }
431 return !err_->has_error();
432 }
433
FillWriteRuntimeDeps()434 bool TargetGenerator::FillWriteRuntimeDeps() {
435 const Value* value = scope_->GetValue(variables::kWriteRuntimeDeps, true);
436 if (!value)
437 return true;
438
439 // Compute the file name and make sure it's in the output dir.
440 SourceFile source_file = scope_->GetSourceDir().ResolveRelativeFile(
441 *value, err_, GetBuildSettings()->root_path_utf8());
442 if (err_->has_error())
443 return false;
444 if (!EnsureStringIsInOutputDir(GetBuildSettings()->build_dir(),
445 source_file.value(), value->origin(), err_))
446 return false;
447 OutputFile output_file(GetBuildSettings(), source_file);
448 target_->set_write_runtime_deps_output(output_file);
449
450 return true;
451 }
452