• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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