• 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 
264   // "data_deps" was previously named "datadeps". For backwards-compat, read
265   // the old one if no "data_deps" were specified.
266   if (!scope_->GetValue(variables::kDataDeps, false)) {
267     if (!FillGenericDeps("datadeps", &target_->data_deps()))
268       return false;
269   }
270 
271   return true;
272 }
273 
FillMetadata()274 bool TargetGenerator::FillMetadata() {
275   // Need to get a mutable value to mark all values in the scope as used. This
276   // cannot be done on a const Scope.
277   Value* value = scope_->GetMutableValue(variables::kMetadata,
278                                          Scope::SEARCH_CURRENT, true);
279 
280   if (!value)
281     return true;
282 
283   if (!value->VerifyTypeIs(Value::SCOPE, err_))
284     return false;
285 
286   Scope* scope_value = value->scope_value();
287 
288   scope_value->GetCurrentScopeValues(&target_->metadata().contents());
289   scope_value->MarkAllUsed();
290 
291   // Metadata values should always hold lists of Values, such that they can be
292   // collected and concatenated. Any additional specific type verification is
293   // done at walk time.
294   for (const auto& iter : target_->metadata().contents()) {
295     if (!iter.second.VerifyTypeIs(Value::LIST, err_))
296       return false;
297   }
298 
299   target_->metadata().set_source_dir(scope_->GetSourceDir());
300   target_->metadata().set_origin(value->origin());
301   return true;
302 }
303 
FillTestonly()304 bool TargetGenerator::FillTestonly() {
305   const Value* value = scope_->GetValue(variables::kTestonly, true);
306   if (value) {
307     if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
308       return false;
309     target_->set_testonly(value->boolean_value());
310   }
311   return true;
312 }
313 
FillAssertNoDeps()314 bool TargetGenerator::FillAssertNoDeps() {
315   const Value* value = scope_->GetValue(variables::kAssertNoDeps, true);
316   if (value) {
317     return ExtractListOfLabelPatterns(scope_->settings()->build_settings(),
318                                       *value, scope_->GetSourceDir(),
319                                       &target_->assert_no_deps(), err_);
320   }
321   return true;
322 }
323 
FillOutputs(bool allow_substitutions)324 bool TargetGenerator::FillOutputs(bool allow_substitutions) {
325   const Value* value = scope_->GetValue(variables::kOutputs, true);
326   if (!value)
327     return true;
328 
329   SubstitutionList& outputs = target_->action_values().outputs();
330   if (!outputs.Parse(*value, err_))
331     return false;
332 
333   if (!allow_substitutions) {
334     // Verify no substitutions were actually used.
335     if (!outputs.required_types().empty()) {
336       *err_ =
337           Err(*value, "Source expansions not allowed here.",
338               "The outputs of this target used source {{expansions}} but this "
339               "target type\ndoesn't support them. Just express the outputs "
340               "literally.");
341       return false;
342     }
343   }
344 
345   // Check the substitutions used are valid for this purpose.
346   if (!EnsureValidSubstitutions(outputs.required_types(),
347                                 &IsValidSourceSubstitution, value->origin(),
348                                 err_))
349     return false;
350 
351   // Validate that outputs are in the output dir.
352   CHECK(outputs.list().size() == value->list_value().size());
353   for (size_t i = 0; i < outputs.list().size(); i++) {
354     if (!EnsureSubstitutionIsInOutputDir(outputs.list()[i],
355                                          value->list_value()[i]))
356       return false;
357   }
358   return true;
359 }
360 
FillCheckIncludes()361 bool TargetGenerator::FillCheckIncludes() {
362   const Value* value = scope_->GetValue(variables::kCheckIncludes, true);
363   if (!value)
364     return true;
365   if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
366     return false;
367   target_->set_check_includes(value->boolean_value());
368   return true;
369 }
370 
FillOutputExtension()371 bool TargetGenerator::FillOutputExtension() {
372   const Value* value = scope_->GetValue(variables::kOutputExtension, true);
373   if (!value)
374     return true;
375   if (!value->VerifyTypeIs(Value::STRING, err_))
376     return false;
377   target_->set_output_extension(value->string_value());
378   return true;
379 }
380 
EnsureSubstitutionIsInOutputDir(const SubstitutionPattern & pattern,const Value & original_value)381 bool TargetGenerator::EnsureSubstitutionIsInOutputDir(
382     const SubstitutionPattern& pattern,
383     const Value& original_value) {
384   if (pattern.ranges().empty()) {
385     // Pattern is empty, error out (this prevents weirdness below).
386     *err_ = Err(original_value, "This has an empty value in it.");
387     return false;
388   }
389 
390   if (pattern.ranges()[0].type == &SubstitutionLiteral) {
391     // If the first thing is a literal, it must start with the output dir.
392     if (!EnsureStringIsInOutputDir(GetBuildSettings()->build_dir(),
393                                    pattern.ranges()[0].literal,
394                                    original_value.origin(), err_))
395       return false;
396   } else {
397     // Otherwise, the first subrange must be a pattern that expands to
398     // something in the output directory.
399     if (!SubstitutionIsInOutputDir(pattern.ranges()[0].type)) {
400       *err_ =
401           Err(original_value, "File is not inside output directory.",
402               "The given file should be in the output directory. Normally you\n"
403               "would specify\n\"$target_out_dir/foo\" or "
404               "\"{{source_gen_dir}}/foo\".");
405       return false;
406     }
407   }
408 
409   return true;
410 }
411 
FillGenericConfigs(const char * var_name,UniqueVector<LabelConfigPair> * dest)412 bool TargetGenerator::FillGenericConfigs(const char* var_name,
413                                          UniqueVector<LabelConfigPair>* dest) {
414   const Value* value = scope_->GetValue(var_name, true);
415   if (value) {
416     ExtractListOfUniqueLabels(scope_->settings()->build_settings(), *value,
417                               scope_->GetSourceDir(),
418                               ToolchainLabelForScope(scope_), dest, err_);
419   }
420   return !err_->has_error();
421 }
422 
FillGenericDeps(const char * var_name,LabelTargetVector * dest)423 bool TargetGenerator::FillGenericDeps(const char* var_name,
424                                       LabelTargetVector* dest) {
425   const Value* value = scope_->GetValue(var_name, true);
426   if (value) {
427     ExtractListOfLabels(scope_->settings()->build_settings(), *value,
428                         scope_->GetSourceDir(), ToolchainLabelForScope(scope_),
429                         dest, err_);
430   }
431   return !err_->has_error();
432 }
433 
FillWriteRuntimeDeps()434 bool TargetGenerator::FillWriteRuntimeDeps() {
435   const Value* value = scope_->GetValue(variables::kWriteRuntimeDeps, true);
436   if (!value)
437     return true;
438 
439   // Compute the file name and make sure it's in the output dir.
440   SourceFile source_file = scope_->GetSourceDir().ResolveRelativeFile(
441       *value, err_, GetBuildSettings()->root_path_utf8());
442   if (err_->has_error())
443     return false;
444   if (!EnsureStringIsInOutputDir(GetBuildSettings()->build_dir(),
445                                  source_file.value(), value->origin(), err_))
446     return false;
447   OutputFile output_file(GetBuildSettings(), source_file);
448   target_->set_write_runtime_deps_output(output_file);
449 
450   return true;
451 }
452