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