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