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