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