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 (!ValidateSources())
68 return;
69
70 if (target_->source_types_used().RustSourceUsed()) {
71 RustValuesGenerator rustgen(target_, scope_, function_call_, err_);
72 rustgen.Run();
73 if (err_->has_error())
74 return;
75 }
76
77 if (target_->source_types_used().SwiftSourceUsed()) {
78 SwiftValuesGenerator swiftgen(target_, scope_, err_);
79 swiftgen.Run();
80 if (err_->has_error())
81 return;
82 }
83
84 // Config values (compiler flags, etc.) set directly on this target.
85 ConfigValuesGenerator gen(&target_->config_values(), scope_,
86 scope_->GetSourceDir(), err_);
87 gen.Run();
88 if (err_->has_error())
89 return;
90 }
91
FillSources()92 bool BinaryTargetGenerator::FillSources() {
93 bool ret = TargetGenerator::FillSources();
94 for (std::size_t i = 0; i < target_->sources().size(); ++i) {
95 const auto& source = target_->sources()[i];
96 const SourceFile::Type source_type = source.GetType();
97 switch (source_type) {
98 case SourceFile::SOURCE_CPP:
99 case SourceFile::SOURCE_MODULEMAP:
100 case SourceFile::SOURCE_H:
101 case SourceFile::SOURCE_C:
102 case SourceFile::SOURCE_M:
103 case SourceFile::SOURCE_MM:
104 case SourceFile::SOURCE_S:
105 case SourceFile::SOURCE_ASM:
106 case SourceFile::SOURCE_O:
107 case SourceFile::SOURCE_DEF:
108 case SourceFile::SOURCE_GO:
109 case SourceFile::SOURCE_RS:
110 case SourceFile::SOURCE_RC:
111 case SourceFile::SOURCE_SWIFT:
112 // These are allowed.
113 break;
114 case SourceFile::SOURCE_UNKNOWN:
115 case SourceFile::SOURCE_SWIFTMODULE:
116 case SourceFile::SOURCE_NUMTYPES:
117 *err_ =
118 Err(scope_->GetValue(variables::kSources, true)->list_value()[i],
119 std::string("Only source, header, and object files belong in "
120 "the sources of a ") +
121 Target::GetStringForOutputType(target_->output_type()) +
122 ". " + source.value() + " is not one of the valid types.");
123 }
124
125 target_->source_types_used().Set(source_type);
126 }
127 return ret;
128 }
129
FillCompleteStaticLib()130 bool BinaryTargetGenerator::FillCompleteStaticLib() {
131 if (target_->output_type() == Target::STATIC_LIBRARY) {
132 const Value* value = scope_->GetValue(variables::kCompleteStaticLib, true);
133 if (!value)
134 return true;
135 if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
136 return false;
137 target_->set_complete_static_lib(value->boolean_value());
138 }
139 return true;
140 }
141
FillFriends()142 bool BinaryTargetGenerator::FillFriends() {
143 const Value* value = scope_->GetValue(variables::kFriend, true);
144 if (value) {
145 return ExtractListOfLabelPatterns(scope_->settings()->build_settings(),
146 *value, scope_->GetSourceDir(),
147 &target_->friends(), err_);
148 }
149 return true;
150 }
151
FillOutputName()152 bool BinaryTargetGenerator::FillOutputName() {
153 const Value* value = scope_->GetValue(variables::kOutputName, true);
154 if (!value)
155 return true;
156 if (!value->VerifyTypeIs(Value::STRING, err_))
157 return false;
158 target_->set_output_name(value->string_value());
159 return true;
160 }
161
FillOutputPrefixOverride()162 bool BinaryTargetGenerator::FillOutputPrefixOverride() {
163 const Value* value = scope_->GetValue(variables::kOutputPrefixOverride, true);
164 if (!value)
165 return true;
166 if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
167 return false;
168 target_->set_output_prefix_override(value->boolean_value());
169 return true;
170 }
171
FillOutputDir()172 bool BinaryTargetGenerator::FillOutputDir() {
173 const Value* value = scope_->GetValue(variables::kOutputDir, true);
174 if (!value)
175 return true;
176 if (!value->VerifyTypeIs(Value::STRING, err_))
177 return false;
178
179 if (value->string_value().empty())
180 return true; // Treat empty string as the default and do nothing.
181
182 const BuildSettings* build_settings = scope_->settings()->build_settings();
183 SourceDir dir = scope_->GetSourceDir().ResolveRelativeDir(
184 *value, err_, build_settings->root_path_utf8());
185 if (err_->has_error())
186 return false;
187
188 if (!EnsureStringIsInOutputDir(build_settings->build_dir(), dir.value(),
189 value->origin(), err_))
190 return false;
191 target_->set_output_dir(dir);
192 return true;
193 }
194
FillAllowCircularIncludesFrom()195 bool BinaryTargetGenerator::FillAllowCircularIncludesFrom() {
196 const Value* value =
197 scope_->GetValue(variables::kAllowCircularIncludesFrom, true);
198 if (!value)
199 return true;
200
201 UniqueVector<Label> circular;
202 ExtractListOfUniqueLabels(scope_->settings()->build_settings(), *value,
203 scope_->GetSourceDir(),
204 ToolchainLabelForScope(scope_), &circular, err_);
205 if (err_->has_error())
206 return false;
207
208 // Validate that all circular includes entries are in the deps.
209 for (const auto& cur : circular) {
210 bool found_dep = false;
211 for (const auto& dep_pair : target_->GetDeps(Target::DEPS_LINKED)) {
212 if (dep_pair.label == cur) {
213 found_dep = true;
214 break;
215 }
216 }
217 if (!found_dep) {
218 *err_ = Err(*value, "Label not in deps.",
219 "The label \"" + cur.GetUserVisibleName(false) +
220 "\"\nwas not in the deps of this target. "
221 "allow_circular_includes_from only allows\ntargets "
222 "present in the "
223 "deps.");
224 return false;
225 }
226 }
227
228 // Add to the set.
229 for (const auto& cur : circular)
230 target_->allow_circular_includes_from().insert(cur);
231 return true;
232 }
233
ValidateSources()234 bool BinaryTargetGenerator::ValidateSources() {
235 // For Rust targets, if the only source file is the root `sources` can be
236 // omitted/empty.
237 if (scope_->GetValue(variables::kRustCrateRoot, false)) {
238 target_->source_types_used().Set(SourceFile::SOURCE_RS);
239 }
240
241 if (target_->source_types_used().MixedSourceUsed()) {
242 *err_ =
243 Err(function_call_, "More than one language used in target sources.",
244 "Mixed sources are not allowed, unless they are "
245 "compilation-compatible (e.g. Objective C and C++).");
246 return false;
247 }
248 return true;
249 }
250