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