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 if (!FillGenericDeps(variables::kGenDeps, &target_->gen_deps()))
264 return false;
265
266 // "data_deps" was previously named "datadeps". For backwards-compat, read
267 // the old one if no "data_deps" were specified.
268 if (!scope_->GetValue(variables::kDataDeps, false)) {
269 if (!FillGenericDeps("datadeps", &target_->data_deps()))
270 return false;
271 }
272
273 return true;
274 }
275
FillMetadata()276 bool TargetGenerator::FillMetadata() {
277 // Need to get a mutable value to mark all values in the scope as used. This
278 // cannot be done on a const Scope.
279 Value* value = scope_->GetMutableValue(variables::kMetadata,
280 Scope::SEARCH_CURRENT, true);
281
282 if (!value)
283 return true;
284
285 if (!value->VerifyTypeIs(Value::SCOPE, err_))
286 return false;
287
288 Scope* scope_value = value->scope_value();
289
290 scope_value->GetCurrentScopeValues(&target_->metadata().contents());
291 scope_value->MarkAllUsed();
292
293 // Metadata values should always hold lists of Values, such that they can be
294 // collected and concatenated. Any additional specific type verification is
295 // done at walk time.
296 for (const auto& iter : target_->metadata().contents()) {
297 if (!iter.second.VerifyTypeIs(Value::LIST, err_))
298 return false;
299 }
300
301 target_->metadata().set_source_dir(scope_->GetSourceDir());
302 target_->metadata().set_origin(value->origin());
303 return true;
304 }
305
FillTestonly()306 bool TargetGenerator::FillTestonly() {
307 const Value* value = scope_->GetValue(variables::kTestonly, true);
308 if (value) {
309 if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
310 return false;
311 target_->set_testonly(value->boolean_value());
312 }
313 return true;
314 }
315
FillAssertNoDeps()316 bool TargetGenerator::FillAssertNoDeps() {
317 const Value* value = scope_->GetValue(variables::kAssertNoDeps, true);
318 if (value) {
319 return ExtractListOfLabelPatterns(scope_->settings()->build_settings(),
320 *value, scope_->GetSourceDir(),
321 &target_->assert_no_deps(), err_);
322 }
323 return true;
324 }
325
FillOutputs(bool allow_substitutions)326 bool TargetGenerator::FillOutputs(bool allow_substitutions) {
327 const Value* value = scope_->GetValue(variables::kOutputs, true);
328 if (!value)
329 return true;
330
331 SubstitutionList& outputs = target_->action_values().outputs();
332 if (!outputs.Parse(*value, err_))
333 return false;
334
335 if (!allow_substitutions) {
336 // Verify no substitutions were actually used.
337 if (!outputs.required_types().empty()) {
338 *err_ =
339 Err(*value, "Source expansions not allowed here.",
340 "The outputs of this target used source {{expansions}} but this "
341 "target type\ndoesn't support them. Just express the outputs "
342 "literally.");
343 return false;
344 }
345 }
346
347 // Check the substitutions used are valid for this purpose.
348 if (!EnsureValidSubstitutions(outputs.required_types(),
349 &IsValidSourceSubstitution, value->origin(),
350 err_))
351 return false;
352
353 // Validate that outputs are in the output dir.
354 CHECK(outputs.list().size() == value->list_value().size());
355 for (size_t i = 0; i < outputs.list().size(); i++) {
356 if (!EnsureSubstitutionIsInOutputDir(outputs.list()[i],
357 value->list_value()[i]))
358 return false;
359 }
360 return true;
361 }
362
FillCheckIncludes()363 bool TargetGenerator::FillCheckIncludes() {
364 const Value* value = scope_->GetValue(variables::kCheckIncludes, true);
365 if (!value)
366 return true;
367 if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
368 return false;
369 target_->set_check_includes(value->boolean_value());
370 return true;
371 }
372
FillOutputExtension()373 bool TargetGenerator::FillOutputExtension() {
374 const Value* value = scope_->GetValue(variables::kOutputExtension, true);
375 if (!value)
376 return true;
377 if (!value->VerifyTypeIs(Value::STRING, err_))
378 return false;
379 target_->set_output_extension(value->string_value());
380 return true;
381 }
382
EnsureSubstitutionIsInOutputDir(const SubstitutionPattern & pattern,const Value & original_value)383 bool TargetGenerator::EnsureSubstitutionIsInOutputDir(
384 const SubstitutionPattern& pattern,
385 const Value& original_value) {
386 if (pattern.ranges().empty()) {
387 // Pattern is empty, error out (this prevents weirdness below).
388 *err_ = Err(original_value, "This has an empty value in it.");
389 return false;
390 }
391
392 if (pattern.ranges()[0].type == &SubstitutionLiteral) {
393 // If the first thing is a literal, it must start with the output dir.
394 if (!EnsureStringIsInOutputDir(GetBuildSettings()->build_dir(),
395 pattern.ranges()[0].literal,
396 original_value.origin(), err_))
397 return false;
398 } else {
399 // Otherwise, the first subrange must be a pattern that expands to
400 // something in the output directory.
401 if (!SubstitutionIsInOutputDir(pattern.ranges()[0].type)) {
402 *err_ =
403 Err(original_value, "File is not inside output directory.",
404 "The given file should be in the output directory. Normally you\n"
405 "would specify\n\"$target_out_dir/foo\" or "
406 "\"{{source_gen_dir}}/foo\".");
407 return false;
408 }
409 }
410
411 return true;
412 }
413
FillGenericConfigs(const char * var_name,UniqueVector<LabelConfigPair> * dest)414 bool TargetGenerator::FillGenericConfigs(const char* var_name,
415 UniqueVector<LabelConfigPair>* dest) {
416 const Value* value = scope_->GetValue(var_name, true);
417 if (value) {
418 ExtractListOfUniqueLabels(scope_->settings()->build_settings(), *value,
419 scope_->GetSourceDir(),
420 ToolchainLabelForScope(scope_), dest, err_);
421 }
422 return !err_->has_error();
423 }
424
FillGenericDeps(const char * var_name,LabelTargetVector * dest)425 bool TargetGenerator::FillGenericDeps(const char* var_name,
426 LabelTargetVector* dest) {
427 const Value* value = scope_->GetValue(var_name, true);
428 if (value) {
429 ExtractListOfLabels(scope_->settings()->build_settings(), *value,
430 scope_->GetSourceDir(), ToolchainLabelForScope(scope_),
431 dest, err_);
432 }
433 return !err_->has_error();
434 }
435
FillWriteRuntimeDeps()436 bool TargetGenerator::FillWriteRuntimeDeps() {
437 const Value* value = scope_->GetValue(variables::kWriteRuntimeDeps, true);
438 if (!value)
439 return true;
440
441 // Compute the file name and make sure it's in the output dir.
442 SourceFile source_file = scope_->GetSourceDir().ResolveRelativeFile(
443 *value, err_, GetBuildSettings()->root_path_utf8());
444 if (err_->has_error())
445 return false;
446 if (!EnsureStringIsInOutputDir(GetBuildSettings()->build_dir(),
447 source_file.value(), value->origin(), err_))
448 return false;
449 OutputFile output_file(GetBuildSettings(), source_file);
450 target_->set_write_runtime_deps_output(output_file);
451
452 return true;
453 }
454