• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }