• 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/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