• 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   // 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 }