• 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/binary_target_generator.h"
6 
7 #include "gn/config_values_generator.h"
8 #include "gn/deps_iterator.h"
9 #include "gn/err.h"
10 #include "gn/filesystem_utils.h"
11 #include "gn/functions.h"
12 #include "gn/parse_tree.h"
13 #include "gn/rust_values_generator.h"
14 #include "gn/rust_variables.h"
15 #include "gn/scope.h"
16 #include "gn/settings.h"
17 #include "gn/swift_values_generator.h"
18 #include "gn/value_extractors.h"
19 #include "gn/variables.h"
20 
BinaryTargetGenerator(Target * target,Scope * scope,const FunctionCallNode * function_call,Target::OutputType type,Err * err)21 BinaryTargetGenerator::BinaryTargetGenerator(
22     Target* target,
23     Scope* scope,
24     const FunctionCallNode* function_call,
25     Target::OutputType type,
26     Err* err)
27     : TargetGenerator(target, scope, function_call, err), output_type_(type) {}
28 
29 BinaryTargetGenerator::~BinaryTargetGenerator() = default;
30 
DoRun()31 void BinaryTargetGenerator::DoRun() {
32   target_->set_output_type(output_type_);
33 
34   if (!FillOutputName())
35     return;
36 
37   if (!FillOutputPrefixOverride())
38     return;
39 
40   if (!FillOutputDir())
41     return;
42 
43   if (!FillOutputExtension())
44     return;
45 
46   if (!FillSources())
47     return;
48 
49   if (!FillPublic())
50     return;
51 
52   if (!FillFriends())
53     return;
54 
55   if (!FillCheckIncludes())
56     return;
57 
58   if (!FillConfigs())
59     return;
60 
61   if (!FillAllowCircularIncludesFrom())
62     return;
63 
64   if (!FillCompleteStaticLib())
65     return;
66 
67   if (!FillPool())
68     return;
69 
70   if (!ValidateSources())
71     return;
72 
73   if (target_->source_types_used().RustSourceUsed()) {
74     RustValuesGenerator rustgen(target_, scope_, function_call_, err_);
75     rustgen.Run();
76     if (err_->has_error())
77       return;
78   }
79 
80   if (target_->source_types_used().SwiftSourceUsed()) {
81     SwiftValuesGenerator swiftgen(target_, scope_, err_);
82     swiftgen.Run();
83     if (err_->has_error())
84       return;
85   }
86 
87   // Config values (compiler flags, etc.) set directly on this target.
88   ConfigValuesGenerator gen(&target_->config_values(), scope_,
89                             scope_->GetSourceDir(), err_);
90   gen.Run();
91   if (err_->has_error())
92     return;
93 }
94 
FillSources()95 bool BinaryTargetGenerator::FillSources() {
96   bool ret = TargetGenerator::FillSources();
97   for (std::size_t i = 0; i < target_->sources().size(); ++i) {
98     const auto& source = target_->sources()[i];
99     const SourceFile::Type source_type = source.GetType();
100     switch (source_type) {
101       case SourceFile::SOURCE_CPP:
102       case SourceFile::SOURCE_MODULEMAP:
103       case SourceFile::SOURCE_H:
104       case SourceFile::SOURCE_C:
105       case SourceFile::SOURCE_M:
106       case SourceFile::SOURCE_MM:
107       case SourceFile::SOURCE_S:
108       case SourceFile::SOURCE_ASM:
109       case SourceFile::SOURCE_O:
110       case SourceFile::SOURCE_DEF:
111       case SourceFile::SOURCE_GO:
112       case SourceFile::SOURCE_RS:
113       case SourceFile::SOURCE_RC:
114       case SourceFile::SOURCE_SWIFT:
115         // These are allowed.
116         break;
117       case SourceFile::SOURCE_UNKNOWN:
118       case SourceFile::SOURCE_SWIFTMODULE:
119       case SourceFile::SOURCE_NUMTYPES:
120         *err_ =
121             Err(scope_->GetValue(variables::kSources, true)->list_value()[i],
122                 std::string("Only source, header, and object files belong in "
123                             "the sources of a ") +
124                     Target::GetStringForOutputType(target_->output_type()) +
125                     ". " + source.value() + " is not one of the valid types.");
126     }
127 
128     target_->source_types_used().Set(source_type);
129   }
130   return ret;
131 }
132 
FillCompleteStaticLib()133 bool BinaryTargetGenerator::FillCompleteStaticLib() {
134   if (target_->output_type() == Target::STATIC_LIBRARY) {
135     const Value* value = scope_->GetValue(variables::kCompleteStaticLib, true);
136     if (!value)
137       return true;
138     if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
139       return false;
140     target_->set_complete_static_lib(value->boolean_value());
141   }
142   return true;
143 }
144 
FillFriends()145 bool BinaryTargetGenerator::FillFriends() {
146   const Value* value = scope_->GetValue(variables::kFriend, true);
147   if (value) {
148     return ExtractListOfLabelPatterns(scope_->settings()->build_settings(),
149                                       *value, scope_->GetSourceDir(),
150                                       &target_->friends(), err_);
151   }
152   return true;
153 }
154 
FillOutputName()155 bool BinaryTargetGenerator::FillOutputName() {
156   const Value* value = scope_->GetValue(variables::kOutputName, true);
157   if (!value)
158     return true;
159   if (!value->VerifyTypeIs(Value::STRING, err_))
160     return false;
161   target_->set_output_name(value->string_value());
162   return true;
163 }
164 
FillOutputPrefixOverride()165 bool BinaryTargetGenerator::FillOutputPrefixOverride() {
166   const Value* value = scope_->GetValue(variables::kOutputPrefixOverride, true);
167   if (!value)
168     return true;
169   if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
170     return false;
171   target_->set_output_prefix_override(value->boolean_value());
172   return true;
173 }
174 
FillOutputDir()175 bool BinaryTargetGenerator::FillOutputDir() {
176   const Value* value = scope_->GetValue(variables::kOutputDir, true);
177   if (!value)
178     return true;
179   if (!value->VerifyTypeIs(Value::STRING, err_))
180     return false;
181 
182   if (value->string_value().empty())
183     return true;  // Treat empty string as the default and do nothing.
184 
185   const BuildSettings* build_settings = scope_->settings()->build_settings();
186   SourceDir dir = scope_->GetSourceDir().ResolveRelativeDir(
187       *value, err_, build_settings->root_path_utf8());
188   if (err_->has_error())
189     return false;
190 
191   if (!EnsureStringIsInOutputDir(build_settings->build_dir(), dir.value(),
192                                  value->origin(), err_))
193     return false;
194   target_->set_output_dir(dir);
195   return true;
196 }
197 
FillAllowCircularIncludesFrom()198 bool BinaryTargetGenerator::FillAllowCircularIncludesFrom() {
199   const Value* value =
200       scope_->GetValue(variables::kAllowCircularIncludesFrom, true);
201   if (!value)
202     return true;
203 
204   UniqueVector<Label> circular;
205   ExtractListOfUniqueLabels(scope_->settings()->build_settings(), *value,
206                             scope_->GetSourceDir(),
207                             ToolchainLabelForScope(scope_), &circular, err_);
208   if (err_->has_error())
209     return false;
210 
211   // Validate that all circular includes entries are in the deps.
212   for (const auto& cur : circular) {
213     bool found_dep = false;
214     for (const auto& dep_pair : target_->GetDeps(Target::DEPS_LINKED)) {
215       if (dep_pair.label == cur) {
216         found_dep = true;
217         break;
218       }
219     }
220     if (!found_dep) {
221       bool with_toolchain =
222           scope_->settings()->ShouldShowToolchain({&target_->label(), &cur});
223       *err_ = Err(*value, "Label not in deps.",
224                   "The label \"" + cur.GetUserVisibleName(with_toolchain) +
225                       "\"\nwas not in the deps of this target. "
226                       "allow_circular_includes_from only allows\ntargets "
227                       "present in the "
228                       "deps.");
229       return false;
230     }
231   }
232 
233   // Add to the set.
234   for (const auto& cur : circular)
235     target_->allow_circular_includes_from().insert(cur);
236   return true;
237 }
238 
FillPool()239 bool BinaryTargetGenerator::FillPool() {
240   const Value* value = scope_->GetValue(variables::kPool, true);
241   if (!value)
242     return true;
243 
244   Label label =
245       Label::Resolve(scope_->GetSourceDir(),
246                      scope_->settings()->build_settings()->root_path_utf8(),
247                      ToolchainLabelForScope(scope_), *value, err_);
248   if (err_->has_error())
249     return false;
250 
251   LabelPtrPair<Pool> pair(label);
252   pair.origin = target_->defined_from();
253 
254   target_->set_pool(std::move(pair));
255   return true;
256 }
257 
ValidateSources()258 bool BinaryTargetGenerator::ValidateSources() {
259   // For Rust targets, if the only source file is the root `sources` can be
260   // omitted/empty.
261   if (scope_->GetValue(variables::kRustCrateRoot, false)) {
262     target_->source_types_used().Set(SourceFile::SOURCE_RS);
263   }
264 
265   if (target_->source_types_used().MixedSourceUsed()) {
266     *err_ =
267         Err(function_call_, "More than one language used in target sources.",
268             "Mixed sources are not allowed, unless they are "
269             "compilation-compatible (e.g. Objective C and C++).");
270     return false;
271   }
272   return true;
273 }
274