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