• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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/ninja_c_binary_target_writer.h"
6 
7 #include <memory>
8 #include <sstream>
9 #include <utility>
10 
11 #include "gn/config.h"
12 #include "gn/ninja_target_command_util.h"
13 #include "gn/scheduler.h"
14 #include "gn/target.h"
15 #include "gn/test_with_scheduler.h"
16 #include "gn/test_with_scope.h"
17 #include "util/build_config.h"
18 #include "util/test/test.h"
19 
20 using NinjaCBinaryTargetWriterTest = TestWithScheduler;
21 
TEST_F(NinjaCBinaryTargetWriterTest,SourceSet)22 TEST_F(NinjaCBinaryTargetWriterTest, SourceSet) {
23   Err err;
24   TestWithScope setup;
25 
26   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
27   target.set_output_type(Target::SOURCE_SET);
28   target.visibility().SetPublic();
29   target.sources().push_back(SourceFile("//foo/input1.cc"));
30   target.sources().push_back(SourceFile("//foo/input2.cc"));
31   // Also test object files, which should be just passed through to the
32   // dependents to link.
33   target.sources().push_back(SourceFile("//foo/input3.o"));
34   target.sources().push_back(SourceFile("//foo/input4.obj"));
35   target.source_types_used().Set(SourceFile::SOURCE_CPP);
36   target.source_types_used().Set(SourceFile::SOURCE_O);
37   target.SetToolchain(setup.toolchain());
38   ASSERT_TRUE(target.OnResolved(&err));
39 
40   // Source set itself.
41   {
42     std::ostringstream out;
43     NinjaCBinaryTargetWriter writer(&target, out);
44     writer.Run();
45 
46     const char expected[] =
47         "defines =\n"
48         "include_dirs =\n"
49         "cflags =\n"
50         "cflags_cc =\n"
51         "root_out_dir = .\n"
52         "target_out_dir = obj/foo\n"
53         "target_output_name = bar\n"
54         "\n"
55         "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc\n"
56         "  source_file_part = input1.cc\n"
57         "  source_name_part = input1\n"
58         "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc\n"
59         "  source_file_part = input2.cc\n"
60         "  source_name_part = input2\n"
61         "\n"
62         "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.o "
63         "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj\n";
64     std::string out_str = out.str();
65     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
66   }
67 
68   // A shared library that depends on the source set.
69   Target shlib_target(setup.settings(), Label(SourceDir("//foo/"), "shlib"));
70   shlib_target.set_output_type(Target::SHARED_LIBRARY);
71   shlib_target.public_deps().push_back(LabelTargetPair(&target));
72   shlib_target.SetToolchain(setup.toolchain());
73   ASSERT_TRUE(shlib_target.OnResolved(&err));
74 
75   {
76     std::ostringstream out;
77     NinjaCBinaryTargetWriter writer(&shlib_target, out);
78     writer.Run();
79 
80     const char expected[] =
81         "defines =\n"
82         "include_dirs =\n"
83         "root_out_dir = .\n"
84         "target_out_dir = obj/foo\n"
85         "target_output_name = libshlib\n"
86         "\n"
87         "\n"
88         // Ordering of the obj files here should come out in the order
89         // specified, with the target's first, followed by the source set's, in
90         // order.
91         "build ./libshlib.so: solink obj/foo/bar.input1.o "
92         "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj "
93         "|| obj/foo/bar.stamp\n"
94         "  ldflags =\n"
95         "  libs =\n"
96         "  frameworks =\n"
97         "  swiftmodules =\n"
98         "  output_extension = .so\n"
99         "  output_dir = \n";
100     std::string out_str = out.str();
101     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
102   }
103 
104   // A static library that depends on the source set (should not link it).
105   Target stlib_target(setup.settings(), Label(SourceDir("//foo/"), "stlib"));
106   stlib_target.set_output_type(Target::STATIC_LIBRARY);
107   stlib_target.public_deps().push_back(LabelTargetPair(&target));
108   stlib_target.SetToolchain(setup.toolchain());
109   ASSERT_TRUE(stlib_target.OnResolved(&err));
110 
111   {
112     std::ostringstream out;
113     NinjaCBinaryTargetWriter writer(&stlib_target, out);
114     writer.Run();
115 
116     const char expected[] =
117         "defines =\n"
118         "include_dirs =\n"
119         "root_out_dir = .\n"
120         "target_out_dir = obj/foo\n"
121         "target_output_name = libstlib\n"
122         "\n"
123         "\n"
124         // There are no sources so there are no params to alink. (In practice
125         // this will probably fail in the archive tool.)
126         "build obj/foo/libstlib.a: alink || obj/foo/bar.stamp\n"
127         "  arflags =\n"
128         "  output_extension = \n"
129         "  output_dir = \n";
130     std::string out_str = out.str();
131     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
132   }
133 
134   // Make the static library 'complete', which means it should be linked.
135   stlib_target.set_complete_static_lib(true);
136   {
137     std::ostringstream out;
138     NinjaCBinaryTargetWriter writer(&stlib_target, out);
139     writer.Run();
140 
141     const char expected[] =
142         "defines =\n"
143         "include_dirs =\n"
144         "root_out_dir = .\n"
145         "target_out_dir = obj/foo\n"
146         "target_output_name = libstlib\n"
147         "\n"
148         "\n"
149         // Ordering of the obj files here should come out in the order
150         // specified, with the target's first, followed by the source set's, in
151         // order.
152         "build obj/foo/libstlib.a: alink obj/foo/bar.input1.o "
153         "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj "
154         "|| obj/foo/bar.stamp\n"
155         "  arflags =\n"
156         "  output_extension = \n"
157         "  output_dir = \n";
158     std::string out_str = out.str();
159     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
160   }
161 }
162 
TEST_F(NinjaCBinaryTargetWriterTest,EscapeDefines)163 TEST_F(NinjaCBinaryTargetWriterTest, EscapeDefines) {
164   TestWithScope setup;
165   Err err;
166 
167   TestTarget target(setup, "//foo:bar", Target::STATIC_LIBRARY);
168   target.config_values().defines().push_back("BOOL_DEF");
169   target.config_values().defines().push_back("INT_DEF=123");
170   target.config_values().defines().push_back("STR_DEF=\"ABCD-1\"");
171   ASSERT_TRUE(target.OnResolved(&err));
172 
173   std::ostringstream out;
174   NinjaCBinaryTargetWriter writer(&target, out);
175   writer.Run();
176 
177   const char expectedSubstr[] =
178 #if defined(OS_WIN)
179       "defines = -DBOOL_DEF -DINT_DEF=123 \"-DSTR_DEF=\\\"ABCD-1\\\"\"";
180 #else
181       "defines = -DBOOL_DEF -DINT_DEF=123 -DSTR_DEF=\\\"ABCD-1\\\"";
182 #endif
183   std::string out_str = out.str();
184   EXPECT_TRUE(out_str.find(expectedSubstr) != std::string::npos);
185 }
186 
TEST_F(NinjaCBinaryTargetWriterTest,StaticLibrary)187 TEST_F(NinjaCBinaryTargetWriterTest, StaticLibrary) {
188   TestWithScope setup;
189   Err err;
190 
191   TestTarget target(setup, "//foo:bar", Target::STATIC_LIBRARY);
192   target.sources().push_back(SourceFile("//foo/input1.cc"));
193   target.source_types_used().Set(SourceFile::SOURCE_CPP);
194   target.config_values().arflags().push_back("--asdf");
195   ASSERT_TRUE(target.OnResolved(&err));
196 
197   std::ostringstream out;
198   NinjaCBinaryTargetWriter writer(&target, out);
199   writer.Run();
200 
201   const char expected[] =
202       "defines =\n"
203       "include_dirs =\n"
204       "cflags =\n"
205       "cflags_cc =\n"
206       "root_out_dir = .\n"
207       "target_out_dir = obj/foo\n"
208       "target_output_name = libbar\n"
209       "\n"
210       "build obj/foo/libbar.input1.o: cxx ../../foo/input1.cc\n"
211       "  source_file_part = input1.cc\n"
212       "  source_name_part = input1\n"
213       "\n"
214       "build obj/foo/libbar.a: alink obj/foo/libbar.input1.o\n"
215       "  arflags = --asdf\n"
216       "  output_extension = \n"
217       "  output_dir = \n";
218   std::string out_str = out.str();
219   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
220 }
221 
TEST_F(NinjaCBinaryTargetWriterTest,CompleteStaticLibrary)222 TEST_F(NinjaCBinaryTargetWriterTest, CompleteStaticLibrary) {
223   TestWithScope setup;
224   Err err;
225 
226   TestTarget target(setup, "//foo:bar", Target::STATIC_LIBRARY);
227   target.sources().push_back(SourceFile("//foo/input1.cc"));
228   target.source_types_used().Set(SourceFile::SOURCE_CPP);
229   target.config_values().arflags().push_back("--asdf");
230   target.set_complete_static_lib(true);
231 
232   TestTarget baz(setup, "//foo:baz", Target::STATIC_LIBRARY);
233   baz.sources().push_back(SourceFile("//foo/input2.cc"));
234   baz.source_types_used().Set(SourceFile::SOURCE_CPP);
235 
236   target.public_deps().push_back(LabelTargetPair(&baz));
237 
238   ASSERT_TRUE(target.OnResolved(&err));
239   ASSERT_TRUE(baz.OnResolved(&err));
240 
241   // A complete static library that depends on an incomplete static library
242   // should link in the dependent object files as if the dependent target
243   // were a source set.
244   {
245     std::ostringstream out;
246     NinjaCBinaryTargetWriter writer(&target, out);
247     writer.Run();
248 
249     const char expected[] =
250         "defines =\n"
251         "include_dirs =\n"
252         "cflags =\n"
253         "cflags_cc =\n"
254         "root_out_dir = .\n"
255         "target_out_dir = obj/foo\n"
256         "target_output_name = libbar\n"
257         "\n"
258         "build obj/foo/libbar.input1.o: cxx ../../foo/input1.cc\n"
259         "  source_file_part = input1.cc\n"
260         "  source_name_part = input1\n"
261         "\n"
262         "build obj/foo/libbar.a: alink obj/foo/libbar.input1.o "
263         "obj/foo/libbaz.input2.o || obj/foo/libbaz.a\n"
264         "  arflags = --asdf\n"
265         "  output_extension = \n"
266         "  output_dir = \n";
267     std::string out_str = out.str();
268     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
269   }
270 
271   // Make the dependent static library complete.
272   baz.set_complete_static_lib(true);
273 
274   // Dependent complete static libraries should not be linked directly.
275   {
276     std::ostringstream out;
277     NinjaCBinaryTargetWriter writer(&target, out);
278     writer.Run();
279 
280     const char expected[] =
281         "defines =\n"
282         "include_dirs =\n"
283         "cflags =\n"
284         "cflags_cc =\n"
285         "root_out_dir = .\n"
286         "target_out_dir = obj/foo\n"
287         "target_output_name = libbar\n"
288         "\n"
289         "build obj/foo/libbar.input1.o: cxx ../../foo/input1.cc\n"
290         "  source_file_part = input1.cc\n"
291         "  source_name_part = input1\n"
292         "\n"
293         "build obj/foo/libbar.a: alink obj/foo/libbar.input1.o "
294         "|| obj/foo/libbaz.a\n"
295         "  arflags = --asdf\n"
296         "  output_extension = \n"
297         "  output_dir = \n";
298     std::string out_str = out.str();
299     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
300   }
301 }
302 
303 // This tests that output extension and output dir overrides apply, and input
304 // dependencies are applied.
TEST_F(NinjaCBinaryTargetWriterTest,OutputExtensionAndInputDeps)305 TEST_F(NinjaCBinaryTargetWriterTest, OutputExtensionAndInputDeps) {
306   Err err;
307   TestWithScope setup;
308 
309   // An action for our library to depend on.
310   Target action(setup.settings(), Label(SourceDir("//foo/"), "action"));
311   action.set_output_type(Target::ACTION_FOREACH);
312   action.visibility().SetPublic();
313   action.SetToolchain(setup.toolchain());
314   ASSERT_TRUE(action.OnResolved(&err));
315 
316   // A shared library w/ the output_extension set to a custom value.
317   Target target(setup.settings(), Label(SourceDir("//foo/"), "shlib"));
318   target.set_output_type(Target::SHARED_LIBRARY);
319   target.set_output_extension(std::string("so.6"));
320   target.set_output_dir(SourceDir("//out/Debug/foo/"));
321   target.sources().push_back(SourceFile("//foo/input1.cc"));
322   target.sources().push_back(SourceFile("//foo/input2.cc"));
323   target.source_types_used().Set(SourceFile::SOURCE_CPP);
324   target.public_deps().push_back(LabelTargetPair(&action));
325   target.SetToolchain(setup.toolchain());
326   ASSERT_TRUE(target.OnResolved(&err));
327 
328   std::ostringstream out;
329   NinjaCBinaryTargetWriter writer(&target, out);
330   writer.Run();
331 
332   const char expected[] =
333       "defines =\n"
334       "include_dirs =\n"
335       "cflags =\n"
336       "cflags_cc =\n"
337       "root_out_dir = .\n"
338       "target_out_dir = obj/foo\n"
339       "target_output_name = libshlib\n"
340       "\n"
341       "build obj/foo/libshlib.input1.o: cxx ../../foo/input1.cc"
342       " || obj/foo/action.stamp\n"
343       "  source_file_part = input1.cc\n"
344       "  source_name_part = input1\n"
345       "build obj/foo/libshlib.input2.o: cxx ../../foo/input2.cc"
346       " || obj/foo/action.stamp\n"
347       "  source_file_part = input2.cc\n"
348       "  source_name_part = input2\n"
349       "\n"
350       "build ./libshlib.so.6: solink obj/foo/libshlib.input1.o "
351       // The order-only dependency here is stricly unnecessary since the
352       // sources list this as an order-only dep. See discussion in the code
353       // that writes this.
354       "obj/foo/libshlib.input2.o || obj/foo/action.stamp\n"
355       "  ldflags =\n"
356       "  libs =\n"
357       "  frameworks =\n"
358       "  swiftmodules =\n"
359       "  output_extension = .so.6\n"
360       "  output_dir = foo\n";
361 
362   std::string out_str = out.str();
363   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
364 }
365 
TEST_F(NinjaCBinaryTargetWriterTest,NoHardDepsToNoPublicHeaderTarget)366 TEST_F(NinjaCBinaryTargetWriterTest, NoHardDepsToNoPublicHeaderTarget) {
367   Err err;
368   TestWithScope setup;
369 
370   SourceFile generated_file("//out/Debug/generated.cc");
371 
372   // An action does code generation.
373   Target action(setup.settings(), Label(SourceDir("//foo/"), "generate"));
374   action.set_output_type(Target::ACTION);
375   action.visibility().SetPublic();
376   action.SetToolchain(setup.toolchain());
377   action.set_output_dir(SourceDir("//out/Debug/foo/"));
378   action.action_values().outputs() =
379       SubstitutionList::MakeForTest("//out/Debug/generated.cc");
380   ASSERT_TRUE(action.OnResolved(&err));
381 
382   // A source set compiling generated code, this target does not publicize any
383   // headers.
384   Target gen_obj(setup.settings(), Label(SourceDir("//foo/"), "gen_obj"));
385   gen_obj.set_output_type(Target::SOURCE_SET);
386   gen_obj.set_output_dir(SourceDir("//out/Debug/foo/"));
387   gen_obj.sources().push_back(generated_file);
388   gen_obj.source_types_used().Set(SourceFile::SOURCE_CPP);
389   gen_obj.visibility().SetPublic();
390   gen_obj.private_deps().push_back(LabelTargetPair(&action));
391   gen_obj.set_all_headers_public(false);
392   gen_obj.SetToolchain(setup.toolchain());
393   ASSERT_TRUE(gen_obj.OnResolved(&err));
394 
395   std::ostringstream obj_out;
396   NinjaCBinaryTargetWriter obj_writer(&gen_obj, obj_out);
397   obj_writer.Run();
398 
399   const char obj_expected[] =
400       "defines =\n"
401       "include_dirs =\n"
402       "cflags =\n"
403       "cflags_cc =\n"
404       "root_out_dir = .\n"
405       "target_out_dir = obj/foo\n"
406       "target_output_name = gen_obj\n"
407       "\n"
408       "build obj/BUILD_DIR/gen_obj.generated.o: cxx generated.cc"
409       " || obj/foo/generate.stamp\n"
410       "  source_file_part = generated.cc\n"
411       "  source_name_part = generated\n"
412       "\n"
413       "build obj/foo/gen_obj.stamp: stamp obj/BUILD_DIR/gen_obj.generated.o"
414       // The order-only dependency here is strictly unnecessary since the
415       // sources list this as an order-only dep.
416       " || obj/foo/generate.stamp\n";
417 
418   std::string obj_str = obj_out.str();
419   EXPECT_EQ(std::string(obj_expected), obj_str);
420 
421   // A shared library depends on gen_obj, having corresponding header for
422   // generated obj.
423   Target gen_lib(setup.settings(), Label(SourceDir("//foo/"), "gen_lib"));
424   gen_lib.set_output_type(Target::SHARED_LIBRARY);
425   gen_lib.set_output_dir(SourceDir("//out/Debug/foo/"));
426   gen_lib.sources().push_back(SourceFile("//foor/generated.h"));
427   gen_lib.source_types_used().Set(SourceFile::SOURCE_H);
428   gen_lib.visibility().SetPublic();
429   gen_lib.private_deps().push_back(LabelTargetPair(&gen_obj));
430   gen_lib.SetToolchain(setup.toolchain());
431   ASSERT_TRUE(gen_lib.OnResolved(&err));
432 
433   std::ostringstream lib_out;
434   NinjaCBinaryTargetWriter lib_writer(&gen_lib, lib_out);
435   lib_writer.Run();
436 
437   const char lib_expected[] =
438       "defines =\n"
439       "include_dirs =\n"
440       "root_out_dir = .\n"
441       "target_out_dir = obj/foo\n"
442       "target_output_name = libgen_lib\n"
443       "\n"
444       "\n"
445       "build ./libgen_lib.so: solink obj/BUILD_DIR/gen_obj.generated.o"
446       // The order-only dependency here is strictly unnecessary since
447       // obj/out/Debug/gen_obj.generated.o has dependency to
448       // obj/foo/gen_obj.stamp
449       " || obj/foo/gen_obj.stamp\n"
450       "  ldflags =\n"
451       "  libs =\n"
452       "  frameworks =\n"
453       "  swiftmodules =\n"
454       "  output_extension = .so\n"
455       "  output_dir = foo\n";
456 
457   std::string lib_str = lib_out.str();
458   EXPECT_EQ(lib_expected, lib_str);
459 
460   // An executable depends on gen_lib.
461   Target executable(setup.settings(),
462                     Label(SourceDir("//foo/"), "final_target"));
463   executable.set_output_type(Target::EXECUTABLE);
464   executable.set_output_dir(SourceDir("//out/Debug/foo/"));
465   executable.sources().push_back(SourceFile("//foo/main.cc"));
466   executable.source_types_used().Set(SourceFile::SOURCE_CPP);
467   executable.private_deps().push_back(LabelTargetPair(&gen_lib));
468   executable.SetToolchain(setup.toolchain());
469   ASSERT_TRUE(executable.OnResolved(&err)) << err.message();
470 
471   std::ostringstream final_out;
472   NinjaCBinaryTargetWriter final_writer(&executable, final_out);
473   final_writer.Run();
474 
475   // There is no order only dependency to action target.
476   const char final_expected[] =
477       "defines =\n"
478       "include_dirs =\n"
479       "cflags =\n"
480       "cflags_cc =\n"
481       "root_out_dir = .\n"
482       "target_out_dir = obj/foo\n"
483       "target_output_name = final_target\n"
484       "\n"
485       "build obj/foo/final_target.main.o: cxx ../../foo/main.cc\n"
486       "  source_file_part = main.cc\n"
487       "  source_name_part = main\n"
488       "\n"
489       "build ./final_target: link obj/foo/final_target.main.o"
490       " ./libgen_lib.so\n"
491       "  ldflags =\n"
492       "  libs =\n"
493       "  frameworks =\n"
494       "  swiftmodules =\n"
495       "  output_extension = \n"
496       "  output_dir = foo\n";
497 
498   std::string final_str = final_out.str();
499   EXPECT_EQ(final_expected, final_str);
500 }
501 
502 // Tests libs are applied.
TEST_F(NinjaCBinaryTargetWriterTest,LibsAndLibDirs)503 TEST_F(NinjaCBinaryTargetWriterTest, LibsAndLibDirs) {
504   Err err;
505   TestWithScope setup;
506 
507   // A shared library w/ libs and lib_dirs.
508   Target target(setup.settings(), Label(SourceDir("//foo/"), "shlib"));
509   target.set_output_type(Target::SHARED_LIBRARY);
510   target.config_values().libs().push_back(LibFile(SourceFile("//foo/lib1.a")));
511   target.config_values().libs().push_back(LibFile(SourceFile("//sysroot/DIA SDK/diaguids.lib")));
512   target.config_values().libs().push_back(LibFile("foo"));
513   target.config_values().lib_dirs().push_back(SourceDir("//foo/bar/"));
514   target.SetToolchain(setup.toolchain());
515   ASSERT_TRUE(target.OnResolved(&err));
516 
517   std::ostringstream out;
518   NinjaCBinaryTargetWriter writer(&target, out);
519   writer.Run();
520 
521   const char expected[] =
522       "defines =\n"
523       "include_dirs =\n"
524       "root_out_dir = .\n"
525       "target_out_dir = obj/foo\n"
526       "target_output_name = libshlib\n"
527       "\n"
528       "\n"
529       "build ./libshlib.so: solink | ../../foo/lib1.a ../../sysroot/DIA$ SDK/diaguids.lib\n"
530       "  ldflags = -L../../foo/bar\n"
531 #ifdef _WIN32
532       "  libs = ../../foo/lib1.a \"../../sysroot/DIA$ SDK/diaguids.lib\" -lfoo\n"
533 #else
534       "  libs = ../../foo/lib1.a ../../sysroot/DIA\\$ SDK/diaguids.lib -lfoo\n"
535 #endif
536       "  frameworks =\n"
537       "  swiftmodules =\n"
538       "  output_extension = .so\n"
539       "  output_dir = \n";
540 
541   std::string out_str = out.str();
542   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
543 }
544 
545 // Tests frameworks are applied.
TEST_F(NinjaCBinaryTargetWriterTest,FrameworksAndFrameworkDirs)546 TEST_F(NinjaCBinaryTargetWriterTest, FrameworksAndFrameworkDirs) {
547   Err err;
548   TestWithScope setup;
549 
550   // A config that force linking with the framework.
551   Config framework_config(setup.settings(),
552                           Label(SourceDir("//bar"), "framework_config"));
553   framework_config.visibility().SetPublic();
554   framework_config.own_values().frameworks().push_back("Bar.framework");
555   framework_config.own_values().framework_dirs().push_back(
556       SourceDir("//out/Debug/"));
557   ASSERT_TRUE(framework_config.OnResolved(&err));
558 
559   // A target creating a framework bundle.
560   Target framework(setup.settings(), Label(SourceDir("//bar"), "framework"));
561   framework.set_output_type(Target::CREATE_BUNDLE);
562   framework.bundle_data().product_type() = "com.apple.product-type.framework";
563   framework.public_configs().push_back(LabelConfigPair(&framework_config));
564   framework.SetToolchain(setup.toolchain());
565   framework.visibility().SetPublic();
566   ASSERT_TRUE(framework.OnResolved(&err));
567 
568   // A shared library w/ libs and lib_dirs.
569   Target target(setup.settings(), Label(SourceDir("//foo/"), "shlib"));
570   target.set_output_type(Target::SHARED_LIBRARY);
571   target.config_values().frameworks().push_back("System.framework");
572   target.config_values().weak_frameworks().push_back("Whizbang.framework");
573   target.private_deps().push_back(LabelTargetPair(&framework));
574   target.SetToolchain(setup.toolchain());
575   ASSERT_TRUE(target.OnResolved(&err));
576 
577   std::ostringstream out;
578   NinjaCBinaryTargetWriter writer(&target, out);
579   writer.Run();
580 
581   const char expected[] =
582       "defines =\n"
583       "include_dirs =\n"
584       "root_out_dir = .\n"
585       "target_out_dir = obj/foo\n"
586       "target_output_name = libshlib\n"
587       "\n"
588       "\n"
589       "build ./libshlib.so: solink | obj/bar/framework.stamp\n"
590       "  ldflags = -F.\n"
591       "  libs =\n"
592       "  frameworks = -framework System -framework Bar "
593       "-weak_framework Whizbang\n"
594       "  swiftmodules =\n"
595       "  output_extension = .so\n"
596       "  output_dir = \n";
597 
598   std::string out_str = out.str();
599   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
600 }
601 
TEST_F(NinjaCBinaryTargetWriterTest,EmptyOutputExtension)602 TEST_F(NinjaCBinaryTargetWriterTest, EmptyOutputExtension) {
603   Err err;
604   TestWithScope setup;
605 
606   // This test is the same as OutputExtensionAndInputDeps, except that we call
607   // set_output_extension("") and ensure that we get an empty one and override
608   // the output prefix so that the name matches the target exactly.
609   Target target(setup.settings(), Label(SourceDir("//foo/"), "shlib"));
610   target.set_output_type(Target::SHARED_LIBRARY);
611   target.set_output_prefix_override(true);
612   target.set_output_extension(std::string());
613   target.sources().push_back(SourceFile("//foo/input1.cc"));
614   target.sources().push_back(SourceFile("//foo/input2.cc"));
615   target.source_types_used().Set(SourceFile::SOURCE_CPP);
616 
617   target.SetToolchain(setup.toolchain());
618   ASSERT_TRUE(target.OnResolved(&err));
619 
620   std::ostringstream out;
621   NinjaCBinaryTargetWriter writer(&target, out);
622   writer.Run();
623 
624   const char expected[] =
625       "defines =\n"
626       "include_dirs =\n"
627       "cflags =\n"
628       "cflags_cc =\n"
629       "root_out_dir = .\n"
630       "target_out_dir = obj/foo\n"
631       "target_output_name = shlib\n"
632       "\n"
633       "build obj/foo/shlib.input1.o: cxx ../../foo/input1.cc\n"
634       "  source_file_part = input1.cc\n"
635       "  source_name_part = input1\n"
636       "build obj/foo/shlib.input2.o: cxx ../../foo/input2.cc\n"
637       "  source_file_part = input2.cc\n"
638       "  source_name_part = input2\n"
639       "\n"
640       "build ./shlib: solink obj/foo/shlib.input1.o "
641       "obj/foo/shlib.input2.o\n"
642       "  ldflags =\n"
643       "  libs =\n"
644       "  frameworks =\n"
645       "  swiftmodules =\n"
646       "  output_extension = \n"
647       "  output_dir = \n";
648 
649   std::string out_str = out.str();
650   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
651 }
652 
TEST_F(NinjaCBinaryTargetWriterTest,SourceSetDataDeps)653 TEST_F(NinjaCBinaryTargetWriterTest, SourceSetDataDeps) {
654   Err err;
655   TestWithScope setup;
656 
657   // This target is a data (runtime) dependency of the intermediate target.
658   Target data(setup.settings(), Label(SourceDir("//foo/"), "data_target"));
659   data.set_output_type(Target::EXECUTABLE);
660   data.visibility().SetPublic();
661   data.SetToolchain(setup.toolchain());
662   ASSERT_TRUE(data.OnResolved(&err));
663 
664   // Intermediate source set target.
665   Target inter(setup.settings(), Label(SourceDir("//foo/"), "inter"));
666   inter.set_output_type(Target::SOURCE_SET);
667   inter.visibility().SetPublic();
668   inter.data_deps().push_back(LabelTargetPair(&data));
669   inter.SetToolchain(setup.toolchain());
670   inter.sources().push_back(SourceFile("//foo/inter.cc"));
671   inter.source_types_used().Set(SourceFile::SOURCE_CPP);
672   ASSERT_TRUE(inter.OnResolved(&err)) << err.message();
673 
674   // Write out the intermediate target.
675   std::ostringstream inter_out;
676   NinjaCBinaryTargetWriter inter_writer(&inter, inter_out);
677   inter_writer.Run();
678 
679   // The intermediate source set will be a stamp file that depends on the
680   // object files, and will have an order-only dependency on its data dep and
681   // data file.
682   const char inter_expected[] =
683       "defines =\n"
684       "include_dirs =\n"
685       "cflags =\n"
686       "cflags_cc =\n"
687       "root_out_dir = .\n"
688       "target_out_dir = obj/foo\n"
689       "target_output_name = inter\n"
690       "\n"
691       "build obj/foo/inter.inter.o: cxx ../../foo/inter.cc\n"
692       "  source_file_part = inter.cc\n"
693       "  source_name_part = inter\n"
694       "\n"
695       "build obj/foo/inter.stamp: stamp obj/foo/inter.inter.o || "
696       "./data_target\n";
697   EXPECT_EQ(inter_expected, inter_out.str());
698 
699   // Final target.
700   Target exe(setup.settings(), Label(SourceDir("//foo/"), "exe"));
701   exe.set_output_type(Target::EXECUTABLE);
702   exe.public_deps().push_back(LabelTargetPair(&inter));
703   exe.SetToolchain(setup.toolchain());
704   exe.sources().push_back(SourceFile("//foo/final.cc"));
705   exe.source_types_used().Set(SourceFile::SOURCE_CPP);
706   ASSERT_TRUE(exe.OnResolved(&err));
707 
708   std::ostringstream final_out;
709   NinjaCBinaryTargetWriter final_writer(&exe, final_out);
710   final_writer.Run();
711 
712   // The final output depends on both object files (one from the final target,
713   // one from the source set) and has an order-only dependency on the source
714   // set's stamp file and the final target's data file. The source set stamp
715   // dependency will create an implicit order-only dependency on the data
716   // target.
717   const char final_expected[] =
718       "defines =\n"
719       "include_dirs =\n"
720       "cflags =\n"
721       "cflags_cc =\n"
722       "root_out_dir = .\n"
723       "target_out_dir = obj/foo\n"
724       "target_output_name = exe\n"
725       "\n"
726       "build obj/foo/exe.final.o: cxx ../../foo/final.cc\n"
727       "  source_file_part = final.cc\n"
728       "  source_name_part = final\n"
729       "\n"
730       "build ./exe: link obj/foo/exe.final.o obj/foo/inter.inter.o || "
731       "obj/foo/inter.stamp\n"
732       "  ldflags =\n"
733       "  libs =\n"
734       "  frameworks =\n"
735       "  swiftmodules =\n"
736       "  output_extension = \n"
737       "  output_dir = \n";
738   EXPECT_EQ(final_expected, final_out.str());
739 }
740 
TEST_F(NinjaCBinaryTargetWriterTest,SharedLibraryModuleDefinitionFile)741 TEST_F(NinjaCBinaryTargetWriterTest, SharedLibraryModuleDefinitionFile) {
742   Err err;
743   TestWithScope setup;
744 
745   Target shared_lib(setup.settings(), Label(SourceDir("//foo/"), "bar"));
746   shared_lib.set_output_type(Target::SHARED_LIBRARY);
747   shared_lib.SetToolchain(setup.toolchain());
748   shared_lib.sources().push_back(SourceFile("//foo/sources.cc"));
749   shared_lib.sources().push_back(SourceFile("//foo/bar.def"));
750   shared_lib.source_types_used().Set(SourceFile::SOURCE_CPP);
751   shared_lib.source_types_used().Set(SourceFile::SOURCE_DEF);
752   ASSERT_TRUE(shared_lib.OnResolved(&err));
753 
754   std::ostringstream out;
755   NinjaCBinaryTargetWriter writer(&shared_lib, out);
756   writer.Run();
757 
758   const char expected[] =
759       "defines =\n"
760       "include_dirs =\n"
761       "cflags =\n"
762       "cflags_cc =\n"
763       "root_out_dir = .\n"
764       "target_out_dir = obj/foo\n"
765       "target_output_name = libbar\n"
766       "\n"
767       "build obj/foo/libbar.sources.o: cxx ../../foo/sources.cc\n"
768       "  source_file_part = sources.cc\n"
769       "  source_name_part = sources\n"
770       "\n"
771       "build ./libbar.so: solink obj/foo/libbar.sources.o | ../../foo/bar.def\n"
772       "  ldflags = /DEF:../../foo/bar.def\n"
773       "  libs =\n"
774       "  frameworks =\n"
775       "  swiftmodules =\n"
776       "  output_extension = .so\n"
777       "  output_dir = \n";
778   EXPECT_EQ(expected, out.str());
779 }
780 
TEST_F(NinjaCBinaryTargetWriterTest,LoadableModule)781 TEST_F(NinjaCBinaryTargetWriterTest, LoadableModule) {
782   Err err;
783   TestWithScope setup;
784 
785   Target loadable_module(setup.settings(), Label(SourceDir("//foo/"), "bar"));
786   loadable_module.set_output_type(Target::LOADABLE_MODULE);
787   loadable_module.visibility().SetPublic();
788   loadable_module.SetToolchain(setup.toolchain());
789   loadable_module.sources().push_back(SourceFile("//foo/sources.cc"));
790   loadable_module.source_types_used().Set(SourceFile::SOURCE_CPP);
791   ASSERT_TRUE(loadable_module.OnResolved(&err)) << err.message();
792 
793   std::ostringstream out;
794   NinjaCBinaryTargetWriter writer(&loadable_module, out);
795   writer.Run();
796 
797   const char loadable_expected[] =
798       "defines =\n"
799       "include_dirs =\n"
800       "cflags =\n"
801       "cflags_cc =\n"
802       "root_out_dir = .\n"
803       "target_out_dir = obj/foo\n"
804       "target_output_name = libbar\n"
805       "\n"
806       "build obj/foo/libbar.sources.o: cxx ../../foo/sources.cc\n"
807       "  source_file_part = sources.cc\n"
808       "  source_name_part = sources\n"
809       "\n"
810       "build ./libbar.so: solink_module obj/foo/libbar.sources.o\n"
811       "  ldflags =\n"
812       "  libs =\n"
813       "  frameworks =\n"
814       "  swiftmodules =\n"
815       "  output_extension = .so\n"
816       "  output_dir = \n";
817   EXPECT_EQ(loadable_expected, out.str());
818 
819   // Final target.
820   Target exe(setup.settings(), Label(SourceDir("//foo/"), "exe"));
821   exe.set_output_type(Target::EXECUTABLE);
822   exe.public_deps().push_back(LabelTargetPair(&loadable_module));
823   exe.SetToolchain(setup.toolchain());
824   exe.sources().push_back(SourceFile("//foo/final.cc"));
825   exe.source_types_used().Set(SourceFile::SOURCE_CPP);
826   ASSERT_TRUE(exe.OnResolved(&err)) << err.message();
827 
828   std::ostringstream final_out;
829   NinjaCBinaryTargetWriter final_writer(&exe, final_out);
830   final_writer.Run();
831 
832   // The final output depends on the loadable module so should have an
833   // order-only dependency on the loadable modules's output file.
834   const char final_expected[] =
835       "defines =\n"
836       "include_dirs =\n"
837       "cflags =\n"
838       "cflags_cc =\n"
839       "root_out_dir = .\n"
840       "target_out_dir = obj/foo\n"
841       "target_output_name = exe\n"
842       "\n"
843       "build obj/foo/exe.final.o: cxx ../../foo/final.cc\n"
844       "  source_file_part = final.cc\n"
845       "  source_name_part = final\n"
846       "\n"
847       "build ./exe: link obj/foo/exe.final.o || ./libbar.so\n"
848       "  ldflags =\n"
849       "  libs =\n"
850       "  frameworks =\n"
851       "  swiftmodules =\n"
852       "  output_extension = \n"
853       "  output_dir = \n";
854   EXPECT_EQ(final_expected, final_out.str());
855 }
856 
TEST_F(NinjaCBinaryTargetWriterTest,WinPrecompiledHeaders)857 TEST_F(NinjaCBinaryTargetWriterTest, WinPrecompiledHeaders) {
858   Err err;
859 
860   // This setup's toolchain does not have precompiled headers defined.
861   TestWithScope setup;
862 
863   // A precompiled header toolchain.
864   Settings pch_settings(setup.build_settings(), "withpch/");
865   Toolchain pch_toolchain(&pch_settings,
866                           Label(SourceDir("//toolchain/"), "withpch"));
867   pch_settings.set_toolchain_label(pch_toolchain.label());
868   pch_settings.set_default_toolchain_label(setup.toolchain()->label());
869 
870   // Declare a C++ compiler that supports PCH.
871   std::unique_ptr<Tool> cxx = std::make_unique<CTool>(CTool::kCToolCxx);
872   CTool* cxx_tool = cxx->AsC();
873   TestWithScope::SetCommandForTool(
874       "c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} {{include_dirs}} "
875       "-o {{output}}",
876       cxx_tool);
877   cxx_tool->set_outputs(SubstitutionList::MakeForTest(
878       "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
879   cxx_tool->set_precompiled_header_type(CTool::PCH_MSVC);
880   pch_toolchain.SetTool(std::move(cxx));
881 
882   // Add a C compiler as well.
883   std::unique_ptr<Tool> cc = std::make_unique<CTool>(CTool::kCToolCc);
884   CTool* cc_tool = cc->AsC();
885   TestWithScope::SetCommandForTool(
886       "cc {{source}} {{cflags}} {{cflags_c}} {{defines}} {{include_dirs}} "
887       "-o {{output}}",
888       cc_tool);
889   cc_tool->set_outputs(SubstitutionList::MakeForTest(
890       "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
891   cc_tool->set_precompiled_header_type(CTool::PCH_MSVC);
892   pch_toolchain.SetTool(std::move(cc));
893   pch_toolchain.ToolchainSetupComplete();
894 
895   // This target doesn't specify precompiled headers.
896   {
897     Target no_pch_target(&pch_settings,
898                          Label(SourceDir("//foo/"), "no_pch_target"));
899     no_pch_target.set_output_type(Target::SOURCE_SET);
900     no_pch_target.visibility().SetPublic();
901     no_pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
902     no_pch_target.sources().push_back(SourceFile("//foo/input2.c"));
903     no_pch_target.source_types_used().Set(SourceFile::SOURCE_CPP);
904     no_pch_target.source_types_used().Set(SourceFile::SOURCE_C);
905     no_pch_target.config_values().cflags_c().push_back("-std=c99");
906     no_pch_target.SetToolchain(&pch_toolchain);
907     ASSERT_TRUE(no_pch_target.OnResolved(&err));
908 
909     std::ostringstream out;
910     NinjaCBinaryTargetWriter writer(&no_pch_target, out);
911     writer.Run();
912 
913     const char no_pch_expected[] =
914         "defines =\n"
915         "include_dirs =\n"
916         "cflags =\n"
917         "cflags_c = -std=c99\n"
918         "cflags_cc =\n"
919         "target_output_name = no_pch_target\n"
920         "\n"
921         "build withpch/obj/foo/no_pch_target.input1.o: "
922         "withpch_cxx ../../foo/input1.cc\n"
923         "  source_file_part = input1.cc\n"
924         "  source_name_part = input1\n"
925         "build withpch/obj/foo/no_pch_target.input2.o: "
926         "withpch_cc ../../foo/input2.c\n"
927         "  source_file_part = input2.c\n"
928         "  source_name_part = input2\n"
929         "\n"
930         "build withpch/obj/foo/no_pch_target.stamp: "
931         "withpch_stamp withpch/obj/foo/no_pch_target.input1.o "
932         "withpch/obj/foo/no_pch_target.input2.o\n";
933     EXPECT_EQ(no_pch_expected, out.str());
934   }
935 
936   // This target specifies PCH.
937   {
938     Target pch_target(&pch_settings, Label(SourceDir("//foo/"), "pch_target"));
939     pch_target.config_values().set_precompiled_header("build/precompile.h");
940     pch_target.config_values().set_precompiled_source(
941         SourceFile("//build/precompile.cc"));
942     pch_target.set_output_type(Target::SOURCE_SET);
943     pch_target.visibility().SetPublic();
944     pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
945     pch_target.sources().push_back(SourceFile("//foo/input2.c"));
946     pch_target.source_types_used().Set(SourceFile::SOURCE_CPP);
947     pch_target.source_types_used().Set(SourceFile::SOURCE_C);
948     pch_target.SetToolchain(&pch_toolchain);
949     ASSERT_TRUE(pch_target.OnResolved(&err));
950 
951     std::ostringstream out;
952     NinjaCBinaryTargetWriter writer(&pch_target, out);
953     writer.Run();
954 
955     const char pch_win_expected[] =
956         "defines =\n"
957         "include_dirs =\n"
958         "cflags =\n"
959         // It should output language-specific pch files.
960         "cflags_c = /Fpwithpch/obj/foo/pch_target_c.pch "
961         "/Yubuild/precompile.h\n"
962         "cflags_cc = /Fpwithpch/obj/foo/pch_target_cc.pch "
963         "/Yubuild/precompile.h\n"
964         "target_output_name = pch_target\n"
965         "\n"
966         // Compile the precompiled source files with /Yc.
967         "build withpch/obj/build/pch_target.precompile.c.o: "
968         "withpch_cc ../../build/precompile.cc\n"
969         "  source_file_part = precompile.cc\n"
970         "  source_name_part = precompile\n"
971         "  cflags_c = ${cflags_c} /Ycbuild/precompile.h\n"
972         "\n"
973         "build withpch/obj/build/pch_target.precompile.cc.o: "
974         "withpch_cxx ../../build/precompile.cc\n"
975         "  source_file_part = precompile.cc\n"
976         "  source_name_part = precompile\n"
977         "  cflags_cc = ${cflags_cc} /Ycbuild/precompile.h\n"
978         "\n"
979         "build withpch/obj/foo/pch_target.input1.o: "
980         "withpch_cxx ../../foo/input1.cc | "
981         // Explicit dependency on the PCH build step.
982         "withpch/obj/build/pch_target.precompile.cc.o\n"
983         "  source_file_part = input1.cc\n"
984         "  source_name_part = input1\n"
985         "build withpch/obj/foo/pch_target.input2.o: "
986         "withpch_cc ../../foo/input2.c | "
987         // Explicit dependency on the PCH build step.
988         "withpch/obj/build/pch_target.precompile.c.o\n"
989         "  source_file_part = input2.c\n"
990         "  source_name_part = input2\n"
991         "\n"
992         "build withpch/obj/foo/pch_target.stamp: withpch_stamp "
993         "withpch/obj/foo/pch_target.input1.o "
994         "withpch/obj/foo/pch_target.input2.o "
995         // The precompiled object files were added to the outputs.
996         "withpch/obj/build/pch_target.precompile.c.o "
997         "withpch/obj/build/pch_target.precompile.cc.o\n";
998     EXPECT_EQ(pch_win_expected, out.str());
999   }
1000 }
1001 
TEST_F(NinjaCBinaryTargetWriterTest,GCCPrecompiledHeaders)1002 TEST_F(NinjaCBinaryTargetWriterTest, GCCPrecompiledHeaders) {
1003   Err err;
1004 
1005   // This setup's toolchain does not have precompiled headers defined.
1006   TestWithScope setup;
1007 
1008   // A precompiled header toolchain.
1009   Settings pch_settings(setup.build_settings(), "withpch/");
1010   Toolchain pch_toolchain(&pch_settings,
1011                           Label(SourceDir("//toolchain/"), "withpch"));
1012   pch_settings.set_toolchain_label(pch_toolchain.label());
1013   pch_settings.set_default_toolchain_label(setup.toolchain()->label());
1014 
1015   // Declare a C++ compiler that supports PCH.
1016   std::unique_ptr<Tool> cxx = std::make_unique<CTool>(CTool::kCToolCxx);
1017   CTool* cxx_tool = cxx->AsC();
1018   TestWithScope::SetCommandForTool(
1019       "c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} {{include_dirs}} "
1020       "-o {{output}}",
1021       cxx_tool);
1022   cxx_tool->set_outputs(SubstitutionList::MakeForTest(
1023       "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
1024   cxx_tool->set_precompiled_header_type(CTool::PCH_GCC);
1025   pch_toolchain.SetTool(std::move(cxx));
1026   pch_toolchain.ToolchainSetupComplete();
1027 
1028   // Add a C compiler as well.
1029   std::unique_ptr<Tool> cc = std::make_unique<CTool>(CTool::kCToolCc);
1030   CTool* cc_tool = cc->AsC();
1031   TestWithScope::SetCommandForTool(
1032       "cc {{source}} {{cflags}} {{cflags_c}} {{defines}} {{include_dirs}} "
1033       "-o {{output}}",
1034       cc_tool);
1035   cc_tool->set_outputs(SubstitutionList::MakeForTest(
1036       "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
1037   cc_tool->set_precompiled_header_type(CTool::PCH_GCC);
1038   pch_toolchain.SetTool(std::move(cc));
1039   pch_toolchain.ToolchainSetupComplete();
1040 
1041   // This target doesn't specify precompiled headers.
1042   {
1043     Target no_pch_target(&pch_settings,
1044                          Label(SourceDir("//foo/"), "no_pch_target"));
1045     no_pch_target.set_output_type(Target::SOURCE_SET);
1046     no_pch_target.visibility().SetPublic();
1047     no_pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
1048     no_pch_target.sources().push_back(SourceFile("//foo/input2.c"));
1049     no_pch_target.source_types_used().Set(SourceFile::SOURCE_CPP);
1050     no_pch_target.source_types_used().Set(SourceFile::SOURCE_C);
1051     no_pch_target.config_values().cflags_c().push_back("-std=c99");
1052     no_pch_target.SetToolchain(&pch_toolchain);
1053     ASSERT_TRUE(no_pch_target.OnResolved(&err));
1054 
1055     std::ostringstream out;
1056     NinjaCBinaryTargetWriter writer(&no_pch_target, out);
1057     writer.Run();
1058 
1059     const char no_pch_expected[] =
1060         "defines =\n"
1061         "include_dirs =\n"
1062         "cflags =\n"
1063         "cflags_c = -std=c99\n"
1064         "cflags_cc =\n"
1065         "target_output_name = no_pch_target\n"
1066         "\n"
1067         "build withpch/obj/foo/no_pch_target.input1.o: "
1068         "withpch_cxx ../../foo/input1.cc\n"
1069         "  source_file_part = input1.cc\n"
1070         "  source_name_part = input1\n"
1071         "build withpch/obj/foo/no_pch_target.input2.o: "
1072         "withpch_cc ../../foo/input2.c\n"
1073         "  source_file_part = input2.c\n"
1074         "  source_name_part = input2\n"
1075         "\n"
1076         "build withpch/obj/foo/no_pch_target.stamp: "
1077         "withpch_stamp withpch/obj/foo/no_pch_target.input1.o "
1078         "withpch/obj/foo/no_pch_target.input2.o\n";
1079     EXPECT_EQ(no_pch_expected, out.str());
1080   }
1081 
1082   // This target specifies PCH.
1083   {
1084     Target pch_target(&pch_settings, Label(SourceDir("//foo/"), "pch_target"));
1085     pch_target.config_values().set_precompiled_source(
1086         SourceFile("//build/precompile.h"));
1087     pch_target.config_values().cflags_c().push_back("-std=c99");
1088     pch_target.set_output_type(Target::SOURCE_SET);
1089     pch_target.visibility().SetPublic();
1090     pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
1091     pch_target.sources().push_back(SourceFile("//foo/input2.c"));
1092     pch_target.source_types_used().Set(SourceFile::SOURCE_CPP);
1093     pch_target.source_types_used().Set(SourceFile::SOURCE_C);
1094     pch_target.SetToolchain(&pch_toolchain);
1095     ASSERT_TRUE(pch_target.OnResolved(&err));
1096 
1097     std::ostringstream out;
1098     NinjaCBinaryTargetWriter writer(&pch_target, out);
1099     writer.Run();
1100 
1101     const char pch_gcc_expected[] =
1102         "defines =\n"
1103         "include_dirs =\n"
1104         "cflags =\n"
1105         "cflags_c = -std=c99 "
1106         "-include withpch/obj/build/pch_target.precompile.h-c\n"
1107         "cflags_cc = -include withpch/obj/build/pch_target.precompile.h-cc\n"
1108         "target_output_name = pch_target\n"
1109         "\n"
1110         // Compile the precompiled sources with -x <lang>.
1111         "build withpch/obj/build/pch_target.precompile.h-c.gch: "
1112         "withpch_cc ../../build/precompile.h\n"
1113         "  source_file_part = precompile.h\n"
1114         "  source_name_part = precompile\n"
1115         "  cflags_c = -std=c99 -x c-header\n"
1116         "\n"
1117         "build withpch/obj/build/pch_target.precompile.h-cc.gch: "
1118         "withpch_cxx ../../build/precompile.h\n"
1119         "  source_file_part = precompile.h\n"
1120         "  source_name_part = precompile\n"
1121         "  cflags_cc = -x c++-header\n"
1122         "\n"
1123         "build withpch/obj/foo/pch_target.input1.o: "
1124         "withpch_cxx ../../foo/input1.cc | "
1125         // Explicit dependency on the PCH build step.
1126         "withpch/obj/build/pch_target.precompile.h-cc.gch\n"
1127         "  source_file_part = input1.cc\n"
1128         "  source_name_part = input1\n"
1129         "build withpch/obj/foo/pch_target.input2.o: "
1130         "withpch_cc ../../foo/input2.c | "
1131         // Explicit dependency on the PCH build step.
1132         "withpch/obj/build/pch_target.precompile.h-c.gch\n"
1133         "  source_file_part = input2.c\n"
1134         "  source_name_part = input2\n"
1135         "\n"
1136         "build withpch/obj/foo/pch_target.stamp: "
1137         "withpch_stamp withpch/obj/foo/pch_target.input1.o "
1138         "withpch/obj/foo/pch_target.input2.o\n";
1139     EXPECT_EQ(pch_gcc_expected, out.str());
1140   }
1141 }
1142 
1143 // Should throw an error with the scheduler if a duplicate object file exists.
1144 // This is dependent on the toolchain's object file mapping.
TEST_F(NinjaCBinaryTargetWriterTest,DupeObjFileError)1145 TEST_F(NinjaCBinaryTargetWriterTest, DupeObjFileError) {
1146   TestWithScope setup;
1147   TestTarget target(setup, "//foo:bar", Target::EXECUTABLE);
1148   target.sources().push_back(SourceFile("//a.cc"));
1149   target.sources().push_back(SourceFile("//a.cc"));
1150   target.source_types_used().Set(SourceFile::SOURCE_CPP);
1151 
1152   EXPECT_FALSE(scheduler().is_failed());
1153 
1154   scheduler().SuppressOutputForTesting(true);
1155 
1156   std::ostringstream out;
1157   NinjaCBinaryTargetWriter writer(&target, out);
1158   writer.Run();
1159 
1160   scheduler().SuppressOutputForTesting(false);
1161 
1162   // Should have issued an error.
1163   EXPECT_TRUE(scheduler().is_failed());
1164 }
1165 
1166 // This tests that output extension and output dir overrides apply, and input
1167 // dependencies are applied.
TEST_F(NinjaCBinaryTargetWriterTest,InputFiles)1168 TEST_F(NinjaCBinaryTargetWriterTest, InputFiles) {
1169   Err err;
1170   TestWithScope setup;
1171 
1172   // This target has one input.
1173   {
1174     Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
1175     target.set_output_type(Target::SOURCE_SET);
1176     target.visibility().SetPublic();
1177     target.sources().push_back(SourceFile("//foo/input1.cc"));
1178     target.sources().push_back(SourceFile("//foo/input2.cc"));
1179     target.source_types_used().Set(SourceFile::SOURCE_CPP);
1180     target.config_values().inputs().push_back(SourceFile("//foo/input.data"));
1181     target.SetToolchain(setup.toolchain());
1182     ASSERT_TRUE(target.OnResolved(&err));
1183 
1184     std::ostringstream out;
1185     NinjaCBinaryTargetWriter writer(&target, out);
1186     writer.Run();
1187 
1188     const char expected[] =
1189         "defines =\n"
1190         "include_dirs =\n"
1191         "cflags =\n"
1192         "cflags_cc =\n"
1193         "root_out_dir = .\n"
1194         "target_out_dir = obj/foo\n"
1195         "target_output_name = bar\n"
1196         "\n"
1197         "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc"
1198         " | ../../foo/input.data\n"
1199         "  source_file_part = input1.cc\n"
1200         "  source_name_part = input1\n"
1201         "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc"
1202         " | ../../foo/input.data\n"
1203         "  source_file_part = input2.cc\n"
1204         "  source_name_part = input2\n"
1205         "\n"
1206         "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.o "
1207         "obj/foo/bar.input2.o\n";
1208 
1209     EXPECT_EQ(expected, out.str());
1210   }
1211 
1212   // This target has one input but no source files.
1213   {
1214     Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
1215     target.set_output_type(Target::SHARED_LIBRARY);
1216     target.visibility().SetPublic();
1217     target.config_values().inputs().push_back(SourceFile("//foo/input.data"));
1218     target.SetToolchain(setup.toolchain());
1219     ASSERT_TRUE(target.OnResolved(&err));
1220 
1221     std::ostringstream out;
1222     NinjaCBinaryTargetWriter writer(&target, out);
1223     writer.Run();
1224 
1225     const char expected[] =
1226         "defines =\n"
1227         "include_dirs =\n"
1228         "root_out_dir = .\n"
1229         "target_out_dir = obj/foo\n"
1230         "target_output_name = libbar\n"
1231         "\n"
1232         "\n"
1233         "build ./libbar.so: solink | ../../foo/input.data\n"
1234         "  ldflags =\n"
1235         "  libs =\n"
1236         "  frameworks =\n"
1237         "  swiftmodules =\n"
1238         "  output_extension = .so\n"
1239         "  output_dir = \n";
1240 
1241     EXPECT_EQ(expected, out.str());
1242   }
1243 
1244   // This target has multiple inputs.
1245   {
1246     Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
1247     target.set_output_type(Target::SOURCE_SET);
1248     target.visibility().SetPublic();
1249     target.sources().push_back(SourceFile("//foo/input1.cc"));
1250     target.sources().push_back(SourceFile("//foo/input2.cc"));
1251     target.source_types_used().Set(SourceFile::SOURCE_CPP);
1252     target.config_values().inputs().push_back(SourceFile("//foo/input1.data"));
1253     target.config_values().inputs().push_back(SourceFile("//foo/input2.data"));
1254     target.SetToolchain(setup.toolchain());
1255     ASSERT_TRUE(target.OnResolved(&err));
1256 
1257     std::ostringstream out;
1258     NinjaCBinaryTargetWriter writer(&target, out);
1259     writer.Run();
1260 
1261     const char expected[] =
1262         "defines =\n"
1263         "include_dirs =\n"
1264         "cflags =\n"
1265         "cflags_cc =\n"
1266         "root_out_dir = .\n"
1267         "target_out_dir = obj/foo\n"
1268         "target_output_name = bar\n"
1269         "\n"
1270         "build obj/foo/bar.inputs.stamp: stamp"
1271         " ../../foo/input1.data ../../foo/input2.data\n"
1272         "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc"
1273         " | obj/foo/bar.inputs.stamp\n"
1274         "  source_file_part = input1.cc\n"
1275         "  source_name_part = input1\n"
1276         "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc"
1277         " | obj/foo/bar.inputs.stamp\n"
1278         "  source_file_part = input2.cc\n"
1279         "  source_name_part = input2\n"
1280         "\n"
1281         "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.o "
1282         "obj/foo/bar.input2.o\n";
1283 
1284     EXPECT_EQ(expected, out.str());
1285   }
1286 
1287   // This target has one input itself, one from an immediate config, and one
1288   // from a config tacked on to said config.
1289   {
1290     Config far_config(setup.settings(), Label(SourceDir("//foo/"), "qux"));
1291     far_config.own_values().inputs().push_back(SourceFile("//foo/input3.data"));
1292     ASSERT_TRUE(far_config.OnResolved(&err));
1293 
1294     Config config(setup.settings(), Label(SourceDir("//foo/"), "baz"));
1295     config.visibility().SetPublic();
1296     config.own_values().inputs().push_back(SourceFile("//foo/input2.data"));
1297     config.configs().push_back(LabelConfigPair(&far_config));
1298     ASSERT_TRUE(config.OnResolved(&err));
1299 
1300     Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
1301     target.set_output_type(Target::SOURCE_SET);
1302     target.visibility().SetPublic();
1303     target.sources().push_back(SourceFile("//foo/input1.cc"));
1304     target.sources().push_back(SourceFile("//foo/input2.cc"));
1305     target.source_types_used().Set(SourceFile::SOURCE_CPP);
1306     target.config_values().inputs().push_back(SourceFile("//foo/input1.data"));
1307     target.configs().push_back(LabelConfigPair(&config));
1308     target.SetToolchain(setup.toolchain());
1309     ASSERT_TRUE(target.OnResolved(&err));
1310 
1311     std::ostringstream out;
1312     NinjaCBinaryTargetWriter writer(&target, out);
1313     writer.Run();
1314 
1315     const char expected[] =
1316         "defines =\n"
1317         "include_dirs =\n"
1318         "cflags =\n"
1319         "cflags_cc =\n"
1320         "root_out_dir = .\n"
1321         "target_out_dir = obj/foo\n"
1322         "target_output_name = bar\n"
1323         "\n"
1324         "build obj/foo/bar.inputs.stamp: stamp"
1325         " ../../foo/input1.data ../../foo/input2.data ../../foo/input3.data\n"
1326         "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc"
1327         " | obj/foo/bar.inputs.stamp\n"
1328         "  source_file_part = input1.cc\n"
1329         "  source_name_part = input1\n"
1330         "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc"
1331         " | obj/foo/bar.inputs.stamp\n"
1332         "  source_file_part = input2.cc\n"
1333         "  source_name_part = input2\n"
1334         "\n"
1335         "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.o "
1336         "obj/foo/bar.input2.o\n";
1337 
1338     EXPECT_EQ(expected, out.str());
1339   }
1340 }
1341 
1342 // Test linking of Rust dependencies into C targets.
TEST_F(NinjaCBinaryTargetWriterTest,RustStaticLib)1343 TEST_F(NinjaCBinaryTargetWriterTest, RustStaticLib) {
1344   Err err;
1345   TestWithScope setup;
1346 
1347   Target library_target(setup.settings(), Label(SourceDir("//foo/"), "foo"));
1348   library_target.set_output_type(Target::STATIC_LIBRARY);
1349   library_target.visibility().SetPublic();
1350   SourceFile lib("//foo/lib.rs");
1351   library_target.sources().push_back(lib);
1352   library_target.source_types_used().Set(SourceFile::SOURCE_RS);
1353   library_target.rust_values().set_crate_root(lib);
1354   library_target.rust_values().crate_name() = "foo";
1355   library_target.SetToolchain(setup.toolchain());
1356   ASSERT_TRUE(library_target.OnResolved(&err));
1357 
1358   Target target(setup.settings(), Label(SourceDir("//bar/"), "bar"));
1359   target.set_output_type(Target::EXECUTABLE);
1360   target.visibility().SetPublic();
1361   target.sources().push_back(SourceFile("//bar/bar.cc"));
1362   target.source_types_used().Set(SourceFile::SOURCE_CPP);
1363   target.private_deps().push_back(LabelTargetPair(&library_target));
1364   target.SetToolchain(setup.toolchain());
1365   ASSERT_TRUE(target.OnResolved(&err));
1366 
1367   std::ostringstream out;
1368   NinjaCBinaryTargetWriter writer(&target, out);
1369   writer.Run();
1370 
1371   const char expected[] =
1372       "defines =\n"
1373       "include_dirs =\n"
1374       "cflags =\n"
1375       "cflags_cc =\n"
1376       "root_out_dir = .\n"
1377       "target_out_dir = obj/bar\n"
1378       "target_output_name = bar\n"
1379       "\n"
1380       "build obj/bar/bar.bar.o: cxx ../../bar/bar.cc\n"
1381       "  source_file_part = bar.cc\n"
1382       "  source_name_part = bar\n"
1383       "\n"
1384       "build ./bar: link obj/bar/bar.bar.o obj/foo/libfoo.a\n"
1385       "  ldflags =\n"
1386       "  libs =\n"
1387       "  frameworks =\n"
1388       "  swiftmodules =\n"
1389       "  output_extension = \n"
1390       "  output_dir = \n";
1391 
1392   std::string out_str = out.str();
1393   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1394 }
1395 
1396 // Test linking of Rust dependencies into C targets.
TEST_F(NinjaCBinaryTargetWriterTest,RlibInLibrary)1397 TEST_F(NinjaCBinaryTargetWriterTest, RlibInLibrary) {
1398   Err err;
1399   TestWithScope setup;
1400 
1401   // This source_set() is depended on by an rlib, which is a private dep of a
1402   // static lib.
1403   Target priv_sset_in_staticlib(
1404       setup.settings(),
1405       Label(SourceDir("//priv_sset_in_staticlib/"), "priv_sset_in_staticlib"));
1406   priv_sset_in_staticlib.set_output_type(Target::SOURCE_SET);
1407   priv_sset_in_staticlib.visibility().SetPublic();
1408   priv_sset_in_staticlib.sources().push_back(
1409       SourceFile("//priv_sset_in_staticlib/lib.cc"));
1410   priv_sset_in_staticlib.source_types_used().Set(SourceFile::SOURCE_CPP);
1411   priv_sset_in_staticlib.SetToolchain(setup.toolchain());
1412   ASSERT_TRUE(priv_sset_in_staticlib.OnResolved(&err));
1413 
1414   // This source_set() is depended on by an rlib, which is a public dep of a
1415   // static lib.
1416   Target pub_sset_in_staticlib(
1417       setup.settings(),
1418       Label(SourceDir("//pub_sset_in_staticlib/"), "pub_sset_in_staticlib"));
1419   pub_sset_in_staticlib.set_output_type(Target::SOURCE_SET);
1420   pub_sset_in_staticlib.visibility().SetPublic();
1421   pub_sset_in_staticlib.sources().push_back(
1422       SourceFile("//pub_sset_in_staticlib/lib.cc"));
1423   pub_sset_in_staticlib.source_types_used().Set(SourceFile::SOURCE_CPP);
1424   pub_sset_in_staticlib.SetToolchain(setup.toolchain());
1425   ASSERT_TRUE(pub_sset_in_staticlib.OnResolved(&err));
1426 
1427   // This source_set() is depended on by an rlib, which is a private dep of a
1428   // shared lib.
1429   Target priv_sset_in_dylib(
1430       setup.settings(),
1431       Label(SourceDir("//priv_sset_in_dylib/"), "priv_sset_in_dylib"));
1432   priv_sset_in_dylib.set_output_type(Target::SOURCE_SET);
1433   priv_sset_in_dylib.visibility().SetPublic();
1434   priv_sset_in_dylib.sources().push_back(
1435       SourceFile("//priv_sset_in_dylib/lib.cc"));
1436   priv_sset_in_dylib.source_types_used().Set(SourceFile::SOURCE_CPP);
1437   priv_sset_in_dylib.SetToolchain(setup.toolchain());
1438   ASSERT_TRUE(priv_sset_in_dylib.OnResolved(&err));
1439 
1440   // This source_set() is depended on by an rlib, which is a public dep of a
1441   // shared lib.
1442   Target pub_sset_in_dylib(
1443       setup.settings(),
1444       Label(SourceDir("//pub_sset_in_dylib"), "pub_sset_in_dylib"));
1445   pub_sset_in_dylib.set_output_type(Target::SOURCE_SET);
1446   pub_sset_in_dylib.visibility().SetPublic();
1447   pub_sset_in_dylib.sources().push_back(
1448       SourceFile("//pub_sset_in_dylib/lib.cc"));
1449   pub_sset_in_dylib.source_types_used().Set(SourceFile::SOURCE_CPP);
1450   pub_sset_in_dylib.SetToolchain(setup.toolchain());
1451   ASSERT_TRUE(pub_sset_in_dylib.OnResolved(&err));
1452 
1453   Target priv_in_staticlib(
1454       setup.settings(),
1455       Label(SourceDir("//priv_in_staticlib/"), "priv_in_staticlib"));
1456   priv_in_staticlib.set_output_type(Target::RUST_LIBRARY);
1457   priv_in_staticlib.visibility().SetPublic();
1458   SourceFile priv_in_staticlib_root("//priv_in_staticlib/lib.rs");
1459   priv_in_staticlib.sources().push_back(priv_in_staticlib_root);
1460   priv_in_staticlib.source_types_used().Set(SourceFile::SOURCE_RS);
1461   priv_in_staticlib.rust_values().set_crate_root(priv_in_staticlib_root);
1462   priv_in_staticlib.rust_values().crate_name() = "priv_in_staticlib";
1463   priv_in_staticlib.SetToolchain(setup.toolchain());
1464   priv_in_staticlib.private_deps().push_back(
1465       LabelTargetPair(&priv_sset_in_staticlib));
1466   ASSERT_TRUE(priv_in_staticlib.OnResolved(&err));
1467 
1468   Target pub_in_staticlib(
1469       setup.settings(),
1470       Label(SourceDir("//pub_in_staticlib/"), "pub_in_staticlib"));
1471   pub_in_staticlib.set_output_type(Target::RUST_LIBRARY);
1472   pub_in_staticlib.visibility().SetPublic();
1473   SourceFile pub_in_staticlib_root("//pub_in_staticlib/lib.rs");
1474   pub_in_staticlib.sources().push_back(pub_in_staticlib_root);
1475   pub_in_staticlib.source_types_used().Set(SourceFile::SOURCE_RS);
1476   pub_in_staticlib.rust_values().set_crate_root(pub_in_staticlib_root);
1477   pub_in_staticlib.rust_values().crate_name() = "pub_in_staticlib";
1478   pub_in_staticlib.SetToolchain(setup.toolchain());
1479   pub_in_staticlib.private_deps().push_back(
1480       LabelTargetPair(&pub_sset_in_staticlib));
1481   ASSERT_TRUE(pub_in_staticlib.OnResolved(&err));
1482 
1483   Target priv_in_dylib(setup.settings(),
1484                        Label(SourceDir("//priv_in_dylib/"), "priv_in_dylib"));
1485   priv_in_dylib.set_output_type(Target::RUST_LIBRARY);
1486   priv_in_dylib.visibility().SetPublic();
1487   SourceFile priv_in_dylib_root("//priv_in_dylib/lib.rs");
1488   priv_in_dylib.sources().push_back(priv_in_dylib_root);
1489   priv_in_dylib.source_types_used().Set(SourceFile::SOURCE_RS);
1490   priv_in_dylib.rust_values().set_crate_root(priv_in_dylib_root);
1491   priv_in_dylib.rust_values().crate_name() = "priv_in_dylib";
1492   priv_in_dylib.SetToolchain(setup.toolchain());
1493   priv_in_dylib.private_deps().push_back(LabelTargetPair(&priv_sset_in_dylib));
1494   ASSERT_TRUE(priv_in_dylib.OnResolved(&err));
1495 
1496   Target pub_in_dylib(setup.settings(),
1497                       Label(SourceDir("//pub_in_dylib/"), "pub_in_dylib"));
1498   pub_in_dylib.set_output_type(Target::RUST_LIBRARY);
1499   pub_in_dylib.visibility().SetPublic();
1500   SourceFile pub_in_dylib_root("//pub_in_dylib/lib.rs");
1501   pub_in_dylib.sources().push_back(pub_in_dylib_root);
1502   pub_in_dylib.source_types_used().Set(SourceFile::SOURCE_RS);
1503   pub_in_dylib.rust_values().set_crate_root(pub_in_dylib_root);
1504   pub_in_dylib.rust_values().crate_name() = "pub_in_dylib";
1505   pub_in_dylib.SetToolchain(setup.toolchain());
1506   pub_in_dylib.private_deps().push_back(LabelTargetPair(&pub_sset_in_dylib));
1507   ASSERT_TRUE(pub_in_dylib.OnResolved(&err));
1508 
1509   Target staticlib(setup.settings(),
1510                    Label(SourceDir("//staticlib/"), "staticlib"));
1511   staticlib.set_output_type(Target::STATIC_LIBRARY);
1512   staticlib.visibility().SetPublic();
1513   staticlib.sources().push_back(SourceFile("//staticlib/lib.cc"));
1514   staticlib.source_types_used().Set(SourceFile::SOURCE_CPP);
1515   staticlib.public_deps().push_back(LabelTargetPair(&pub_in_staticlib));
1516   staticlib.private_deps().push_back(LabelTargetPair(&priv_in_staticlib));
1517   staticlib.SetToolchain(setup.toolchain());
1518   ASSERT_TRUE(staticlib.OnResolved(&err));
1519 
1520   Target dylib(setup.settings(), Label(SourceDir("//dylib/"), "dylib"));
1521   dylib.set_output_type(Target::SHARED_LIBRARY);
1522   dylib.visibility().SetPublic();
1523   SourceFile dylib_root("//dylib/lib.rs");
1524   dylib.sources().push_back(dylib_root);
1525   dylib.source_types_used().Set(SourceFile::SOURCE_RS);
1526   dylib.rust_values().set_crate_root(dylib_root);
1527   dylib.rust_values().crate_name() = "dylib";
1528   dylib.public_deps().push_back(LabelTargetPair(&pub_in_dylib));
1529   dylib.private_deps().push_back(LabelTargetPair(&priv_in_dylib));
1530   dylib.SetToolchain(setup.toolchain());
1531   ASSERT_TRUE(dylib.OnResolved(&err));
1532 
1533   Target target(setup.settings(), Label(SourceDir("//exe/"), "exe"));
1534   target.set_output_type(Target::EXECUTABLE);
1535   target.visibility().SetPublic();
1536   target.sources().push_back(SourceFile("//exe/main.cc"));
1537   target.source_types_used().Set(SourceFile::SOURCE_CPP);
1538   target.private_deps().push_back(LabelTargetPair(&staticlib));
1539   target.private_deps().push_back(LabelTargetPair(&dylib));
1540   target.SetToolchain(setup.toolchain());
1541   ASSERT_TRUE(target.OnResolved(&err));
1542 
1543 
1544   std::ostringstream out;
1545   NinjaCBinaryTargetWriter writer(&target, out);
1546   writer.Run();
1547 
1548   const char expected[] =
1549       "defines =\n"
1550       "include_dirs =\n"
1551       "cflags =\n"
1552       "cflags_cc =\n"
1553       "root_out_dir = .\n"
1554       "target_out_dir = obj/exe\n"
1555       "target_output_name = exe\n"
1556       "\n"
1557       "build obj/exe/exe.main.o: cxx ../../exe/main.cc\n"
1558       "  source_file_part = main.cc\n"
1559       "  source_name_part = main\n"
1560       "\n"
1561       "build ./exe: link obj/exe/exe.main.o "
1562       "obj/pub_sset_in_staticlib/pub_sset_in_staticlib.lib.o "
1563       "obj/priv_sset_in_staticlib/priv_sset_in_staticlib.lib.o "
1564       "obj/staticlib/libstaticlib.a "
1565       "obj/dylib/libdylib.so | "
1566       "obj/pub_in_staticlib/libpub_in_staticlib.rlib "
1567       "obj/priv_in_staticlib/libpriv_in_staticlib.rlib || "
1568       "obj/pub_sset_in_staticlib/pub_sset_in_staticlib.stamp "
1569       "obj/priv_sset_in_staticlib/priv_sset_in_staticlib.stamp\n"
1570       "  ldflags =\n"
1571       "  libs =\n"
1572       "  frameworks =\n"
1573       "  swiftmodules =\n"
1574       "  output_extension = \n"
1575       "  output_dir = \n"
1576       "  rlibs = obj/pub_in_staticlib/libpub_in_staticlib.rlib "
1577       "obj/priv_in_staticlib/libpriv_in_staticlib.rlib\n";
1578 
1579   std::string out_str = out.str();
1580   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1581 }
1582 
1583 // Test linking of Rust dependencies into C targets. Proc-macro dependencies are
1584 // not inherited by the targets that depend on them, even from public_deps,
1585 // since they are not built into those targets, but instead used to build them.
TEST_F(NinjaCBinaryTargetWriterTest,RlibsWithProcMacros)1586 TEST_F(NinjaCBinaryTargetWriterTest, RlibsWithProcMacros) {
1587   Err err;
1588   TestWithScope setup;
1589 
1590   Target pub_in_staticlib(
1591       setup.settings(),
1592       Label(SourceDir("//pub_in_staticlib/"), "pub_in_staticlib"));
1593   pub_in_staticlib.set_output_type(Target::RUST_LIBRARY);
1594   pub_in_staticlib.visibility().SetPublic();
1595   SourceFile pub_in_staticlib_root("//pub_in_staticlib/lib.rs");
1596   pub_in_staticlib.sources().push_back(pub_in_staticlib_root);
1597   pub_in_staticlib.source_types_used().Set(SourceFile::SOURCE_RS);
1598   pub_in_staticlib.rust_values().set_crate_root(pub_in_staticlib_root);
1599   pub_in_staticlib.rust_values().crate_name() = "pub_in_staticlib";
1600   pub_in_staticlib.SetToolchain(setup.toolchain());
1601   ASSERT_TRUE(pub_in_staticlib.OnResolved(&err));
1602 
1603   Target priv_in_staticlib(
1604       setup.settings(),
1605       Label(SourceDir("//priv_in_staticlib/"), "priv_in_staticlib"));
1606   priv_in_staticlib.set_output_type(Target::RUST_LIBRARY);
1607   priv_in_staticlib.visibility().SetPublic();
1608   SourceFile priv_in_staticlib_root("//priv_in_staticlib/lib.rs");
1609   priv_in_staticlib.sources().push_back(priv_in_staticlib_root);
1610   priv_in_staticlib.source_types_used().Set(SourceFile::SOURCE_RS);
1611   priv_in_staticlib.rust_values().set_crate_root(priv_in_staticlib_root);
1612   priv_in_staticlib.rust_values().crate_name() = "priv_in_staticlib";
1613   priv_in_staticlib.SetToolchain(setup.toolchain());
1614   ASSERT_TRUE(priv_in_staticlib.OnResolved(&err));
1615 
1616   Target staticlib(setup.settings(),
1617                    Label(SourceDir("//staticlib/"), "staticlib"));
1618   staticlib.set_output_type(Target::STATIC_LIBRARY);
1619   staticlib.visibility().SetPublic();
1620   staticlib.sources().push_back(SourceFile("//staticlib/lib.cc"));
1621   staticlib.source_types_used().Set(SourceFile::SOURCE_CPP);
1622   staticlib.public_deps().push_back(LabelTargetPair(&pub_in_staticlib));
1623   staticlib.private_deps().push_back(LabelTargetPair(&priv_in_staticlib));
1624   staticlib.SetToolchain(setup.toolchain());
1625   ASSERT_TRUE(staticlib.OnResolved(&err));
1626 
1627   Target priv_in_procmacro(
1628       setup.settings(),
1629       Label(SourceDir("//priv_in_procmacro/"), "priv_in_procmacro"));
1630   priv_in_procmacro.set_output_type(Target::RUST_LIBRARY);
1631   priv_in_procmacro.visibility().SetPublic();
1632   SourceFile priv_in_procmacro_root("//priv_in_procmacro/lib.rs");
1633   priv_in_procmacro.sources().push_back(priv_in_procmacro_root);
1634   priv_in_procmacro.source_types_used().Set(SourceFile::SOURCE_RS);
1635   priv_in_procmacro.rust_values().set_crate_root(priv_in_procmacro_root);
1636   priv_in_procmacro.rust_values().crate_name() = "priv_in_procmacro";
1637   priv_in_procmacro.SetToolchain(setup.toolchain());
1638   ASSERT_TRUE(priv_in_procmacro.OnResolved(&err));
1639 
1640   // Public deps in a proc-macro are not inherited, since the proc-macro is not
1641   // compiled into targets that depend on it.
1642   Target pub_in_procmacro(
1643       setup.settings(),
1644       Label(SourceDir("//pub_in_procmacro/"), "pub_in_procmacro"));
1645   pub_in_procmacro.set_output_type(Target::RUST_LIBRARY);
1646   pub_in_procmacro.visibility().SetPublic();
1647   SourceFile pub_in_procmacro_root("//pub_in_procmacro/lib.rs");
1648   pub_in_procmacro.sources().push_back(pub_in_procmacro_root);
1649   pub_in_procmacro.source_types_used().Set(SourceFile::SOURCE_RS);
1650   pub_in_procmacro.rust_values().set_crate_root(pub_in_procmacro_root);
1651   pub_in_procmacro.rust_values().crate_name() = "pub_in_procmacro";
1652   pub_in_procmacro.SetToolchain(setup.toolchain());
1653   ASSERT_TRUE(pub_in_procmacro.OnResolved(&err));
1654 
1655   Target pub_in_procmacro_and_rlib(
1656       setup.settings(), Label(SourceDir("//pub_in_procmacro_and_rlib/"),
1657                               "pub_in_procmacro_and_rlib"));
1658   pub_in_procmacro_and_rlib.set_output_type(Target::RUST_LIBRARY);
1659   pub_in_procmacro_and_rlib.visibility().SetPublic();
1660   SourceFile pub_in_procmacro_and_rlib_root(
1661       "//pub_in_procmacro_and_rlib/lib.rs");
1662   pub_in_procmacro_and_rlib.sources().push_back(pub_in_procmacro_and_rlib_root);
1663   pub_in_procmacro_and_rlib.source_types_used().Set(SourceFile::SOURCE_RS);
1664   pub_in_procmacro_and_rlib.rust_values().set_crate_root(
1665       pub_in_procmacro_and_rlib_root);
1666   pub_in_procmacro_and_rlib.rust_values().crate_name() = "lib2";
1667   pub_in_procmacro_and_rlib.SetToolchain(setup.toolchain());
1668   ASSERT_TRUE(pub_in_procmacro_and_rlib.OnResolved(&err));
1669 
1670   Target procmacro(setup.settings(),
1671                    Label(SourceDir("//procmacro/"), "procmacro"));
1672   procmacro.set_output_type(Target::RUST_PROC_MACRO);
1673   procmacro.visibility().SetPublic();
1674   SourceFile procmacrolib("//procmacro/lib.rs");
1675   procmacro.sources().push_back(procmacrolib);
1676   procmacro.source_types_used().Set(SourceFile::SOURCE_RS);
1677   procmacro.public_deps().push_back(LabelTargetPair(&pub_in_procmacro));
1678   procmacro.public_deps().push_back(LabelTargetPair(&priv_in_procmacro));
1679   procmacro.public_deps().push_back(
1680       LabelTargetPair(&pub_in_procmacro_and_rlib));
1681   procmacro.rust_values().set_crate_root(procmacrolib);
1682   procmacro.rust_values().crate_name() = "procmacro";
1683   procmacro.SetToolchain(setup.toolchain());
1684   ASSERT_TRUE(procmacro.OnResolved(&err));
1685 
1686   Target rlib(setup.settings(), Label(SourceDir("//rlib/"), "rlib"));
1687   rlib.set_output_type(Target::RUST_LIBRARY);
1688   rlib.visibility().SetPublic();
1689   SourceFile rlib_root("//rlib/lib.rs");
1690   rlib.sources().push_back(rlib_root);
1691   rlib.source_types_used().Set(SourceFile::SOURCE_RS);
1692   rlib.public_deps().push_back(LabelTargetPair(&pub_in_procmacro_and_rlib));
1693   // Transitive proc macros should not impact C++ targets; we're
1694   // adding one to ensure the ninja instructions below are unaffected.
1695   rlib.public_deps().push_back(LabelTargetPair(&procmacro));
1696   rlib.rust_values().set_crate_root(rlib_root);
1697   rlib.rust_values().crate_name() = "rlib";
1698   rlib.SetToolchain(setup.toolchain());
1699   ASSERT_TRUE(rlib.OnResolved(&err));
1700 
1701   Target target(setup.settings(), Label(SourceDir("//exe/"), "exe"));
1702   target.set_output_type(Target::EXECUTABLE);
1703   target.visibility().SetPublic();
1704   target.sources().push_back(SourceFile("//exe/main.cc"));
1705   target.source_types_used().Set(SourceFile::SOURCE_CPP);
1706   target.private_deps().push_back(LabelTargetPair(&staticlib));
1707   target.private_deps().push_back(LabelTargetPair(&rlib));
1708   target.SetToolchain(setup.toolchain());
1709   ASSERT_TRUE(target.OnResolved(&err));
1710 
1711   std::ostringstream out;
1712   NinjaCBinaryTargetWriter writer(&target, out);
1713   writer.Run();
1714 
1715   const char expected[] =
1716       "defines =\n"
1717       "include_dirs =\n"
1718       "cflags =\n"
1719       "cflags_cc =\n"
1720       "root_out_dir = .\n"
1721       "target_out_dir = obj/exe\n"
1722       "target_output_name = exe\n"
1723       "\n"
1724       "build obj/exe/exe.main.o: cxx ../../exe/main.cc\n"
1725       "  source_file_part = main.cc\n"
1726       "  source_name_part = main\n"
1727       "\n"
1728       "build ./exe: link obj/exe/exe.main.o "
1729       "obj/staticlib/libstaticlib.a | "
1730       "obj/pub_in_staticlib/libpub_in_staticlib.rlib "
1731       "obj/priv_in_staticlib/libpriv_in_staticlib.rlib "
1732       "obj/rlib/librlib.rlib "
1733       "obj/pub_in_procmacro_and_rlib/libpub_in_procmacro_and_rlib.rlib\n"
1734       "  ldflags =\n"
1735       "  libs =\n"
1736       "  frameworks =\n"
1737       "  swiftmodules =\n"
1738       "  output_extension = \n"
1739       "  output_dir = \n"
1740       "  rlibs = obj/pub_in_staticlib/libpub_in_staticlib.rlib "
1741       "obj/priv_in_staticlib/libpriv_in_staticlib.rlib "
1742       "obj/rlib/librlib.rlib "
1743       "obj/pub_in_procmacro_and_rlib/libpub_in_procmacro_and_rlib.rlib\n";
1744 
1745   std::string out_str = out.str();
1746   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1747 }
1748 
1749 // Test linking of Rust dependencies into C targets.
TEST_F(NinjaCBinaryTargetWriterTest,ProcMacroInRustStaticLib)1750 TEST_F(NinjaCBinaryTargetWriterTest, ProcMacroInRustStaticLib) {
1751   Err err;
1752   TestWithScope setup;
1753 
1754   Target procmacro(setup.settings(), Label(SourceDir("//baz/"), "macro"));
1755   procmacro.set_output_type(Target::LOADABLE_MODULE);
1756   procmacro.visibility().SetPublic();
1757   SourceFile bazlib("//baz/lib.rs");
1758   procmacro.sources().push_back(bazlib);
1759   procmacro.source_types_used().Set(SourceFile::SOURCE_RS);
1760   procmacro.rust_values().set_crate_root(bazlib);
1761   procmacro.rust_values().crate_name() = "macro";
1762   procmacro.rust_values().set_crate_type(RustValues::CRATE_PROC_MACRO);
1763   procmacro.SetToolchain(setup.toolchain());
1764   ASSERT_TRUE(procmacro.OnResolved(&err));
1765 
1766   Target library_target(setup.settings(), Label(SourceDir("//foo/"), "foo"));
1767   library_target.set_output_type(Target::STATIC_LIBRARY);
1768   library_target.visibility().SetPublic();
1769   SourceFile lib("//foo/lib.rs");
1770   library_target.sources().push_back(lib);
1771   library_target.source_types_used().Set(SourceFile::SOURCE_RS);
1772   library_target.rust_values().set_crate_root(lib);
1773   library_target.rust_values().crate_name() = "foo";
1774   library_target.public_deps().push_back(LabelTargetPair(&procmacro));
1775   library_target.SetToolchain(setup.toolchain());
1776   ASSERT_TRUE(library_target.OnResolved(&err));
1777 
1778   Target target(setup.settings(), Label(SourceDir("//bar/"), "bar"));
1779   target.set_output_type(Target::EXECUTABLE);
1780   target.visibility().SetPublic();
1781   target.sources().push_back(SourceFile("//bar/bar.cc"));
1782   target.source_types_used().Set(SourceFile::SOURCE_CPP);
1783   target.private_deps().push_back(LabelTargetPair(&library_target));
1784   target.SetToolchain(setup.toolchain());
1785   ASSERT_TRUE(target.OnResolved(&err));
1786 
1787   std::ostringstream out;
1788   NinjaCBinaryTargetWriter writer(&target, out);
1789   writer.Run();
1790 
1791   const char expected[] =
1792       "defines =\n"
1793       "include_dirs =\n"
1794       "cflags =\n"
1795       "cflags_cc =\n"
1796       "root_out_dir = .\n"
1797       "target_out_dir = obj/bar\n"
1798       "target_output_name = bar\n"
1799       "\n"
1800       "build obj/bar/bar.bar.o: cxx ../../bar/bar.cc\n"
1801       "  source_file_part = bar.cc\n"
1802       "  source_name_part = bar\n"
1803       "\n"
1804       "build ./bar: link obj/bar/bar.bar.o obj/foo/libfoo.a\n"
1805       "  ldflags =\n"
1806       "  libs =\n"
1807       "  frameworks =\n"
1808       "  swiftmodules =\n"
1809       "  output_extension = \n"
1810       "  output_dir = \n";
1811 
1812   std::string out_str = out.str();
1813   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1814 }
1815 
TEST_F(NinjaCBinaryTargetWriterTest,RustDepsOverDynamicLinking)1816 TEST_F(NinjaCBinaryTargetWriterTest, RustDepsOverDynamicLinking) {
1817   Err err;
1818   TestWithScope setup;
1819 
1820   Target rlib3(setup.settings(), Label(SourceDir("//baz/"), "baz"));
1821   rlib3.set_output_type(Target::RUST_LIBRARY);
1822   rlib3.visibility().SetPublic();
1823   SourceFile lib3("//baz/lib.rs");
1824   rlib3.sources().push_back(lib3);
1825   rlib3.source_types_used().Set(SourceFile::SOURCE_RS);
1826   rlib3.rust_values().set_crate_root(lib3);
1827   rlib3.rust_values().crate_name() = "baz";
1828   rlib3.SetToolchain(setup.toolchain());
1829   ASSERT_TRUE(rlib3.OnResolved(&err));
1830 
1831   Target rlib2(setup.settings(), Label(SourceDir("//bar/"), "bar"));
1832   rlib2.set_output_type(Target::RUST_LIBRARY);
1833   rlib2.visibility().SetPublic();
1834   SourceFile lib2("//bar/lib.rs");
1835   rlib2.sources().push_back(lib2);
1836   rlib2.source_types_used().Set(SourceFile::SOURCE_RS);
1837   rlib2.rust_values().set_crate_root(lib2);
1838   rlib2.rust_values().crate_name() = "bar";
1839   rlib2.SetToolchain(setup.toolchain());
1840   ASSERT_TRUE(rlib2.OnResolved(&err));
1841 
1842   Target rlib(setup.settings(), Label(SourceDir("//foo/"), "foo"));
1843   rlib.set_output_type(Target::RUST_LIBRARY);
1844   rlib.visibility().SetPublic();
1845   SourceFile lib("//foo/lib.rs");
1846   rlib.sources().push_back(lib);
1847   rlib.source_types_used().Set(SourceFile::SOURCE_RS);
1848   rlib.rust_values().set_crate_root(lib);
1849   rlib.rust_values().crate_name() = "foo";
1850   rlib.public_deps().push_back(LabelTargetPair(&rlib2));
1851   rlib.SetToolchain(setup.toolchain());
1852   ASSERT_TRUE(rlib.OnResolved(&err));
1853 
1854   Target cdylib(setup.settings(), Label(SourceDir("//sh/"), "mylib"));
1855   cdylib.set_output_type(Target::SHARED_LIBRARY);
1856   cdylib.visibility().SetPublic();
1857   SourceFile barlib("//sh/lib.rs");
1858   cdylib.sources().push_back(barlib);
1859   cdylib.source_types_used().Set(SourceFile::SOURCE_RS);
1860   cdylib.rust_values().set_crate_type(RustValues::CRATE_CDYLIB);
1861   cdylib.rust_values().set_crate_root(barlib);
1862   cdylib.rust_values().crate_name() = "mylib";
1863   cdylib.private_deps().push_back(LabelTargetPair(&rlib));
1864   cdylib.public_deps().push_back(LabelTargetPair(&rlib3));
1865   cdylib.SetToolchain(setup.toolchain());
1866   ASSERT_TRUE(cdylib.OnResolved(&err));
1867 
1868   Target nearrlib(setup.settings(), Label(SourceDir("//near/"), "near"));
1869   nearrlib.set_output_type(Target::RUST_LIBRARY);
1870   nearrlib.visibility().SetPublic();
1871   SourceFile nearlib("//near/lib.rs");
1872   nearrlib.sources().push_back(nearlib);
1873   nearrlib.source_types_used().Set(SourceFile::SOURCE_RS);
1874   nearrlib.rust_values().set_crate_root(nearlib);
1875   nearrlib.rust_values().crate_name() = "near";
1876   nearrlib.public_deps().push_back(LabelTargetPair(&cdylib));
1877   nearrlib.SetToolchain(setup.toolchain());
1878   ASSERT_TRUE(nearrlib.OnResolved(&err));
1879 
1880   Target target(setup.settings(), Label(SourceDir("//exe/"), "binary"));
1881   target.set_output_type(Target::EXECUTABLE);
1882   target.visibility().SetPublic();
1883   target.sources().push_back(SourceFile("//exe/main.cc"));
1884   target.source_types_used().Set(SourceFile::SOURCE_CPP);
1885   target.private_deps().push_back(LabelTargetPair(&nearrlib));
1886   target.SetToolchain(setup.toolchain());
1887   ASSERT_TRUE(target.OnResolved(&err));
1888 
1889   std::ostringstream out;
1890   NinjaCBinaryTargetWriter writer(&target, out);
1891   writer.Run();
1892 
1893   const char expected[] =
1894       "defines =\n"
1895       "include_dirs =\n"
1896       "cflags =\n"
1897       "cflags_cc =\n"
1898       "root_out_dir = .\n"
1899       "target_out_dir = obj/exe\n"
1900       "target_output_name = binary\n"
1901       "\n"
1902       "build obj/exe/binary.main.o: cxx ../../exe/main.cc\n"
1903       "  source_file_part = main.cc\n"
1904       "  source_name_part = main\n"
1905       "\n"
1906       "build ./binary: link obj/exe/binary.main.o obj/sh/libmylib.so | "
1907       "obj/near/libnear.rlib\n"
1908       "  ldflags =\n"
1909       "  libs =\n"
1910       "  frameworks =\n"
1911       "  swiftmodules =\n"
1912       "  output_extension = \n"
1913       "  output_dir = \n"
1914       "  rlibs = obj/near/libnear.rlib\n";
1915 
1916   std::string out_str = out.str();
1917   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1918 }
1919 
TEST_F(NinjaCBinaryTargetWriterTest,LinkingWithRustLibraryDepsOnCdylib)1920 TEST_F(NinjaCBinaryTargetWriterTest, LinkingWithRustLibraryDepsOnCdylib) {
1921   Err err;
1922   TestWithScope setup;
1923 
1924   // A non-rust shared library.
1925   Target cc_shlib(setup.settings(), Label(SourceDir("//cc_shlib"), "cc_shlib"));
1926   cc_shlib.set_output_type(Target::SHARED_LIBRARY);
1927   cc_shlib.set_output_name("cc_shlib");
1928   cc_shlib.SetToolchain(setup.toolchain());
1929   cc_shlib.visibility().SetPublic();
1930   ASSERT_TRUE(cc_shlib.OnResolved(&err));
1931 
1932   // A Rust CDYLIB shared library that will be in deps.
1933   Target rust_shlib(setup.settings(),
1934                     Label(SourceDir("//rust_shlib/"), "rust_shlib"));
1935   rust_shlib.set_output_type(Target::SHARED_LIBRARY);
1936   rust_shlib.visibility().SetPublic();
1937   SourceFile rust_shlib_rs("//rust_shlib/lib.rs");
1938   rust_shlib.sources().push_back(rust_shlib_rs);
1939   rust_shlib.source_types_used().Set(SourceFile::SOURCE_RS);
1940   rust_shlib.rust_values().set_crate_type(RustValues::CRATE_CDYLIB);
1941   rust_shlib.rust_values().set_crate_root(rust_shlib_rs);
1942   rust_shlib.rust_values().crate_name() = "rust_shlib";
1943   rust_shlib.SetToolchain(setup.toolchain());
1944   ASSERT_TRUE(rust_shlib.OnResolved(&err));
1945 
1946   // A Rust DYLIB shared library that will be in public_deps.
1947   Target pub_rust_shlib(setup.settings(), Label(SourceDir("//pub_rust_shlib/"),
1948                                                 "pub_rust_shlib"));
1949   pub_rust_shlib.set_output_type(Target::SHARED_LIBRARY);
1950   pub_rust_shlib.visibility().SetPublic();
1951   SourceFile pub_rust_shlib_rs("//pub_rust_shlib/lib.rs");
1952   pub_rust_shlib.sources().push_back(pub_rust_shlib_rs);
1953   pub_rust_shlib.source_types_used().Set(SourceFile::SOURCE_RS);
1954   pub_rust_shlib.rust_values().set_crate_type(RustValues::CRATE_CDYLIB);
1955   pub_rust_shlib.rust_values().set_crate_root(pub_rust_shlib_rs);
1956   pub_rust_shlib.rust_values().crate_name() = "pub_rust_shlib";
1957   pub_rust_shlib.SetToolchain(setup.toolchain());
1958   ASSERT_TRUE(pub_rust_shlib.OnResolved(&err));
1959 
1960   // An rlib that depends on both shared libraries.
1961   Target rlib(setup.settings(), Label(SourceDir("//rlib/"), "rlib"));
1962   rlib.set_output_type(Target::RUST_LIBRARY);
1963   rlib.visibility().SetPublic();
1964   SourceFile rlib_rs("//rlib/lib.rs");
1965   rlib.sources().push_back(rlib_rs);
1966   rlib.source_types_used().Set(SourceFile::SOURCE_RS);
1967   rlib.rust_values().set_crate_root(rlib_rs);
1968   rlib.rust_values().crate_name() = "rlib";
1969   rlib.private_deps().push_back(LabelTargetPair(&rust_shlib));
1970   rlib.private_deps().push_back(LabelTargetPair(&cc_shlib));
1971   rlib.public_deps().push_back(LabelTargetPair(&pub_rust_shlib));
1972   rlib.SetToolchain(setup.toolchain());
1973   ASSERT_TRUE(rlib.OnResolved(&err));
1974 
1975   Target target(setup.settings(), Label(SourceDir("//exe/"), "binary"));
1976   target.set_output_type(Target::EXECUTABLE);
1977   target.visibility().SetPublic();
1978   target.sources().push_back(SourceFile("//exe/main.cc"));
1979   target.source_types_used().Set(SourceFile::SOURCE_CPP);
1980   target.private_deps().push_back(LabelTargetPair(&rlib));
1981   target.SetToolchain(setup.toolchain());
1982   ASSERT_TRUE(target.OnResolved(&err));
1983 
1984   std::ostringstream out;
1985   NinjaCBinaryTargetWriter writer(&target, out);
1986   writer.Run();
1987 
1988   const char expected[] =
1989       "defines =\n"
1990       "include_dirs =\n"
1991       "cflags =\n"
1992       "cflags_cc =\n"
1993       "root_out_dir = .\n"
1994       "target_out_dir = obj/exe\n"
1995       "target_output_name = binary\n"
1996       "\n"
1997       "build obj/exe/binary.main.o: cxx ../../exe/main.cc\n"
1998       "  source_file_part = main.cc\n"
1999       "  source_name_part = main\n"
2000       "\n"
2001       "build ./binary: link obj/exe/binary.main.o "
2002       "obj/pub_rust_shlib/libpub_rust_shlib.so obj/rust_shlib/librust_shlib.so "
2003       "./libcc_shlib.so | "
2004       "obj/rlib/librlib.rlib\n"
2005       "  ldflags =\n"
2006       "  libs =\n"
2007       "  frameworks =\n"
2008       "  swiftmodules =\n"
2009       "  output_extension = \n"
2010       "  output_dir = \n"
2011       "  rlibs = obj/rlib/librlib.rlib\n";
2012 
2013   std::string out_str = out.str();
2014   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
2015 }
2016 
TEST_F(NinjaCBinaryTargetWriterTest,LinkingWithRustLibraryDepsOnDylib)2017 TEST_F(NinjaCBinaryTargetWriterTest, LinkingWithRustLibraryDepsOnDylib) {
2018   Err err;
2019   TestWithScope setup;
2020 
2021   // A non-rust shared library.
2022   Target cc_shlib(setup.settings(), Label(SourceDir("//cc_shlib"), "cc_shlib"));
2023   cc_shlib.set_output_type(Target::SHARED_LIBRARY);
2024   cc_shlib.set_output_name("cc_shlib");
2025   cc_shlib.SetToolchain(setup.toolchain());
2026   cc_shlib.visibility().SetPublic();
2027   ASSERT_TRUE(cc_shlib.OnResolved(&err));
2028 
2029   // A Rust DYLIB shared library that will be in deps.
2030   Target rust_shlib(setup.settings(),
2031                     Label(SourceDir("//rust_shlib/"), "rust_shlib"));
2032   rust_shlib.set_output_type(Target::SHARED_LIBRARY);
2033   rust_shlib.visibility().SetPublic();
2034   SourceFile rust_shlib_rs("//rust_shlib/lib.rs");
2035   rust_shlib.sources().push_back(rust_shlib_rs);
2036   rust_shlib.source_types_used().Set(SourceFile::SOURCE_RS);
2037   rust_shlib.rust_values().set_crate_type(RustValues::CRATE_DYLIB);
2038   rust_shlib.rust_values().set_crate_root(rust_shlib_rs);
2039   rust_shlib.rust_values().crate_name() = "rust_shlib";
2040   rust_shlib.SetToolchain(setup.toolchain());
2041   ASSERT_TRUE(rust_shlib.OnResolved(&err));
2042 
2043   // A Rust DYLIB shared library that will be in public_deps.
2044   Target pub_rust_shlib(setup.settings(), Label(SourceDir("//pub_rust_shlib/"),
2045                                                 "pub_rust_shlib"));
2046   pub_rust_shlib.set_output_type(Target::SHARED_LIBRARY);
2047   pub_rust_shlib.visibility().SetPublic();
2048   SourceFile pub_rust_shlib_rs("//pub_rust_shlib/lib.rs");
2049   pub_rust_shlib.sources().push_back(pub_rust_shlib_rs);
2050   pub_rust_shlib.source_types_used().Set(SourceFile::SOURCE_RS);
2051   pub_rust_shlib.rust_values().set_crate_type(RustValues::CRATE_DYLIB);
2052   pub_rust_shlib.rust_values().set_crate_root(pub_rust_shlib_rs);
2053   pub_rust_shlib.rust_values().crate_name() = "pub_rust_shlib";
2054   pub_rust_shlib.SetToolchain(setup.toolchain());
2055   ASSERT_TRUE(pub_rust_shlib.OnResolved(&err));
2056 
2057   // An rlib that depends on both shared libraries.
2058   Target rlib(setup.settings(), Label(SourceDir("//rlib/"), "rlib"));
2059   rlib.set_output_type(Target::RUST_LIBRARY);
2060   rlib.visibility().SetPublic();
2061   SourceFile rlib_rs("//rlib/lib.rs");
2062   rlib.sources().push_back(rlib_rs);
2063   rlib.source_types_used().Set(SourceFile::SOURCE_RS);
2064   rlib.rust_values().set_crate_root(rlib_rs);
2065   rlib.rust_values().crate_name() = "rlib";
2066   rlib.private_deps().push_back(LabelTargetPair(&rust_shlib));
2067   rlib.private_deps().push_back(LabelTargetPair(&cc_shlib));
2068   rlib.public_deps().push_back(LabelTargetPair(&pub_rust_shlib));
2069   rlib.SetToolchain(setup.toolchain());
2070   ASSERT_TRUE(rlib.OnResolved(&err));
2071 
2072   Target target(setup.settings(), Label(SourceDir("//exe/"), "binary"));
2073   target.set_output_type(Target::EXECUTABLE);
2074   target.visibility().SetPublic();
2075   target.sources().push_back(SourceFile("//exe/main.cc"));
2076   target.source_types_used().Set(SourceFile::SOURCE_CPP);
2077   target.private_deps().push_back(LabelTargetPair(&rlib));
2078   target.SetToolchain(setup.toolchain());
2079   ASSERT_TRUE(target.OnResolved(&err));
2080 
2081   std::ostringstream out;
2082   NinjaCBinaryTargetWriter writer(&target, out);
2083   writer.Run();
2084 
2085   const char expected[] =
2086       "defines =\n"
2087       "include_dirs =\n"
2088       "cflags =\n"
2089       "cflags_cc =\n"
2090       "root_out_dir = .\n"
2091       "target_out_dir = obj/exe\n"
2092       "target_output_name = binary\n"
2093       "\n"
2094       "build obj/exe/binary.main.o: cxx ../../exe/main.cc\n"
2095       "  source_file_part = main.cc\n"
2096       "  source_name_part = main\n"
2097       "\n"
2098       "build ./binary: link obj/exe/binary.main.o "
2099       "obj/pub_rust_shlib/libpub_rust_shlib.so obj/rust_shlib/librust_shlib.so "
2100       "./libcc_shlib.so | "
2101       "obj/rlib/librlib.rlib\n"
2102       "  ldflags =\n"
2103       "  libs =\n"
2104       "  frameworks =\n"
2105       "  swiftmodules =\n"
2106       "  output_extension = \n"
2107       "  output_dir = \n"
2108       "  rlibs = obj/rlib/librlib.rlib\n";
2109 
2110   std::string out_str = out.str();
2111   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
2112 }
2113 
2114 // Verify dependencies of a shared library and a rust library are inherited
2115 // independently.
TEST_F(NinjaCBinaryTargetWriterTest,RustLibAfterSharedLib)2116 TEST_F(NinjaCBinaryTargetWriterTest, RustLibAfterSharedLib) {
2117   Err err;
2118   TestWithScope setup;
2119 
2120   Target static1(setup.settings(),
2121                 Label(SourceDir("//static1/"), "staticlib1"));
2122   static1.set_output_type(Target::STATIC_LIBRARY);
2123   static1.visibility().SetPublic();
2124   static1.sources().push_back(SourceFile("//static1/c.cc"));
2125   static1.source_types_used().Set(SourceFile::SOURCE_CPP);
2126   static1.SetToolchain(setup.toolchain());
2127   ASSERT_TRUE(static1.OnResolved(&err));
2128 
2129   Target static2(setup.settings(),
2130                 Label(SourceDir("//static2/"), "staticlib2"));
2131   static2.set_output_type(Target::STATIC_LIBRARY);
2132   static2.visibility().SetPublic();
2133   static2.sources().push_back(SourceFile("//static2/c.cc"));
2134   static2.source_types_used().Set(SourceFile::SOURCE_CPP);
2135   static2.SetToolchain(setup.toolchain());
2136   ASSERT_TRUE(static2.OnResolved(&err));
2137 
2138   Target static3(setup.settings(),
2139                 Label(SourceDir("//static3/"), "staticlib3"));
2140   static3.set_output_type(Target::STATIC_LIBRARY);
2141   static3.visibility().SetPublic();
2142   static3.sources().push_back(SourceFile("//static3/c.cc"));
2143   static3.source_types_used().Set(SourceFile::SOURCE_CPP);
2144   static3.SetToolchain(setup.toolchain());
2145   ASSERT_TRUE(static3.OnResolved(&err));
2146 
2147   Target shared1(setup.settings(),
2148                     Label(SourceDir("//shared1"), "mysharedlib1"));
2149   shared1.set_output_type(Target::SHARED_LIBRARY);
2150   shared1.set_output_name("mysharedlib1");
2151   shared1.set_output_prefix_override("");
2152   shared1.SetToolchain(setup.toolchain());
2153   shared1.visibility().SetPublic();
2154   shared1.private_deps().push_back(LabelTargetPair(&static1));
2155   ASSERT_TRUE(shared1.OnResolved(&err));
2156 
2157   Target rlib2(setup.settings(), Label(SourceDir("//rlib2/"), "myrlib2"));
2158   rlib2.set_output_type(Target::RUST_LIBRARY);
2159   rlib2.visibility().SetPublic();
2160   SourceFile lib2("//rlib2/lib.rs");
2161   rlib2.sources().push_back(lib2);
2162   rlib2.source_types_used().Set(SourceFile::SOURCE_RS);
2163   rlib2.rust_values().set_crate_root(lib2);
2164   rlib2.rust_values().crate_name() = "foo";
2165   rlib2.private_deps().push_back(LabelTargetPair(&static2));
2166   rlib2.SetToolchain(setup.toolchain());
2167   ASSERT_TRUE(rlib2.OnResolved(&err));
2168 
2169   Target shared3(setup.settings(),
2170                     Label(SourceDir("//shared3"), "mysharedlib3"));
2171   shared3.set_output_type(Target::SHARED_LIBRARY);
2172   shared3.set_output_name("mysharedlib3");
2173   shared3.set_output_prefix_override("");
2174   shared3.SetToolchain(setup.toolchain());
2175   shared3.visibility().SetPublic();
2176   shared3.private_deps().push_back(LabelTargetPair(&static3));
2177   ASSERT_TRUE(shared3.OnResolved(&err));
2178 
2179   Target target(setup.settings(), Label(SourceDir("//exe/"), "binary"));
2180   target.set_output_type(Target::EXECUTABLE);
2181   target.visibility().SetPublic();
2182   target.sources().push_back(SourceFile("//exe/main.cc"));
2183   target.source_types_used().Set(SourceFile::SOURCE_CPP);
2184   target.private_deps().push_back(LabelTargetPair(&shared1));
2185   target.private_deps().push_back(LabelTargetPair(&rlib2));
2186   target.private_deps().push_back(LabelTargetPair(&shared3));
2187   target.SetToolchain(setup.toolchain());
2188   ASSERT_TRUE(target.OnResolved(&err));
2189 
2190   std::ostringstream out;
2191   NinjaCBinaryTargetWriter writer(&target, out);
2192   writer.Run();
2193 
2194   const char expected[] =
2195       "defines =\n"
2196       "include_dirs =\n"
2197       "cflags =\n"
2198       "cflags_cc =\n"
2199       "root_out_dir = .\n"
2200       "target_out_dir = obj/exe\n"
2201       "target_output_name = binary\n"
2202       "\n"
2203       "build obj/exe/binary.main.o: cxx ../../exe/main.cc\n"
2204       "  source_file_part = main.cc\n"
2205       "  source_name_part = main\n"
2206       "\n"
2207       "build ./binary: link obj/exe/binary.main.o "
2208       "./mysharedlib1.so ./mysharedlib3.so "
2209       "obj/static2/libstaticlib2.a | obj/rlib2/libmyrlib2.rlib\n"
2210       "  ldflags =\n"
2211       "  libs =\n"
2212       "  frameworks =\n"
2213       "  swiftmodules =\n"
2214       "  output_extension = \n"
2215       "  output_dir = \n"
2216       "  rlibs = obj/rlib2/libmyrlib2.rlib\n";
2217 
2218   std::string out_str = out.str();
2219   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
2220 }
2221 
TEST_F(NinjaCBinaryTargetWriterTest,ModuleMapInStaticLibrary)2222 TEST_F(NinjaCBinaryTargetWriterTest, ModuleMapInStaticLibrary) {
2223   TestWithScope setup;
2224   Err err;
2225 
2226   std::unique_ptr<Tool> cxx_module_tool =
2227       Tool::CreateTool(CTool::kCToolCxxModule);
2228   cxx_module_tool->set_outputs(SubstitutionList::MakeForTest(
2229       "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.pcm"));
2230   setup.toolchain()->SetTool(std::move(cxx_module_tool));
2231 
2232   TestTarget target(setup, "//foo:bar", Target::STATIC_LIBRARY);
2233   target.sources().push_back(SourceFile("//foo/bar.cc"));
2234   target.sources().push_back(SourceFile("//foo/bar.modulemap"));
2235   target.source_types_used().Set(SourceFile::SOURCE_CPP);
2236   target.source_types_used().Set(SourceFile::SOURCE_MODULEMAP);
2237   ASSERT_TRUE(target.OnResolved(&err));
2238 
2239   std::ostringstream out;
2240   NinjaCBinaryTargetWriter writer(&target, out);
2241   writer.Run();
2242 
2243   const char expected[] =
2244       "defines =\n"
2245       "include_dirs =\n"
2246       "cflags =\n"
2247       "cflags_cc =\n"
2248       "root_out_dir = .\n"
2249       "target_out_dir = obj/foo\n"
2250       "target_output_name = libbar\n"
2251       "\n"
2252       "build obj/foo/libbar.bar.o: cxx ../../foo/bar.cc | obj/foo/libbar.bar.pcm\n"
2253       "  source_file_part = bar.cc\n"
2254       "  source_name_part = bar\n"
2255       "build obj/foo/libbar.bar.pcm: cxx_module ../../foo/bar.modulemap\n"
2256       "  source_file_part = bar.modulemap\n"
2257       "  source_name_part = bar\n"
2258       "\n"
2259       "build obj/foo/libbar.a: alink obj/foo/libbar.bar.o\n"
2260       "  arflags =\n"
2261       "  output_extension = \n"
2262       "  output_dir = \n";
2263   std::string out_str = out.str();
2264   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
2265 }
2266 
2267 // Test linking of targets containing Swift modules.
TEST_F(NinjaCBinaryTargetWriterTest,SwiftModule)2268 TEST_F(NinjaCBinaryTargetWriterTest, SwiftModule) {
2269   Err err;
2270   TestWithScope setup;
2271 
2272   // A single Swift module.
2273   Target foo_target(setup.settings(), Label(SourceDir("//foo/"), "foo"));
2274   foo_target.set_output_type(Target::SOURCE_SET);
2275   foo_target.visibility().SetPublic();
2276   foo_target.sources().push_back(SourceFile("//foo/file1.swift"));
2277   foo_target.sources().push_back(SourceFile("//foo/file2.swift"));
2278   foo_target.source_types_used().Set(SourceFile::SOURCE_SWIFT);
2279   foo_target.swift_values().module_name() = "Foo";
2280   foo_target.SetToolchain(setup.toolchain());
2281   ASSERT_TRUE(foo_target.OnResolved(&err));
2282 
2283   {
2284     std::ostringstream out;
2285     NinjaCBinaryTargetWriter writer(&foo_target, out);
2286     writer.Run();
2287 
2288     const char expected[] =
2289         "defines =\n"
2290         "include_dirs =\n"
2291         "module_name = Foo\n"
2292         "module_dirs =\n"
2293         "root_out_dir = .\n"
2294         "target_out_dir = obj/foo\n"
2295         "target_output_name = foo\n"
2296         "\n"
2297         "build obj/foo/Foo.swiftmodule: swift"
2298         " ../../foo/file1.swift ../../foo/file2.swift\n"
2299         "\n"
2300         "build obj/foo/file1.o obj/foo/file2.o: stamp obj/foo/Foo.swiftmodule\n"
2301         "\n"
2302         "build obj/foo/foo.stamp: stamp"
2303         " obj/foo/file1.o obj/foo/file2.o\n";
2304 
2305     const std::string out_str = out.str();
2306     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
2307   }
2308 
2309   // Swift module_dirs correctly set if dependency between Swift modules.
2310   {
2311     Target bar_target(setup.settings(), Label(SourceDir("//bar/"), "bar"));
2312     bar_target.set_output_type(Target::SOURCE_SET);
2313     bar_target.visibility().SetPublic();
2314     bar_target.sources().push_back(SourceFile("//bar/bar.swift"));
2315     bar_target.source_types_used().Set(SourceFile::SOURCE_SWIFT);
2316     bar_target.swift_values().module_name() = "Bar";
2317     bar_target.private_deps().push_back(LabelTargetPair(&foo_target));
2318     bar_target.SetToolchain(setup.toolchain());
2319     ASSERT_TRUE(bar_target.OnResolved(&err));
2320 
2321     std::ostringstream out;
2322     NinjaCBinaryTargetWriter writer(&bar_target, out);
2323     writer.Run();
2324 
2325     const char expected[] =
2326         "defines =\n"
2327         "include_dirs =\n"
2328         "module_name = Bar\n"
2329         "module_dirs = -Iobj/foo\n"
2330         "root_out_dir = .\n"
2331         "target_out_dir = obj/bar\n"
2332         "target_output_name = bar\n"
2333         "\n"
2334         "build obj/bar/Bar.swiftmodule: swift ../../bar/bar.swift"
2335         " || obj/foo/foo.stamp\n"
2336         "\n"
2337         "build obj/bar/bar.o: stamp obj/bar/Bar.swiftmodule"
2338         " || obj/foo/foo.stamp\n"
2339         "\n"
2340         "build obj/bar/bar.stamp: stamp obj/bar/bar.o "
2341         "|| obj/foo/foo.stamp\n";
2342 
2343     const std::string out_str = out.str();
2344     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
2345   }
2346 
2347   // Swift module_dirs correctly set if dependency between Swift modules,
2348   // even if the dependency is indirect (via public_deps).
2349   {
2350     Target group(setup.settings(), Label(SourceDir("//bar/"), "group"));
2351     group.set_output_type(Target::GROUP);
2352     group.visibility().SetPublic();
2353     group.public_deps().push_back(LabelTargetPair(&foo_target));
2354     group.SetToolchain(setup.toolchain());
2355     ASSERT_TRUE(group.OnResolved(&err));
2356 
2357     Target bar_target(setup.settings(), Label(SourceDir("//bar/"), "bar"));
2358     bar_target.set_output_type(Target::SOURCE_SET);
2359     bar_target.visibility().SetPublic();
2360     bar_target.sources().push_back(SourceFile("//bar/bar.swift"));
2361     bar_target.source_types_used().Set(SourceFile::SOURCE_SWIFT);
2362     bar_target.swift_values().module_name() = "Bar";
2363     bar_target.private_deps().push_back(LabelTargetPair(&group));
2364     bar_target.SetToolchain(setup.toolchain());
2365     ASSERT_TRUE(bar_target.OnResolved(&err));
2366 
2367     std::ostringstream out;
2368     NinjaCBinaryTargetWriter writer(&bar_target, out);
2369     writer.Run();
2370 
2371     const char expected[] =
2372         "defines =\n"
2373         "include_dirs =\n"
2374         "module_name = Bar\n"
2375         "module_dirs = -Iobj/foo\n"
2376         "root_out_dir = .\n"
2377         "target_out_dir = obj/bar\n"
2378         "target_output_name = bar\n"
2379         "\n"
2380         "build obj/bar/Bar.swiftmodule: swift ../../bar/bar.swift"
2381         " || obj/bar/group.stamp obj/foo/foo.stamp\n"
2382         "\n"
2383         "build obj/bar/bar.o: stamp obj/bar/Bar.swiftmodule"
2384         " || obj/bar/group.stamp obj/foo/foo.stamp\n"
2385         "\n"
2386         "build obj/bar/bar.stamp: stamp obj/bar/bar.o "
2387         "|| obj/bar/group.stamp obj/foo/foo.stamp\n";
2388 
2389     const std::string out_str = out.str();
2390     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
2391   }
2392 
2393   // C target links with module.
2394   {
2395     Target bar_target(setup.settings(), Label(SourceDir("//bar/"), "bar"));
2396     bar_target.set_output_type(Target::EXECUTABLE);
2397     bar_target.visibility().SetPublic();
2398     bar_target.private_deps().push_back(LabelTargetPair(&foo_target));
2399     bar_target.SetToolchain(setup.toolchain());
2400     ASSERT_TRUE(bar_target.OnResolved(&err));
2401 
2402     std::ostringstream out;
2403     NinjaCBinaryTargetWriter writer(&bar_target, out);
2404     writer.Run();
2405 
2406     const char expected[] =
2407         "defines =\n"
2408         "include_dirs =\n"
2409         "root_out_dir = .\n"
2410         "target_out_dir = obj/bar\n"
2411         "target_output_name = bar\n"
2412         "\n"
2413         "\n"
2414         "build ./bar: link obj/foo/file1.o obj/foo/file2.o "
2415         "| obj/foo/Foo.swiftmodule "
2416         "|| obj/foo/foo.stamp\n"
2417         "  ldflags =\n"
2418         "  libs =\n"
2419         "  frameworks =\n"
2420         "  swiftmodules = obj/foo/Foo.swiftmodule\n"
2421         "  output_extension = \n"
2422         "  output_dir = \n";
2423 
2424     const std::string out_str = out.str();
2425     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
2426   }
2427 }
2428 
TEST_F(NinjaCBinaryTargetWriterTest,DependOnModule)2429 TEST_F(NinjaCBinaryTargetWriterTest, DependOnModule) {
2430   TestWithScope setup;
2431   Err err;
2432 
2433   // There's no cxx_module or flags in the test toolchain, set up a
2434   // custom one here.
2435   Settings module_settings(setup.build_settings(), "withmodules/");
2436   Toolchain module_toolchain(&module_settings,
2437                              Label(SourceDir("//toolchain/"), "withmodules"));
2438   module_settings.set_toolchain_label(module_toolchain.label());
2439   module_settings.set_default_toolchain_label(module_toolchain.label());
2440 
2441   std::unique_ptr<Tool> cxx = std::make_unique<CTool>(CTool::kCToolCxx);
2442   CTool* cxx_tool = cxx->AsC();
2443   TestWithScope::SetCommandForTool(
2444       "c++ {{source}} {{cflags}} {{cflags_cc}} {{module_deps}} "
2445       "{{defines}} {{include_dirs}} -o {{output}}",
2446       cxx_tool);
2447   cxx_tool->set_outputs(SubstitutionList::MakeForTest(
2448       "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
2449   cxx_tool->set_precompiled_header_type(CTool::PCH_GCC);
2450   module_toolchain.SetTool(std::move(cxx));
2451 
2452   std::unique_ptr<Tool> cxx_module_tool =
2453       Tool::CreateTool(CTool::kCToolCxxModule);
2454   TestWithScope::SetCommandForTool(
2455       "c++ {{source}} {{cflags}} {{cflags_cc}} {{module_deps_no_self}} "
2456       "{{defines}} {{include_dirs}} -fmodule-name={{label}} -c -x c++ "
2457       "-Xclang -emit-module -o {{output}}",
2458       cxx_module_tool.get());
2459   cxx_module_tool->set_outputs(SubstitutionList::MakeForTest(
2460       "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.pcm"));
2461   module_toolchain.SetTool(std::move(cxx_module_tool));
2462 
2463   std::unique_ptr<Tool> alink = Tool::CreateTool(CTool::kCToolAlink);
2464   CTool* alink_tool = alink->AsC();
2465   TestWithScope::SetCommandForTool("ar {{output}} {{source}}", alink_tool);
2466   alink_tool->set_lib_switch("-l");
2467   alink_tool->set_lib_dir_switch("-L");
2468   alink_tool->set_output_prefix("lib");
2469   alink_tool->set_outputs(SubstitutionList::MakeForTest(
2470       "{{target_out_dir}}/{{target_output_name}}.a"));
2471   module_toolchain.SetTool(std::move(alink));
2472 
2473   std::unique_ptr<Tool> link = Tool::CreateTool(CTool::kCToolLink);
2474   CTool* link_tool = link->AsC();
2475   TestWithScope::SetCommandForTool(
2476       "ld -o {{target_output_name}} {{source}} "
2477       "{{ldflags}} {{libs}}",
2478       link_tool);
2479   link_tool->set_lib_switch("-l");
2480   link_tool->set_lib_dir_switch("-L");
2481   link_tool->set_outputs(
2482       SubstitutionList::MakeForTest("{{root_out_dir}}/{{target_output_name}}"));
2483   module_toolchain.SetTool(std::move(link));
2484 
2485   module_toolchain.ToolchainSetupComplete();
2486 
2487   Target target(&module_settings, Label(SourceDir("//blah/"), "a"));
2488   target.set_output_type(Target::STATIC_LIBRARY);
2489   target.visibility().SetPublic();
2490   target.sources().push_back(SourceFile("//blah/a.modulemap"));
2491   target.sources().push_back(SourceFile("//blah/a.cc"));
2492   target.sources().push_back(SourceFile("//blah/a.h"));
2493   target.source_types_used().Set(SourceFile::SOURCE_CPP);
2494   target.source_types_used().Set(SourceFile::SOURCE_MODULEMAP);
2495   target.SetToolchain(&module_toolchain);
2496   ASSERT_TRUE(target.OnResolved(&err));
2497 
2498   // The library first.
2499   {
2500     std::ostringstream out;
2501     NinjaCBinaryTargetWriter writer(&target, out);
2502     writer.Run();
2503 
2504     const char expected[] = R"(defines =
2505 include_dirs =
2506 cflags =
2507 cflags_cc =
2508 module_deps = -Xclang -fmodules-embed-all-files -fmodule-file=obj/blah/liba.a.pcm
2509 module_deps_no_self = -Xclang -fmodules-embed-all-files
2510 label = //blah$:a
2511 root_out_dir = withmodules
2512 target_out_dir = obj/blah
2513 target_output_name = liba
2514 
2515 build obj/blah/liba.a.pcm: cxx_module ../../blah/a.modulemap
2516   source_file_part = a.modulemap
2517   source_name_part = a
2518 build obj/blah/liba.a.o: cxx ../../blah/a.cc | obj/blah/liba.a.pcm
2519   source_file_part = a.cc
2520   source_name_part = a
2521 
2522 build obj/blah/liba.a: alink obj/blah/liba.a.o
2523   arflags =
2524   output_extension =
2525   output_dir =
2526 )";
2527 
2528     std::string out_str = out.str();
2529     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
2530   }
2531 
2532   Target target2(&module_settings, Label(SourceDir("//stuff/"), "b"));
2533   target2.set_output_type(Target::STATIC_LIBRARY);
2534   target2.visibility().SetPublic();
2535   target2.sources().push_back(SourceFile("//stuff/b.modulemap"));
2536   target2.sources().push_back(SourceFile("//stuff/b.cc"));
2537   target2.sources().push_back(SourceFile("//stuff/b.h"));
2538   target2.source_types_used().Set(SourceFile::SOURCE_CPP);
2539   target2.source_types_used().Set(SourceFile::SOURCE_MODULEMAP);
2540   target2.SetToolchain(&module_toolchain);
2541   ASSERT_TRUE(target2.OnResolved(&err));
2542 
2543   // A second library to make sure the depender includes both.
2544   {
2545     std::ostringstream out;
2546     NinjaCBinaryTargetWriter writer(&target2, out);
2547     writer.Run();
2548 
2549     const char expected[] = R"(defines =
2550 include_dirs =
2551 cflags =
2552 cflags_cc =
2553 module_deps = -Xclang -fmodules-embed-all-files -fmodule-file=obj/stuff/libb.b.pcm
2554 module_deps_no_self = -Xclang -fmodules-embed-all-files
2555 label = //stuff$:b
2556 root_out_dir = withmodules
2557 target_out_dir = obj/stuff
2558 target_output_name = libb
2559 
2560 build obj/stuff/libb.b.pcm: cxx_module ../../stuff/b.modulemap
2561   source_file_part = b.modulemap
2562   source_name_part = b
2563 build obj/stuff/libb.b.o: cxx ../../stuff/b.cc | obj/stuff/libb.b.pcm
2564   source_file_part = b.cc
2565   source_name_part = b
2566 
2567 build obj/stuff/libb.a: alink obj/stuff/libb.b.o
2568   arflags =
2569   output_extension =
2570   output_dir =
2571 )";
2572 
2573     std::string out_str = out.str();
2574     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
2575   }
2576 
2577   Target target3(&module_settings, Label(SourceDir("//things/"), "c"));
2578   target3.set_output_type(Target::STATIC_LIBRARY);
2579   target3.visibility().SetPublic();
2580   target3.sources().push_back(SourceFile("//stuff/c.modulemap"));
2581   target3.source_types_used().Set(SourceFile::SOURCE_MODULEMAP);
2582   target3.private_deps().push_back(LabelTargetPair(&target));
2583   target3.SetToolchain(&module_toolchain);
2584   ASSERT_TRUE(target3.OnResolved(&err));
2585 
2586   // A third library that depends on one of the previous static libraries, to
2587   // check module_deps_no_self.
2588   {
2589     std::ostringstream out;
2590     NinjaCBinaryTargetWriter writer(&target3, out);
2591     writer.Run();
2592 
2593     const char expected[] = R"(defines =
2594 include_dirs =
2595 cflags =
2596 cflags_cc =
2597 module_deps = -Xclang -fmodules-embed-all-files -fmodule-file=obj/stuff/libc.c.pcm -fmodule-file=obj/blah/liba.a.pcm
2598 module_deps_no_self = -Xclang -fmodules-embed-all-files -fmodule-file=obj/blah/liba.a.pcm
2599 label = //things$:c
2600 root_out_dir = withmodules
2601 target_out_dir = obj/things
2602 target_output_name = libc
2603 
2604 build obj/stuff/libc.c.pcm: cxx_module ../../stuff/c.modulemap | obj/blah/liba.a.pcm
2605   source_file_part = c.modulemap
2606   source_name_part = c
2607 
2608 build obj/things/libc.a: alink || obj/blah/liba.a
2609   arflags =
2610   output_extension =
2611   output_dir =
2612 )";
2613 
2614     std::string out_str = out.str();
2615     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
2616   }
2617 
2618   Target depender(&module_settings, Label(SourceDir("//zap/"), "c"));
2619   depender.set_output_type(Target::EXECUTABLE);
2620   depender.sources().push_back(SourceFile("//zap/x.cc"));
2621   depender.sources().push_back(SourceFile("//zap/y.cc"));
2622   depender.source_types_used().Set(SourceFile::SOURCE_CPP);
2623   depender.private_deps().push_back(LabelTargetPair(&target));
2624   depender.private_deps().push_back(LabelTargetPair(&target2));
2625   depender.SetToolchain(&module_toolchain);
2626   ASSERT_TRUE(depender.OnResolved(&err));
2627 
2628   // Then the executable that depends on it.
2629   {
2630     std::ostringstream out;
2631     NinjaCBinaryTargetWriter writer(&depender, out);
2632     writer.Run();
2633 
2634     const char expected[] = R"(defines =
2635 include_dirs =
2636 cflags =
2637 cflags_cc =
2638 module_deps = -Xclang -fmodules-embed-all-files -fmodule-file=obj/blah/liba.a.pcm -fmodule-file=obj/stuff/libb.b.pcm
2639 module_deps_no_self = -Xclang -fmodules-embed-all-files -fmodule-file=obj/blah/liba.a.pcm -fmodule-file=obj/stuff/libb.b.pcm
2640 label = //zap$:c
2641 root_out_dir = withmodules
2642 target_out_dir = obj/zap
2643 target_output_name = c
2644 
2645 build obj/zap/c.x.o: cxx ../../zap/x.cc | obj/blah/liba.a.pcm obj/stuff/libb.b.pcm
2646   source_file_part = x.cc
2647   source_name_part = x
2648 build obj/zap/c.y.o: cxx ../../zap/y.cc | obj/blah/liba.a.pcm obj/stuff/libb.b.pcm
2649   source_file_part = y.cc
2650   source_name_part = y
2651 
2652 build withmodules/c: link obj/zap/c.x.o obj/zap/c.y.o obj/blah/liba.a obj/stuff/libb.a
2653   ldflags =
2654   libs =
2655   frameworks =
2656   swiftmodules =
2657   output_extension =
2658   output_dir =
2659 )";
2660 
2661     std::string out_str = out.str();
2662     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
2663   }
2664 }
2665 
TEST_F(NinjaCBinaryTargetWriterTest,SolibsEscaping)2666 TEST_F(NinjaCBinaryTargetWriterTest, SolibsEscaping) {
2667   Err err;
2668   TestWithScope setup;
2669 
2670   Toolchain toolchain_with_toc(
2671       setup.settings(), Label(SourceDir("//toolchain_with_toc/"), "with_toc"));
2672   TestWithScope::SetupToolchain(&toolchain_with_toc, true);
2673 
2674   // Create a shared library with a space in the output name.
2675   Target shared_lib(setup.settings(),
2676                     Label(SourceDir("//rocket"), "space_cadet"));
2677   shared_lib.set_output_type(Target::SHARED_LIBRARY);
2678   shared_lib.set_output_name("Space Cadet");
2679   shared_lib.set_output_prefix_override("");
2680   shared_lib.SetToolchain(&toolchain_with_toc);
2681   shared_lib.visibility().SetPublic();
2682   ASSERT_TRUE(shared_lib.OnResolved(&err));
2683 
2684   // Set up an executable to depend on it.
2685   Target target(setup.settings(), Label(SourceDir("//launchpad"), "main"));
2686   target.sources().push_back(SourceFile("//launchpad/main.cc"));
2687   target.set_output_type(Target::EXECUTABLE);
2688   target.private_deps().push_back(LabelTargetPair(&shared_lib));
2689   target.SetToolchain(&toolchain_with_toc);
2690   ASSERT_TRUE(target.OnResolved(&err));
2691 
2692   std::ostringstream out;
2693   NinjaCBinaryTargetWriter writer(&target, out);
2694   writer.Run();
2695 
2696   const char expected[] = R"(defines =
2697 include_dirs =
2698 root_out_dir = .
2699 target_out_dir = obj/launchpad
2700 target_output_name = main
2701 
2702 build obj/launchpad/main.main.o: cxx ../../launchpad/main.cc
2703   source_file_part = main.cc
2704   source_name_part = main
2705 
2706 build ./main: link obj/launchpad/main.main.o | ./Space$ Cadet.so.TOC
2707   ldflags =
2708   libs =
2709   frameworks =
2710   swiftmodules =
2711   output_extension =
2712   output_dir =
2713 )"
2714 #if defined(OS_WIN)
2715   "  solibs = \"./Space$ Cadet.so\"\n";
2716 #else
2717   "  solibs = ./Space\\$ Cadet.so\n";
2718 #endif
2719 
2720   std::string out_str = out.str();
2721   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
2722 }
2723