• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/test_with_scope.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "gn/parser.h"
11 #include "gn/tokenizer.h"
12 
13 namespace {
14 
CreateBuildSettingsForTest()15 BuildSettings CreateBuildSettingsForTest() {
16   BuildSettings build_settings;
17   build_settings.SetBuildDir(SourceDir("//out/Debug/"));
18   return build_settings;
19 }
20 
21 }  // namespace
22 
TestWithScope()23 TestWithScope::TestWithScope()
24     : build_settings_(CreateBuildSettingsForTest()),
25       settings_(&build_settings_, std::string()),
26       toolchain_(&settings_, Label(SourceDir("//toolchain/"), "default")),
27       scope_(&settings_),
28       scope_progammatic_provider_(&scope_, true) {
29   build_settings_.set_print_callback(
30       [this](const std::string& str) { AppendPrintOutput(str); });
31 
32   settings_.set_toolchain_label(toolchain_.label());
33   settings_.set_default_toolchain_label(toolchain_.label());
34 
35   SetupToolchain(&toolchain_);
36   scope_.set_item_collector(&items_);
37 }
38 
39 TestWithScope::~TestWithScope() = default;
40 
ParseLabel(const std::string & str) const41 Label TestWithScope::ParseLabel(const std::string& str) const {
42   Err err;
43   Label result = Label::Resolve(SourceDir("//"), std::string_view(),
44                                 toolchain_.label(), Value(nullptr, str), &err);
45   CHECK(!err.has_error());
46   return result;
47 }
48 
ExecuteSnippet(const std::string & str,Err * err)49 bool TestWithScope::ExecuteSnippet(const std::string& str, Err* err) {
50   TestParseInput input(str);
51   if (input.has_error()) {
52     *err = input.parse_err();
53     return false;
54   }
55 
56   size_t first_item = items_.size();
57   input.parsed()->Execute(&scope_, err);
58   if (err->has_error())
59     return false;
60 
61   for (size_t i = first_item; i < items_.size(); ++i) {
62     CHECK(items_[i]->AsTarget() != nullptr)
63         << "Only targets are supported in ExecuteSnippet()";
64     items_[i]->AsTarget()->SetToolchain(&toolchain_);
65     if (!items_[i]->OnResolved(err))
66       return false;
67   }
68   return true;
69 }
70 
ExecuteExpression(const std::string & expr,Err * err)71 Value TestWithScope::ExecuteExpression(const std::string& expr, Err* err) {
72   InputFile input_file(SourceFile("//test"));
73   input_file.SetContents(expr);
74 
75   std::vector<Token> tokens = Tokenizer::Tokenize(&input_file, err);
76   if (err->has_error()) {
77     return Value();
78   }
79   std::unique_ptr<ParseNode> node = Parser::ParseExpression(tokens, err);
80   if (err->has_error()) {
81     return Value();
82   }
83 
84   return node->Execute(&scope_, err);
85 }
86 
87 // static
SetupToolchain(Toolchain * toolchain,bool use_toc)88 void TestWithScope::SetupToolchain(Toolchain* toolchain, bool use_toc) {
89   Err err;
90 
91   // CC
92   std::unique_ptr<Tool> cc_tool = Tool::CreateTool(CTool::kCToolCc);
93   SetCommandForTool(
94       "cc {{source}} {{cflags}} {{cflags_c}} {{defines}} {{include_dirs}} "
95       "-o {{output}}",
96       cc_tool.get());
97   cc_tool->set_outputs(SubstitutionList::MakeForTest(
98       "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
99   toolchain->SetTool(std::move(cc_tool));
100 
101   // CXX
102   std::unique_ptr<Tool> cxx_tool = Tool::CreateTool(CTool::kCToolCxx);
103   SetCommandForTool(
104       "c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} {{include_dirs}} "
105       "-o {{output}}",
106       cxx_tool.get());
107   cxx_tool->set_outputs(SubstitutionList::MakeForTest(
108       "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
109   cxx_tool->set_command_launcher("launcher");
110   toolchain->SetTool(std::move(cxx_tool));
111 
112   // OBJC
113   std::unique_ptr<Tool> objc_tool = Tool::CreateTool(CTool::kCToolObjC);
114   SetCommandForTool(
115       "objcc {{source}} {{cflags}} {{cflags_objc}} {{defines}} "
116       "{{include_dirs}} -o {{output}}",
117       objc_tool.get());
118   objc_tool->set_outputs(SubstitutionList::MakeForTest(
119       "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
120   toolchain->SetTool(std::move(objc_tool));
121 
122   // OBJC
123   std::unique_ptr<Tool> objcxx_tool = Tool::CreateTool(CTool::kCToolObjCxx);
124   SetCommandForTool(
125       "objcxx {{source}} {{cflags}} {{cflags_objcc}} {{defines}} "
126       "{{include_dirs}} -o {{output}}",
127       objcxx_tool.get());
128   objcxx_tool->set_outputs(SubstitutionList::MakeForTest(
129       "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
130   toolchain->SetTool(std::move(objcxx_tool));
131 
132   // Don't use RC and ASM tools in unit tests yet. Add here if needed.
133 
134   // ALINK
135   std::unique_ptr<Tool> alink = Tool::CreateTool(CTool::kCToolAlink);
136   CTool* alink_tool = alink->AsC();
137   SetCommandForTool("ar {{output}} {{source}}", alink_tool);
138   alink_tool->set_lib_switch("-l");
139   alink_tool->set_lib_dir_switch("-L");
140   alink_tool->set_output_prefix("lib");
141   alink_tool->set_outputs(SubstitutionList::MakeForTest(
142       "{{target_out_dir}}/{{target_output_name}}.a"));
143   toolchain->SetTool(std::move(alink));
144 
145   // SOLINK
146   std::unique_ptr<Tool> solink = Tool::CreateTool(CTool::kCToolSolink);
147   CTool* solink_tool = solink->AsC();
148   SetCommandForTool(
149       "ld -shared -o {{target_output_name}}.so {{inputs}} "
150       "{{ldflags}} {{libs}}",
151       solink_tool);
152   solink_tool->set_lib_switch("-l");
153   solink_tool->set_lib_dir_switch("-L");
154   solink_tool->set_output_prefix("lib");
155   solink_tool->set_default_output_extension(".so");
156   if (use_toc) {
157     solink_tool->set_outputs(SubstitutionList::MakeForTest(
158         "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.TOC",
159         "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"));
160     solink_tool->set_link_output(SubstitutionPattern::MakeForTest(
161         "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"));
162     solink_tool->set_depend_output(SubstitutionPattern::MakeForTest(
163         "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.TOC"));
164   } else {
165     solink_tool->set_outputs(SubstitutionList::MakeForTest(
166         "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"));
167   }
168   toolchain->SetTool(std::move(solink));
169 
170   // SOLINK_MODULE
171   std::unique_ptr<Tool> solink_module =
172       Tool::CreateTool(CTool::kCToolSolinkModule);
173   CTool* solink_module_tool = solink_module->AsC();
174   SetCommandForTool(
175       "ld -bundle -o {{target_output_name}}.so {{inputs}} "
176       "{{ldflags}} {{libs}}",
177       solink_module_tool);
178   solink_module_tool->set_lib_switch("-l");
179   solink_module_tool->set_lib_dir_switch("-L");
180   solink_module_tool->set_output_prefix("lib");
181   solink_module_tool->set_default_output_extension(".so");
182   solink_module_tool->set_outputs(SubstitutionList::MakeForTest(
183       "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"));
184   toolchain->SetTool(std::move(solink_module));
185 
186   // LINK
187   std::unique_ptr<Tool> link = Tool::CreateTool(CTool::kCToolLink);
188   CTool* link_tool = link->AsC();
189   SetCommandForTool(
190       "ld -o {{target_output_name}} {{source}} "
191       "{{ldflags}} {{libs}}",
192       link_tool);
193   link_tool->set_lib_switch("-l");
194   link_tool->set_lib_dir_switch("-L");
195   link_tool->set_outputs(
196       SubstitutionList::MakeForTest("{{root_out_dir}}/{{target_output_name}}"));
197   toolchain->SetTool(std::move(link));
198 
199   // STAMP
200   std::unique_ptr<Tool> stamp_tool =
201       Tool::CreateTool(GeneralTool::kGeneralToolStamp);
202   SetCommandForTool("touch {{output}}", stamp_tool.get());
203   toolchain->SetTool(std::move(stamp_tool));
204 
205   // COPY
206   std::unique_ptr<Tool> copy_tool =
207       Tool::CreateTool(GeneralTool::kGeneralToolCopy);
208   SetCommandForTool("cp {{source}} {{output}}", copy_tool.get());
209   toolchain->SetTool(std::move(copy_tool));
210 
211   // COPY_BUNDLE_DATA
212   std::unique_ptr<Tool> copy_bundle_data_tool =
213       Tool::CreateTool(GeneralTool::kGeneralToolCopyBundleData);
214   SetCommandForTool("cp {{source}} {{output}}", copy_bundle_data_tool.get());
215   toolchain->SetTool(std::move(copy_bundle_data_tool));
216 
217   // COMPILE_XCASSETS
218   std::unique_ptr<Tool> compile_xcassets_tool =
219       Tool::CreateTool(GeneralTool::kGeneralToolCompileXCAssets);
220   SetCommandForTool("touch {{output}}", compile_xcassets_tool.get());
221   toolchain->SetTool(std::move(compile_xcassets_tool));
222 
223   // RUST
224   std::unique_ptr<Tool> rustc_tool = Tool::CreateTool(RustTool::kRsToolBin);
225   SetCommandForTool(
226       "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} "
227       "--crate-type {{crate_type}} {{rustflags}} -o {{output}} "
228       "{{rustdeps}} {{externs}}",
229       rustc_tool.get());
230   rustc_tool->set_outputs(SubstitutionList::MakeForTest(
231       "{{root_out_dir}}/{{crate_name}}{{output_extension}}"));
232   toolchain->SetTool(std::move(rustc_tool));
233 
234   // SWIFT
235   std::unique_ptr<Tool> swift_tool = Tool::CreateTool(CTool::kCToolSwift);
236   SetCommandForTool(
237       "swiftc --module-name {{module_name}} {{module_dirs}} {{inputs}}",
238       swift_tool.get());
239   swift_tool->set_outputs(SubstitutionList::MakeForTest(
240       "{{target_gen_dir}}/{{target_output_name}}.h",
241       "{{target_out_dir}}/{{module_name}}.swiftmodule"));
242   swift_tool->set_partial_outputs(SubstitutionList::MakeForTest(
243       "{{target_out_dir}}/{{source_name_part}}.o"));
244   toolchain->SetTool(std::move(swift_tool));
245 
246   // RUST CDYLIB
247   std::unique_ptr<Tool> cdylib_tool = Tool::CreateTool(RustTool::kRsToolCDylib);
248   SetCommandForTool(
249       "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} "
250       "--crate-type {{crate_type}} {{rustflags}} -o {{output}} "
251       "{{rustdeps}} {{externs}}",
252       cdylib_tool.get());
253   cdylib_tool->set_output_prefix("lib");
254   cdylib_tool->set_default_output_extension(".so");
255   cdylib_tool->set_outputs(SubstitutionList::MakeForTest(
256       "{{target_out_dir}}/{{target_output_name}}{{output_extension}}"));
257   toolchain->SetTool(std::move(cdylib_tool));
258 
259   // RUST DYLIB
260   std::unique_ptr<Tool> dylib_tool = Tool::CreateTool(RustTool::kRsToolDylib);
261   SetCommandForTool(
262       "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} "
263       "--crate-type {{crate_type}} {{rustflags}} -o {{output}} "
264       "{{rustdeps}} {{externs}}",
265       dylib_tool.get());
266   dylib_tool->set_output_prefix("lib");
267   dylib_tool->set_default_output_extension(".so");
268   dylib_tool->set_outputs(SubstitutionList::MakeForTest(
269       "{{target_out_dir}}/{{target_output_name}}{{output_extension}}"));
270   toolchain->SetTool(std::move(dylib_tool));
271 
272   // RUST_PROC_MACRO
273   std::unique_ptr<Tool> rust_proc_macro_tool =
274       Tool::CreateTool(RustTool::kRsToolMacro);
275   SetCommandForTool(
276       "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} "
277       "--crate-type {{crate_type}} {{rustflags}} -o {{output}} "
278       "{{rustdeps}} {{externs}}",
279       rust_proc_macro_tool.get());
280   rust_proc_macro_tool->set_output_prefix("lib");
281   rust_proc_macro_tool->set_default_output_extension(".so");
282   rust_proc_macro_tool->set_outputs(SubstitutionList::MakeForTest(
283       "{{target_out_dir}}/{{target_output_name}}{{output_extension}}"));
284   toolchain->SetTool(std::move(rust_proc_macro_tool));
285 
286   // RLIB
287   std::unique_ptr<Tool> rlib_tool = Tool::CreateTool(RustTool::kRsToolRlib);
288   SetCommandForTool(
289       "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} "
290       "--crate-type {{crate_type}} {{rustflags}} -o {{output}} "
291       "{{rustdeps}} {{externs}}",
292       rlib_tool.get());
293   rlib_tool->set_output_prefix("lib");
294   rlib_tool->set_default_output_extension(".rlib");
295   rlib_tool->set_outputs(SubstitutionList::MakeForTest(
296       "{{target_out_dir}}/{{target_output_name}}{{output_extension}}"));
297   toolchain->SetTool(std::move(rlib_tool));
298 
299   // RUST STATICLIB
300   std::unique_ptr<Tool> staticlib_tool =
301       Tool::CreateTool(RustTool::kRsToolStaticlib);
302   SetCommandForTool(
303       "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} "
304       "--crate-type {{crate_type}} {{rustflags}} -o {{output}} "
305       "{{rustdeps}} {{externs}}",
306       staticlib_tool.get());
307   staticlib_tool->set_output_prefix("lib");
308   staticlib_tool->set_default_output_extension(".a");
309   staticlib_tool->set_outputs(SubstitutionList::MakeForTest(
310       "{{target_out_dir}}/{{target_output_name}}{{output_extension}}"));
311   static_cast<RustTool*>(staticlib_tool.get())
312       ->set_dynamic_link_switch("-Clink-arg=-Balternative-dynamic");
313   toolchain->SetTool(std::move(staticlib_tool));
314 
315   toolchain->ToolchainSetupComplete();
316 }
317 
318 // static
SetCommandForTool(const std::string & cmd,Tool * tool)319 void TestWithScope::SetCommandForTool(const std::string& cmd, Tool* tool) {
320   Err err;
321   SubstitutionPattern command;
322   command.Parse(cmd, nullptr, &err);
323   CHECK(!err.has_error()) << "Couldn't parse \"" << cmd << "\", " << "got "
324                           << err.message();
325   tool->set_command(command);
326 }
327 
AppendPrintOutput(const std::string & str)328 void TestWithScope::AppendPrintOutput(const std::string& str) {
329   print_output_.append(str);
330 }
331 
TestParseInput(const std::string & input)332 TestParseInput::TestParseInput(const std::string& input)
333     : input_file_(SourceFile("//test")) {
334   input_file_.SetContents(input);
335 
336   tokens_ = Tokenizer::Tokenize(&input_file_, &parse_err_);
337   if (!parse_err_.has_error())
338     parsed_ = Parser::Parse(tokens_, &parse_err_);
339 }
340 
341 TestParseInput::~TestParseInput() = default;
342 
TestTarget(const TestWithScope & setup,const std::string & label_string,Target::OutputType type)343 TestTarget::TestTarget(const TestWithScope& setup,
344                        const std::string& label_string,
345                        Target::OutputType type)
346     : Target(setup.settings(), setup.ParseLabel(label_string)) {
347   visibility().SetPublic();
348   set_output_type(type);
349   SetToolchain(setup.toolchain());
350 }
351 
352 TestTarget::~TestTarget() = default;
353