1 // Copyright 2014 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/tool.h"
6
7 #include "gn/builtin_tool.h"
8 #include "gn/c_tool.h"
9 #include "gn/general_tool.h"
10 #include "gn/rust_tool.h"
11 #include "gn/settings.h"
12 #include "gn/target.h"
13
14 const char* Tool::kToolNone = "";
15
Tool(const char * n)16 Tool::Tool(const char* n) : name_(n) {}
17
18 Tool::~Tool() = default;
19
SetToolComplete()20 void Tool::SetToolComplete() {
21 DCHECK(!complete_);
22 complete_ = true;
23
24 command_.FillRequiredTypes(&substitution_bits_);
25 depfile_.FillRequiredTypes(&substitution_bits_);
26 description_.FillRequiredTypes(&substitution_bits_);
27 outputs_.FillRequiredTypes(&substitution_bits_);
28 rspfile_.FillRequiredTypes(&substitution_bits_);
29 rspfile_content_.FillRequiredTypes(&substitution_bits_);
30 partial_outputs_.FillRequiredTypes(&substitution_bits_);
31 }
32
AsGeneral()33 GeneralTool* Tool::AsGeneral() {
34 return nullptr;
35 }
36
AsGeneral() const37 const GeneralTool* Tool::AsGeneral() const {
38 return nullptr;
39 }
40
AsC()41 CTool* Tool::AsC() {
42 return nullptr;
43 }
44
AsC() const45 const CTool* Tool::AsC() const {
46 return nullptr;
47 }
48
AsRust()49 RustTool* Tool::AsRust() {
50 return nullptr;
51 }
AsRust() const52 const RustTool* Tool::AsRust() const {
53 return nullptr;
54 }
55
AsBuiltin()56 BuiltinTool* Tool::AsBuiltin() {
57 return nullptr;
58 }
AsBuiltin() const59 const BuiltinTool* Tool::AsBuiltin() const {
60 return nullptr;
61 }
62
IsPatternInOutputList(const SubstitutionList & output_list,const SubstitutionPattern & pattern) const63 bool Tool::IsPatternInOutputList(const SubstitutionList& output_list,
64 const SubstitutionPattern& pattern) const {
65 for (const auto& cur : output_list.list()) {
66 if (pattern.ranges().size() == cur.ranges().size() &&
67 std::equal(pattern.ranges().begin(), pattern.ranges().end(),
68 cur.ranges().begin()))
69 return true;
70 }
71 return false;
72 }
73
ValidateSubstitutionList(const std::vector<const Substitution * > & list,const Value * origin,Err * err) const74 bool Tool::ValidateSubstitutionList(
75 const std::vector<const Substitution*>& list,
76 const Value* origin,
77 Err* err) const {
78 for (const auto& cur_type : list) {
79 if (!ValidateSubstitution(cur_type)) {
80 *err = Err(*origin, "Pattern not valid here.",
81 "You used the pattern " + std::string(cur_type->name) +
82 " which is not valid\nfor this variable.");
83 return false;
84 }
85 }
86 return true;
87 }
88
ReadBool(Scope * scope,const char * var,bool * field,Err * err)89 bool Tool::ReadBool(Scope* scope, const char* var, bool* field, Err* err) {
90 DCHECK(!complete_);
91 const Value* v = scope->GetValue(var, true);
92 if (!v)
93 return true; // Not present is fine.
94 if (!v->VerifyTypeIs(Value::BOOLEAN, err))
95 return false;
96 *field = v->boolean_value();
97 return true;
98 }
99
ReadString(Scope * scope,const char * var,std::string * field,Err * err)100 bool Tool::ReadString(Scope* scope,
101 const char* var,
102 std::string* field,
103 Err* err) {
104 DCHECK(!complete_);
105 const Value* v = scope->GetValue(var, true);
106 if (!v)
107 return true; // Not present is fine.
108 if (!v->VerifyTypeIs(Value::STRING, err))
109 return false;
110 *field = v->string_value();
111 return true;
112 }
113
ReadPattern(Scope * scope,const char * var,SubstitutionPattern * field,Err * err)114 bool Tool::ReadPattern(Scope* scope,
115 const char* var,
116 SubstitutionPattern* field,
117 Err* err) {
118 DCHECK(!complete_);
119 const Value* value = scope->GetValue(var, true);
120 if (!value)
121 return true; // Not present is fine.
122 if (!value->VerifyTypeIs(Value::STRING, err))
123 return false;
124
125 SubstitutionPattern pattern;
126 if (!pattern.Parse(*value, err))
127 return false;
128 if (!ValidateSubstitutionList(pattern.required_types(), value, err))
129 return false;
130
131 *field = std::move(pattern);
132 return true;
133 }
134
ReadPatternList(Scope * scope,const char * var,SubstitutionList * field,Err * err)135 bool Tool::ReadPatternList(Scope* scope,
136 const char* var,
137 SubstitutionList* field,
138 Err* err) {
139 DCHECK(!complete_);
140 const Value* value = scope->GetValue(var, true);
141 if (!value)
142 return true; // Not present is fine.
143 if (!value->VerifyTypeIs(Value::LIST, err))
144 return false;
145
146 SubstitutionList list;
147 if (!list.Parse(*value, err))
148 return false;
149
150 // Validate the right kinds of patterns are used.
151 if (!ValidateSubstitutionList(list.required_types(), value, err))
152 return false;
153
154 *field = std::move(list);
155 return true;
156 }
157
ReadLabel(Scope * scope,const char * var,const Label & current_toolchain,LabelPtrPair<Pool> * field,Err * err)158 bool Tool::ReadLabel(Scope* scope,
159 const char* var,
160 const Label& current_toolchain,
161 LabelPtrPair<Pool>* field,
162 Err* err) {
163 DCHECK(!complete_);
164 const Value* v = scope->GetValue(var, true);
165 if (!v)
166 return true; // Not present is fine.
167
168 Label label =
169 Label::Resolve(scope->GetSourceDir(),
170 scope->settings()->build_settings()->root_path_utf8(),
171 current_toolchain, *v, err);
172 if (err->has_error())
173 return false;
174
175 LabelPtrPair<Pool> pair(label);
176 pair.origin = defined_from();
177
178 *field = std::move(pair);
179 return true;
180 }
181
ReadOutputExtension(Scope * scope,Err * err)182 bool Tool::ReadOutputExtension(Scope* scope, Err* err) {
183 DCHECK(!complete_);
184 const Value* value = scope->GetValue("default_output_extension", true);
185 if (!value)
186 return true; // Not present is fine.
187 if (!value->VerifyTypeIs(Value::STRING, err))
188 return false;
189
190 if (value->string_value().empty())
191 return true; // Accept empty string.
192
193 if (value->string_value()[0] != '.') {
194 *err = Err(*value, "default_output_extension must begin with a '.'");
195 return false;
196 }
197
198 set_default_output_extension(value->string_value());
199 return true;
200 }
201
InitTool(Scope * scope,Toolchain * toolchain,Err * err)202 bool Tool::InitTool(Scope* scope, Toolchain* toolchain, Err* err) {
203 if (!ReadPattern(scope, "command", &command_, err) ||
204 !ReadString(scope, "command_launcher", &command_launcher_, err) ||
205 !ReadOutputExtension(scope, err) ||
206 !ReadPattern(scope, "depfile", &depfile_, err) ||
207 !ReadPattern(scope, "description", &description_, err) ||
208 !ReadPatternList(scope, "runtime_outputs", &runtime_outputs_, err) ||
209 !ReadString(scope, "output_prefix", &output_prefix_, err) ||
210 !ReadPattern(scope, "default_output_dir", &default_output_dir_, err) ||
211 !ReadBool(scope, "restat", &restat_, err) ||
212 !ReadPattern(scope, "rspfile", &rspfile_, err) ||
213 !ReadPattern(scope, "rspfile_content", &rspfile_content_, err) ||
214 !ReadLabel(scope, "pool", toolchain->label(), &pool_, err)) {
215 return false;
216 }
217 const bool command_is_required = name_ != GeneralTool::kGeneralToolAction;
218 if (command_.empty() == command_is_required) {
219 *err = Err(defined_from(), "This tool's command is bad.",
220 command_is_required
221 ? "This tool requires \"command\" to be defined."
222 : "This tool doesn't support \"command\".");
223 return false;
224 }
225 return true;
226 }
227
CreateTool(const ParseNode * function,const std::string & name,Scope * scope,Toolchain * toolchain,Err * err)228 std::unique_ptr<Tool> Tool::CreateTool(const ParseNode* function,
229 const std::string& name,
230 Scope* scope,
231 Toolchain* toolchain,
232 Err* err) {
233 std::unique_ptr<Tool> tool = CreateTool(name);
234 if (!tool) {
235 *err = Err(function, "Unknown tool type.");
236 return nullptr;
237 }
238 if (CTool* c_tool = tool->AsC()) {
239 if (c_tool->InitTool(scope, toolchain, err))
240 return tool;
241 return nullptr;
242 }
243 if (GeneralTool* general_tool = tool->AsGeneral()) {
244 if (general_tool->InitTool(scope, toolchain, err))
245 return tool;
246 return nullptr;
247 }
248 if (RustTool* rust_tool = tool->AsRust()) {
249 if (rust_tool->InitTool(scope, toolchain, err))
250 return tool;
251 return nullptr;
252 }
253 NOTREACHED();
254 *err = Err(function, "Unknown tool type.");
255 return nullptr;
256 }
257
258 // static
CreateTool(const std::string & name)259 std::unique_ptr<Tool> Tool::CreateTool(const std::string& name) {
260 // C tools
261 if (name == CTool::kCToolCc)
262 return std::make_unique<CTool>(CTool::kCToolCc);
263 else if (name == CTool::kCToolCxx)
264 return std::make_unique<CTool>(CTool::kCToolCxx);
265 else if (name == CTool::kCToolCxxModule)
266 return std::make_unique<CTool>(CTool::kCToolCxxModule);
267 else if (name == CTool::kCToolObjC)
268 return std::make_unique<CTool>(CTool::kCToolObjC);
269 else if (name == CTool::kCToolObjCxx)
270 return std::make_unique<CTool>(CTool::kCToolObjCxx);
271 else if (name == CTool::kCToolRc)
272 return std::make_unique<CTool>(CTool::kCToolRc);
273 else if (name == CTool::kCToolAsm)
274 return std::make_unique<CTool>(CTool::kCToolAsm);
275 else if (name == CTool::kCToolSwift)
276 return std::make_unique<CTool>(CTool::kCToolSwift);
277 else if (name == CTool::kCToolAlink)
278 return std::make_unique<CTool>(CTool::kCToolAlink);
279 else if (name == CTool::kCToolSolink)
280 return std::make_unique<CTool>(CTool::kCToolSolink);
281 else if (name == CTool::kCToolSolinkModule)
282 return std::make_unique<CTool>(CTool::kCToolSolinkModule);
283 else if (name == CTool::kCToolLink)
284 return std::make_unique<CTool>(CTool::kCToolLink);
285
286 // General tools
287 else if (name == GeneralTool::kGeneralToolAction)
288 return std::make_unique<GeneralTool>(GeneralTool::kGeneralToolAction);
289 else if (name == GeneralTool::kGeneralToolStamp)
290 return std::make_unique<GeneralTool>(GeneralTool::kGeneralToolStamp);
291 else if (name == GeneralTool::kGeneralToolCopy)
292 return std::make_unique<GeneralTool>(GeneralTool::kGeneralToolCopy);
293 else if (name == GeneralTool::kGeneralToolCopyBundleData)
294 return std::make_unique<GeneralTool>(
295 GeneralTool::kGeneralToolCopyBundleData);
296 else if (name == GeneralTool::kGeneralToolCompileXCAssets)
297 return std::make_unique<GeneralTool>(
298 GeneralTool::kGeneralToolCompileXCAssets);
299
300 // Rust tool
301 else if (name == RustTool::kRsToolBin)
302 return std::make_unique<RustTool>(RustTool::kRsToolBin);
303 else if (name == RustTool::kRsToolCDylib)
304 return std::make_unique<RustTool>(RustTool::kRsToolCDylib);
305 else if (name == RustTool::kRsToolDylib)
306 return std::make_unique<RustTool>(RustTool::kRsToolDylib);
307 else if (name == RustTool::kRsToolMacro)
308 return std::make_unique<RustTool>(RustTool::kRsToolMacro);
309 else if (name == RustTool::kRsToolRlib)
310 return std::make_unique<RustTool>(RustTool::kRsToolRlib);
311 else if (name == RustTool::kRsToolStaticlib)
312 return std::make_unique<RustTool>(RustTool::kRsToolStaticlib);
313
314 return nullptr;
315 }
316
317 // static
GetToolTypeForSourceType(SourceFile::Type type)318 const char* Tool::GetToolTypeForSourceType(SourceFile::Type type) {
319 switch (type) {
320 case SourceFile::SOURCE_C:
321 return CTool::kCToolCc;
322 case SourceFile::SOURCE_CPP:
323 return CTool::kCToolCxx;
324 case SourceFile::SOURCE_MODULEMAP:
325 return CTool::kCToolCxxModule;
326 case SourceFile::SOURCE_M:
327 return CTool::kCToolObjC;
328 case SourceFile::SOURCE_MM:
329 return CTool::kCToolObjCxx;
330 case SourceFile::SOURCE_ASM:
331 case SourceFile::SOURCE_S:
332 return CTool::kCToolAsm;
333 case SourceFile::SOURCE_RC:
334 return CTool::kCToolRc;
335 case SourceFile::SOURCE_RS:
336 return RustTool::kRsToolBin;
337 case SourceFile::SOURCE_SWIFT:
338 return CTool::kCToolSwift;
339 case SourceFile::SOURCE_UNKNOWN:
340 case SourceFile::SOURCE_H:
341 case SourceFile::SOURCE_O:
342 case SourceFile::SOURCE_DEF:
343 case SourceFile::SOURCE_GO:
344 return kToolNone;
345 default:
346 NOTREACHED();
347 return kToolNone;
348 }
349 }
350
351 // static
GetToolTypeForTargetFinalOutput(const Target * target)352 const char* Tool::GetToolTypeForTargetFinalOutput(const Target* target) {
353 // The contents of this list might be surprising (i.e. phony tool for copy
354 // rules). See the header for why.
355 // TODO(crbug.com/gn/39): Don't emit stamp files for single-output targets.
356 if (target->source_types_used().RustSourceUsed()) {
357 switch (target->rust_values().InferredCrateType(target)) {
358 case RustValues::CRATE_BIN:
359 return RustTool::kRsToolBin;
360 case RustValues::CRATE_CDYLIB:
361 return RustTool::kRsToolCDylib;
362 case RustValues::CRATE_DYLIB:
363 return RustTool::kRsToolDylib;
364 case RustValues::CRATE_PROC_MACRO:
365 return RustTool::kRsToolMacro;
366 case RustValues::CRATE_RLIB:
367 return RustTool::kRsToolRlib;
368 case RustValues::CRATE_STATICLIB:
369 return RustTool::kRsToolStaticlib;
370 case RustValues::CRATE_AUTO:
371 break;
372 default:
373 NOTREACHED();
374 }
375 }
376 switch (target->output_type()) {
377 case Target::EXECUTABLE:
378 return CTool::kCToolLink;
379 case Target::SHARED_LIBRARY:
380 return CTool::kCToolSolink;
381 case Target::LOADABLE_MODULE:
382 return CTool::kCToolSolinkModule;
383 case Target::STATIC_LIBRARY:
384 return CTool::kCToolAlink;
385 case Target::ACTION:
386 case Target::ACTION_FOREACH:
387 case Target::BUNDLE_DATA:
388 case Target::COPY_FILES:
389 case Target::CREATE_BUNDLE:
390 case Target::GENERATED_FILE:
391 case Target::GROUP:
392 case Target::SOURCE_SET:
393 if (target->settings()->build_settings()->no_stamp_files()) {
394 return BuiltinTool::kBuiltinToolPhony;
395 } else {
396 return GeneralTool::kGeneralToolStamp;
397 }
398 default:
399 NOTREACHED();
400 return kToolNone;
401 }
402 }
403