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