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