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