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
173 InnerApiPublicInfoGenerator* instance = InnerApiPublicInfoGenerator::getInstance();
174 if (instance != nullptr) {
175 instance->GeneratedInnerapiPublicInfo(target.get(), label, scope, output_type, err);
176 }
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
FillPublic()198 bool TargetGenerator::FillPublic() {
199 const Value* value = scope_->GetValue(variables::kPublic, true);
200 if (!value)
201 return true;
202
203 // If the public headers are defined, don't default to public.
204 target_->set_all_headers_public(false);
205
206 Target::FileList dest_public;
207 if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
208 scope_->GetSourceDir(), &dest_public, err_))
209 return false;
210 target_->public_headers() = std::move(dest_public);
211 return true;
212 }
213
FillConfigs()214 bool TargetGenerator::FillConfigs() {
215 return FillGenericConfigs(variables::kConfigs, &target_->configs());
216 }
217
FillDependentConfigs()218 bool TargetGenerator::FillDependentConfigs() {
219 if (!FillGenericConfigs(variables::kAllDependentConfigs,
220 &target_->all_dependent_configs()))
221 return false;
222
223 if (!FillGenericConfigs(variables::kPublicConfigs,
224 &target_->public_configs()))
225 return false;
226
227 return true;
228 }
229
FillData()230 bool TargetGenerator::FillData() {
231 const Value* value = scope_->GetValue(variables::kData, true);
232 if (!value)
233 return true;
234 if (!value->VerifyTypeIs(Value::LIST, err_))
235 return false;
236
237 const std::vector<Value>& input_list = value->list_value();
238 std::vector<std::string>& output_list = target_->data();
239 output_list.reserve(input_list.size());
240
241 const SourceDir& dir = scope_->GetSourceDir();
242 const std::string& root_path =
243 scope_->settings()->build_settings()->root_path_utf8();
244
245 for (size_t i = 0; i < input_list.size(); i++) {
246 const Value& input = input_list[i];
247 if (!input.VerifyTypeIs(Value::STRING, err_))
248 return false;
249 const std::string input_str = input.string_value();
250
251 // Treat each input as either a file or a directory, depending on the
252 // last character.
253 bool as_dir = !input_str.empty() && input_str[input_str.size() - 1] == '/';
254
255 std::string resolved =
256 dir.ResolveRelativeAs(!as_dir, input, err_, root_path, &input_str);
257 if (err_->has_error())
258 return false;
259
260 output_list.push_back(resolved);
261 }
262 return true;
263 }
264
FillDependencies()265 bool TargetGenerator::FillDependencies() {
266 if (!FillGenericDeps(variables::kDeps, &target_->private_deps()))
267 return false;
268 if (scope_->settings()->build_settings()->is_ohos_components_enabled()) {
269 if (!FillOhosComponentDeps(variables::kExternalDeps, &target_->private_deps()))
270 return false;
271 if (!FillOhosComponentDeps(variables::kPublicExternalDeps, &target_->public_deps()))
272 return false;
273 }
274 if (!FillGenericDeps(variables::kPublicDeps, &target_->public_deps()))
275 return false;
276 if (!FillGenericDeps(variables::kDataDeps, &target_->data_deps()))
277 return false;
278 if (!FillGenericDeps(variables::kGenDeps, &target_->gen_deps()))
279 return false;
280
281 // "data_deps" was previously named "datadeps". For backwards-compat, read
282 // the old one if no "data_deps" were specified.
283 if (!scope_->GetValue(variables::kDataDeps, false)) {
284 if (!FillGenericDeps("datadeps", &target_->data_deps()))
285 return false;
286 }
287
288 return true;
289 }
290
FillMetadata()291 bool TargetGenerator::FillMetadata() {
292 // Need to get a mutable value to mark all values in the scope as used. This
293 // cannot be done on a const Scope.
294 Value* value = scope_->GetMutableValue(variables::kMetadata,
295 Scope::SEARCH_CURRENT, true);
296
297 if (!value)
298 return true;
299
300 if (!value->VerifyTypeIs(Value::SCOPE, err_))
301 return false;
302
303 Scope* scope_value = value->scope_value();
304
305 scope_value->GetCurrentScopeValues(&target_->metadata().contents());
306 scope_value->MarkAllUsed();
307
308 // Metadata values should always hold lists of Values, such that they can be
309 // collected and concatenated. Any additional specific type verification is
310 // done at walk time.
311 for (const auto& iter : target_->metadata().contents()) {
312 if (!iter.second.VerifyTypeIs(Value::LIST, err_))
313 return false;
314 }
315
316 target_->metadata().set_source_dir(scope_->GetSourceDir());
317 target_->metadata().set_origin(value->origin());
318 return true;
319 }
320
FillTestonly()321 bool TargetGenerator::FillTestonly() {
322 const Value* value = scope_->GetValue(variables::kTestonly, true);
323 if (value) {
324 if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
325 return false;
326 target_->set_testonly(value->boolean_value());
327 }
328 return true;
329 }
330
FillAssertNoDeps()331 bool TargetGenerator::FillAssertNoDeps() {
332 const Value* value = scope_->GetValue(variables::kAssertNoDeps, true);
333 if (value) {
334 return ExtractListOfLabelPatterns(scope_->settings()->build_settings(),
335 *value, scope_->GetSourceDir(),
336 &target_->assert_no_deps(), err_);
337 }
338 return true;
339 }
340
FillOutputs(bool allow_substitutions)341 bool TargetGenerator::FillOutputs(bool allow_substitutions) {
342 const Value* value = scope_->GetValue(variables::kOutputs, true);
343 if (!value)
344 return true;
345
346 SubstitutionList& outputs = target_->action_values().outputs();
347 if (!outputs.Parse(*value, err_))
348 return false;
349
350 if (!allow_substitutions) {
351 // Verify no substitutions were actually used.
352 if (!outputs.required_types().empty()) {
353 *err_ =
354 Err(*value, "Source expansions not allowed here.",
355 "The outputs of this target used source {{expansions}} but this "
356 "target type\ndoesn't support them. Just express the outputs "
357 "literally.");
358 return false;
359 }
360 }
361
362 // Check the substitutions used are valid for this purpose.
363 if (!EnsureValidSubstitutions(outputs.required_types(),
364 &IsValidSourceSubstitution, value->origin(),
365 err_))
366 return false;
367
368 // Validate that outputs are in the output dir.
369 CHECK(outputs.list().size() == value->list_value().size());
370 for (size_t i = 0; i < outputs.list().size(); i++) {
371 if (!EnsureSubstitutionIsInOutputDir(outputs.list()[i],
372 value->list_value()[i]))
373 return false;
374 }
375 return true;
376 }
377
FillCheckIncludes()378 bool TargetGenerator::FillCheckIncludes() {
379 const Value* value = scope_->GetValue(variables::kCheckIncludes, true);
380 if (!value)
381 return true;
382 if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
383 return false;
384 target_->set_check_includes(value->boolean_value());
385 return true;
386 }
387
FillOutputExtension()388 bool TargetGenerator::FillOutputExtension() {
389 const Value* value = scope_->GetValue(variables::kOutputExtension, true);
390 if (!value)
391 return true;
392 if (!value->VerifyTypeIs(Value::STRING, err_))
393 return false;
394 target_->set_output_extension(value->string_value());
395 return true;
396 }
397
EnsureSubstitutionIsInOutputDir(const SubstitutionPattern & pattern,const Value & original_value)398 bool TargetGenerator::EnsureSubstitutionIsInOutputDir(
399 const SubstitutionPattern& pattern,
400 const Value& original_value) {
401 if (pattern.ranges().empty()) {
402 // Pattern is empty, error out (this prevents weirdness below).
403 *err_ = Err(original_value, "This has an empty value in it.");
404 return false;
405 }
406
407 if (pattern.ranges()[0].type == &SubstitutionLiteral) {
408 // If the first thing is a literal, it must start with the output dir.
409 if (!EnsureStringIsInOutputDir(GetBuildSettings()->build_dir(),
410 pattern.ranges()[0].literal,
411 original_value.origin(), err_))
412 return false;
413 } else {
414 // Otherwise, the first subrange must be a pattern that expands to
415 // something in the output directory.
416 if (!SubstitutionIsInOutputDir(pattern.ranges()[0].type)) {
417 *err_ =
418 Err(original_value, "File is not inside output directory.",
419 "The given file should be in the output directory. Normally you\n"
420 "would specify\n\"$target_out_dir/foo\" or "
421 "\"{{source_gen_dir}}/foo\".");
422 return false;
423 }
424 }
425
426 return true;
427 }
428
FillGenericConfigs(const char * var_name,UniqueVector<LabelConfigPair> * dest)429 bool TargetGenerator::FillGenericConfigs(const char* var_name,
430 UniqueVector<LabelConfigPair>* dest) {
431 const Value* value = scope_->GetValue(var_name, true);
432 if (value) {
433 ExtractListOfUniqueLabels(scope_->settings()->build_settings(), *value,
434 scope_->GetSourceDir(),
435 ToolchainLabelForScope(scope_), dest, err_);
436 }
437 return !err_->has_error();
438 }
439
FillGenericDeps(const char * var_name,LabelTargetVector * dest)440 bool TargetGenerator::FillGenericDeps(const char* var_name,
441 LabelTargetVector* dest) {
442 const Value* value = scope_->GetValue(var_name, true);
443 if (value) {
444 ExtractListOfLabels(scope_->settings()->build_settings(), *value,
445 scope_->GetSourceDir(), ToolchainLabelForScope(scope_),
446 dest, err_);
447 }
448 return !err_->has_error();
449 }
450
FillOhosComponentDeps(const char * var_name,LabelTargetVector * dest)451 bool TargetGenerator::FillOhosComponentDeps(const char* var_name, LabelTargetVector* dest)
452 {
453 const Value* value = scope_->GetValue(var_name, true);
454 if (value) {
455 // Append to private deps
456 ExtractListOfExternalDeps(scope_->settings()->build_settings(), *value,
457 scope_->GetSourceDir(), ToolchainLabelForScope(scope_),
458 dest, err_);
459 }
460 return !err_->has_error();
461 }
FillWriteRuntimeDeps()462 bool TargetGenerator::FillWriteRuntimeDeps() {
463 const Value* value = scope_->GetValue(variables::kWriteRuntimeDeps, true);
464 if (!value)
465 return true;
466
467 // Compute the file name and make sure it's in the output dir.
468 SourceFile source_file = scope_->GetSourceDir().ResolveRelativeFile(
469 *value, err_, GetBuildSettings()->root_path_utf8());
470 if (err_->has_error())
471 return false;
472 if (!EnsureStringIsInOutputDir(GetBuildSettings()->build_dir(),
473 source_file.value(), value->origin(), err_))
474 return false;
475 OutputFile output_file(GetBuildSettings(), source_file);
476 target_->set_write_runtime_deps_output(output_file);
477
478 return true;
479 }
480