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