• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "gn/ninja_rust_binary_target_writer.h"
6 
7 #include "gn/config.h"
8 #include "gn/pool.h"
9 #include "gn/rust_values.h"
10 #include "gn/scheduler.h"
11 #include "gn/target.h"
12 #include "gn/test_with_scheduler.h"
13 #include "gn/test_with_scope.h"
14 #include "util/build_config.h"
15 #include "util/test/test.h"
16 
17 using NinjaRustBinaryTargetWriterTest = TestWithScheduler;
18 
TEST_F(NinjaRustBinaryTargetWriterTest,RustSourceSet)19 TEST_F(NinjaRustBinaryTargetWriterTest, RustSourceSet) {
20   Err err;
21   TestWithScope setup;
22 
23   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
24   target.set_output_type(Target::SOURCE_SET);
25   target.visibility().SetPublic();
26   target.sources().push_back(SourceFile("//foo/input1.rs"));
27   target.sources().push_back(SourceFile("//foo/main.rs"));
28   target.source_types_used().Set(SourceFile::SOURCE_RS);
29   target.SetToolchain(setup.toolchain());
30   ASSERT_FALSE(target.OnResolved(&err));
31 }
32 
TEST_F(NinjaRustBinaryTargetWriterTest,RustExecutable)33 TEST_F(NinjaRustBinaryTargetWriterTest, RustExecutable) {
34   Err err;
35   TestWithScope setup;
36 
37   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
38   target.set_output_type(Target::EXECUTABLE);
39   target.visibility().SetPublic();
40   SourceFile main("//foo/main.rs");
41   target.sources().push_back(SourceFile("//foo/input3.rs"));
42   target.sources().push_back(main);
43   target.source_types_used().Set(SourceFile::SOURCE_RS);
44   target.rust_values().set_crate_root(main);
45   target.rust_values().crate_name() = "foo_bar";
46   target.config_values().ldflags().push_back("-fsanitize=address");
47   target.SetToolchain(setup.toolchain());
48   ASSERT_TRUE(target.OnResolved(&err));
49 
50   {
51     std::ostringstream out;
52     NinjaRustBinaryTargetWriter writer(&target, out);
53     writer.Run();
54 
55     const char expected[] =
56         "crate_name = foo_bar\n"
57         "crate_type = bin\n"
58         "output_extension = \n"
59         "output_dir = \n"
60         "rustflags =\n"
61         "rustenv =\n"
62         "root_out_dir = .\n"
63         "target_gen_dir = gen/foo\n"
64         "target_out_dir = obj/foo\n"
65         "target_output_name = bar\n"
66         "\n"
67         "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/input3.rs "
68         "../../foo/main.rs\n"
69         "  source_file_part = main.rs\n"
70         "  source_name_part = main\n"
71         "  externs =\n"
72         "  rustdeps =\n"
73         "  ldflags = -fsanitize=address\n"
74         "  sources = ../../foo/input3.rs ../../foo/main.rs\n";
75     std::string out_str = out.str();
76     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
77   }
78 }
79 
80 // Accessible dependencies appear as --extern switches for rustc, so that the
81 // target crate can make use of them whether transitive or not. Transitive
82 // dependencies can be accessible if they are in the public_deps of a direct
83 // dependency, or part of a chain of public_deps from a direct dependency. Any
84 // dependencies used by other crate dependencies also must appear, but are
85 // pointed to by -Ldependency as they are not available for use from the target
86 // crate. In the future they may move to `--extern priv:` when explicit private
87 // dependencies are stabilized.
TEST_F(NinjaRustBinaryTargetWriterTest,RlibDeps)88 TEST_F(NinjaRustBinaryTargetWriterTest, RlibDeps) {
89   Err err;
90   TestWithScope setup;
91 
92   Target private_rlib(setup.settings(),
93                       Label(SourceDir("//baz/"), "privatelib"));
94   private_rlib.set_output_type(Target::RUST_LIBRARY);
95   private_rlib.visibility().SetPublic();
96   SourceFile bazlib("//baz/lib.rs");
97   private_rlib.sources().push_back(SourceFile("//baz/privatelib.rs"));
98   private_rlib.sources().push_back(bazlib);
99   private_rlib.source_types_used().Set(SourceFile::SOURCE_RS);
100   private_rlib.rust_values().set_crate_root(bazlib);
101   private_rlib.rust_values().crate_name() = "privatecrate";
102   private_rlib.SetToolchain(setup.toolchain());
103   ASSERT_TRUE(private_rlib.OnResolved(&err));
104 
105   {
106     std::ostringstream out;
107     NinjaRustBinaryTargetWriter writer(&private_rlib, out);
108     writer.Run();
109 
110     const char expected[] =
111         "crate_name = privatecrate\n"
112         "crate_type = rlib\n"
113         "output_extension = .rlib\n"
114         "output_dir = \n"
115         "rustflags =\n"
116         "rustenv =\n"
117         "root_out_dir = .\n"
118         "target_gen_dir = gen/baz\n"
119         "target_out_dir = obj/baz\n"
120         "target_output_name = libprivatelib\n"
121         "\n"
122         "build obj/baz/libprivatelib.rlib: rust_rlib ../../baz/lib.rs | "
123         "../../baz/privatelib.rs ../../baz/lib.rs\n"
124         "  source_file_part = lib.rs\n"
125         "  source_name_part = lib\n"
126         "  externs =\n"
127         "  rustdeps =\n"
128         "  ldflags =\n"
129         "  sources = ../../baz/privatelib.rs ../../baz/lib.rs\n";
130     std::string out_str = out.str();
131     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
132   }
133 
134   Target far_public_rlib(setup.settings(),
135                          Label(SourceDir("//far/"), "farlib"));
136   far_public_rlib.set_output_type(Target::RUST_LIBRARY);
137   far_public_rlib.visibility().SetPublic();
138   SourceFile farlib("//far/lib.rs");
139   far_public_rlib.sources().push_back(SourceFile("//far/farlib.rs"));
140   far_public_rlib.sources().push_back(farlib);
141   far_public_rlib.source_types_used().Set(SourceFile::SOURCE_RS);
142   far_public_rlib.rust_values().set_crate_root(farlib);
143   far_public_rlib.rust_values().crate_name() = "farcrate";
144   far_public_rlib.SetToolchain(setup.toolchain());
145   ASSERT_TRUE(far_public_rlib.OnResolved(&err));
146 
147   {
148     std::ostringstream out;
149     NinjaRustBinaryTargetWriter writer(&far_public_rlib, out);
150     writer.Run();
151 
152     const char expected[] =
153         "crate_name = farcrate\n"
154         "crate_type = rlib\n"
155         "output_extension = .rlib\n"
156         "output_dir = \n"
157         "rustflags =\n"
158         "rustenv =\n"
159         "root_out_dir = .\n"
160         "target_gen_dir = gen/far\n"
161         "target_out_dir = obj/far\n"
162         "target_output_name = libfarlib\n"
163         "\n"
164         "build obj/far/libfarlib.rlib: rust_rlib ../../far/lib.rs | "
165         "../../far/farlib.rs ../../far/lib.rs\n"
166         "  source_file_part = lib.rs\n"
167         "  source_name_part = lib\n"
168         "  externs =\n"
169         "  rustdeps =\n"
170         "  ldflags =\n"
171         "  sources = ../../far/farlib.rs ../../far/lib.rs\n";
172     std::string out_str = out.str();
173     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
174   }
175 
176   Target public_rlib(setup.settings(), Label(SourceDir("//bar/"), "publiclib"));
177   public_rlib.set_output_type(Target::RUST_LIBRARY);
178   public_rlib.visibility().SetPublic();
179   SourceFile barlib("//bar/lib.rs");
180   public_rlib.sources().push_back(SourceFile("//bar/publiclib.rs"));
181   public_rlib.sources().push_back(barlib);
182   public_rlib.source_types_used().Set(SourceFile::SOURCE_RS);
183   public_rlib.rust_values().set_crate_root(barlib);
184   public_rlib.rust_values().crate_name() = "publiccrate";
185   public_rlib.public_deps().push_back(LabelTargetPair(&far_public_rlib));
186   public_rlib.SetToolchain(setup.toolchain());
187   ASSERT_TRUE(public_rlib.OnResolved(&err));
188 
189   {
190     std::ostringstream out;
191     NinjaRustBinaryTargetWriter writer(&public_rlib, out);
192     writer.Run();
193 
194     const char expected[] =
195         "crate_name = publiccrate\n"
196         "crate_type = rlib\n"
197         "output_extension = .rlib\n"
198         "output_dir = \n"
199         "rustflags =\n"
200         "rustenv =\n"
201         "root_out_dir = .\n"
202         "target_gen_dir = gen/bar\n"
203         "target_out_dir = obj/bar\n"
204         "target_output_name = libpubliclib\n"
205         "\n"
206         "build obj/bar/libpubliclib.rlib: rust_rlib ../../bar/lib.rs | "
207         "../../bar/publiclib.rs ../../bar/lib.rs obj/far/libfarlib.rlib\n"
208         "  source_file_part = lib.rs\n"
209         "  source_name_part = lib\n"
210         "  externs = --extern farcrate=obj/far/libfarlib.rlib\n"
211         "  rustdeps = -Ldependency=obj/far\n"
212         "  ldflags =\n"
213         "  sources = ../../bar/publiclib.rs ../../bar/lib.rs\n";
214     std::string out_str = out.str();
215     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
216   }
217 
218   Target rlib(setup.settings(), Label(SourceDir("//foo/"), "direct"));
219   rlib.set_output_type(Target::RUST_LIBRARY);
220   rlib.visibility().SetPublic();
221   SourceFile lib("//foo/main.rs");
222   rlib.sources().push_back(SourceFile("//foo/direct.rs"));
223   rlib.sources().push_back(lib);
224   rlib.source_types_used().Set(SourceFile::SOURCE_RS);
225   rlib.rust_values().set_crate_root(lib);
226   rlib.rust_values().crate_name() = "direct";
227   rlib.SetToolchain(setup.toolchain());
228   rlib.public_deps().push_back(LabelTargetPair(&public_rlib));
229   rlib.private_deps().push_back(LabelTargetPair(&private_rlib));
230   ASSERT_TRUE(rlib.OnResolved(&err));
231 
232   Target target(setup.settings(), Label(SourceDir("//main/"), "main"));
233   target.set_output_type(Target::EXECUTABLE);
234   target.visibility().SetPublic();
235   SourceFile main("//main/main.rs");
236   target.sources().push_back(SourceFile("//main/source.rs"));
237   target.sources().push_back(main);
238   target.source_types_used().Set(SourceFile::SOURCE_RS);
239   target.rust_values().set_crate_root(main);
240   target.rust_values().crate_name() = "main_crate";
241   target.private_deps().push_back(LabelTargetPair(&rlib));
242   target.SetToolchain(setup.toolchain());
243   ASSERT_TRUE(target.OnResolved(&err));
244 
245   {
246     std::ostringstream out;
247     NinjaRustBinaryTargetWriter writer(&target, out);
248     writer.Run();
249 
250     const char expected[] =
251         "crate_name = main_crate\n"
252         "crate_type = bin\n"
253         "output_extension = \n"
254         "output_dir = \n"
255         "rustflags =\n"
256         "rustenv =\n"
257         "root_out_dir = .\n"
258         "target_gen_dir = gen/main\n"
259         "target_out_dir = obj/main\n"
260         "target_output_name = main\n"
261         "\n"
262         "build ./main_crate: rust_bin ../../main/main.rs | "
263         "../../main/source.rs ../../main/main.rs obj/foo/libdirect.rlib "
264         "obj/bar/libpubliclib.rlib obj/far/libfarlib.rlib "
265         "obj/baz/libprivatelib.rlib\n"
266         "  source_file_part = main.rs\n"
267         "  source_name_part = main\n"
268         "  externs = --extern direct=obj/foo/libdirect.rlib "
269         "--extern publiccrate=obj/bar/libpubliclib.rlib "
270         "--extern farcrate=obj/far/libfarlib.rlib\n"
271         "  rustdeps = -Ldependency=obj/foo -Ldependency=obj/bar "
272         "-Ldependency=obj/far -Ldependency=obj/baz\n"
273         "  ldflags =\n"
274         "  sources = ../../main/source.rs ../../main/main.rs\n";
275     std::string out_str = out.str();
276     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
277   }
278 }
279 
TEST_F(NinjaRustBinaryTargetWriterTest,DylibDeps)280 TEST_F(NinjaRustBinaryTargetWriterTest, DylibDeps) {
281   Err err;
282   TestWithScope setup;
283 
284   Target private_inside_dylib(setup.settings(),
285                               Label(SourceDir("//faz/"), "private_inside"));
286   private_inside_dylib.set_output_type(Target::RUST_LIBRARY);
287   private_inside_dylib.visibility().SetPublic();
288   SourceFile fazlib("//faz/lib.rs");
289   private_inside_dylib.sources().push_back(
290       SourceFile("//faz/private_inside.rs"));
291   private_inside_dylib.sources().push_back(fazlib);
292   private_inside_dylib.source_types_used().Set(SourceFile::SOURCE_RS);
293   private_inside_dylib.rust_values().set_crate_root(fazlib);
294   private_inside_dylib.rust_values().crate_name() = "private_inside";
295   private_inside_dylib.SetToolchain(setup.toolchain());
296   ASSERT_TRUE(private_inside_dylib.OnResolved(&err));
297 
298   {
299     std::ostringstream out;
300     NinjaRustBinaryTargetWriter writer(&private_inside_dylib, out);
301     writer.Run();
302 
303     const char expected[] =
304         "crate_name = private_inside\n"
305         "crate_type = rlib\n"
306         "output_extension = .rlib\n"
307         "output_dir = \n"
308         "rustflags =\n"
309         "rustenv =\n"
310         "root_out_dir = .\n"
311         "target_gen_dir = gen/faz\n"
312         "target_out_dir = obj/faz\n"
313         "target_output_name = libprivate_inside\n"
314         "\n"
315         "build obj/faz/libprivate_inside.rlib: rust_rlib ../../faz/lib.rs | "
316         "../../faz/private_inside.rs ../../faz/lib.rs\n"
317         "  source_file_part = lib.rs\n"
318         "  source_name_part = lib\n"
319         "  externs =\n"
320         "  rustdeps =\n"
321         "  ldflags =\n"
322         "  sources = ../../faz/private_inside.rs ../../faz/lib.rs\n";
323     std::string out_str = out.str();
324     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
325   }
326 
327   Target inside_dylib(setup.settings(), Label(SourceDir("//baz/"), "inside"));
328   inside_dylib.set_output_type(Target::RUST_LIBRARY);
329   inside_dylib.visibility().SetPublic();
330   SourceFile bazlib("//baz/lib.rs");
331   inside_dylib.sources().push_back(SourceFile("//baz/inside.rs"));
332   inside_dylib.sources().push_back(bazlib);
333   inside_dylib.source_types_used().Set(SourceFile::SOURCE_RS);
334   inside_dylib.rust_values().set_crate_root(bazlib);
335   inside_dylib.rust_values().crate_name() = "inside";
336   inside_dylib.SetToolchain(setup.toolchain());
337   ASSERT_TRUE(inside_dylib.OnResolved(&err));
338 
339   {
340     std::ostringstream out;
341     NinjaRustBinaryTargetWriter writer(&inside_dylib, out);
342     writer.Run();
343 
344     const char expected[] =
345         "crate_name = inside\n"
346         "crate_type = rlib\n"
347         "output_extension = .rlib\n"
348         "output_dir = \n"
349         "rustflags =\n"
350         "rustenv =\n"
351         "root_out_dir = .\n"
352         "target_gen_dir = gen/baz\n"
353         "target_out_dir = obj/baz\n"
354         "target_output_name = libinside\n"
355         "\n"
356         "build obj/baz/libinside.rlib: rust_rlib ../../baz/lib.rs | "
357         "../../baz/inside.rs ../../baz/lib.rs\n"
358         "  source_file_part = lib.rs\n"
359         "  source_name_part = lib\n"
360         "  externs =\n"
361         "  rustdeps =\n"
362         "  ldflags =\n"
363         "  sources = ../../baz/inside.rs ../../baz/lib.rs\n";
364     std::string out_str = out.str();
365     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
366   }
367 
368   Target dylib(setup.settings(), Label(SourceDir("//bar/"), "mylib"));
369   dylib.set_output_type(Target::SHARED_LIBRARY);
370   dylib.visibility().SetPublic();
371   SourceFile barlib("//bar/lib.rs");
372   dylib.sources().push_back(SourceFile("//bar/mylib.rs"));
373   dylib.sources().push_back(barlib);
374   dylib.source_types_used().Set(SourceFile::SOURCE_RS);
375   dylib.rust_values().set_crate_type(RustValues::CRATE_DYLIB);
376   dylib.rust_values().set_crate_root(barlib);
377   dylib.rust_values().crate_name() = "mylib";
378   dylib.public_deps().push_back(LabelTargetPair(&inside_dylib));
379   dylib.private_deps().push_back(LabelTargetPair(&private_inside_dylib));
380   dylib.SetToolchain(setup.toolchain());
381   ASSERT_TRUE(dylib.OnResolved(&err));
382 
383   {
384     std::ostringstream out;
385     NinjaRustBinaryTargetWriter writer(&dylib, out);
386     writer.Run();
387 
388     const char expected[] =
389         "crate_name = mylib\n"
390         "crate_type = dylib\n"
391         "output_extension = .so\n"
392         "output_dir = \n"
393         "rustflags =\n"
394         "rustenv =\n"
395         "root_out_dir = .\n"
396         "target_gen_dir = gen/bar\n"
397         "target_out_dir = obj/bar\n"
398         "target_output_name = libmylib\n"
399         "\n"
400         "build obj/bar/libmylib.so: rust_dylib ../../bar/lib.rs | "
401         "../../bar/mylib.rs ../../bar/lib.rs "
402         "obj/baz/libinside.rlib obj/faz/libprivate_inside.rlib\n"
403         "  source_file_part = lib.rs\n"
404         "  source_name_part = lib\n"
405         "  externs = --extern inside=obj/baz/libinside.rlib "
406         "--extern private_inside=obj/faz/libprivate_inside.rlib\n"
407         "  rustdeps = -Ldependency=obj/baz -Ldependency=obj/faz\n"
408         "  ldflags =\n"
409         "  sources = ../../bar/mylib.rs ../../bar/lib.rs\n";
410     std::string out_str = out.str();
411     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
412   }
413 
414   Target private_dylib(setup.settings(),
415                        Label(SourceDir("//private_dylib/"), "private_dylib"));
416   private_dylib.set_output_type(Target::SHARED_LIBRARY);
417   private_dylib.visibility().SetPublic();
418   SourceFile private_dyliblib("//private_dylib/lib.rs");
419   private_dylib.sources().push_back(SourceFile("//private_dylib/mylib.rs"));
420   private_dylib.sources().push_back(private_dyliblib);
421   private_dylib.source_types_used().Set(SourceFile::SOURCE_RS);
422   private_dylib.rust_values().set_crate_type(RustValues::CRATE_DYLIB);
423   private_dylib.rust_values().set_crate_root(private_dyliblib);
424   private_dylib.rust_values().crate_name() = "private_dylib";
425   private_dylib.SetToolchain(setup.toolchain());
426   ASSERT_TRUE(private_dylib.OnResolved(&err));
427 
428   Target another_dylib(setup.settings(), Label(SourceDir("//foo/"), "direct"));
429   another_dylib.set_output_type(Target::SHARED_LIBRARY);
430   another_dylib.visibility().SetPublic();
431   SourceFile lib("//foo/main.rs");
432   another_dylib.sources().push_back(SourceFile("//foo/direct.rs"));
433   another_dylib.sources().push_back(lib);
434   another_dylib.source_types_used().Set(SourceFile::SOURCE_RS);
435   another_dylib.rust_values().set_crate_type(RustValues::CRATE_DYLIB);
436   another_dylib.rust_values().set_crate_root(lib);
437   another_dylib.rust_values().crate_name() = "direct";
438   another_dylib.SetToolchain(setup.toolchain());
439   another_dylib.public_deps().push_back(LabelTargetPair(&dylib));
440   another_dylib.private_deps().push_back(LabelTargetPair(&private_dylib));
441   ASSERT_TRUE(another_dylib.OnResolved(&err));
442 
443   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
444   target.set_output_type(Target::EXECUTABLE);
445   target.visibility().SetPublic();
446   SourceFile main("//foo/main.rs");
447   target.sources().push_back(SourceFile("//foo/source.rs"));
448   target.sources().push_back(main);
449   target.source_types_used().Set(SourceFile::SOURCE_RS);
450   target.rust_values().set_crate_root(main);
451   target.rust_values().crate_name() = "foo_bar";
452   target.private_deps().push_back(LabelTargetPair(&another_dylib));
453   target.SetToolchain(setup.toolchain());
454   ASSERT_TRUE(target.OnResolved(&err));
455 
456   {
457     std::ostringstream out;
458     NinjaRustBinaryTargetWriter writer(&target, out);
459     writer.Run();
460 
461     const char expected[] =
462         "crate_name = foo_bar\n"
463         "crate_type = bin\n"
464         "output_extension = \n"
465         "output_dir = \n"
466         "rustflags =\n"
467         "rustenv =\n"
468         "root_out_dir = .\n"
469         "target_gen_dir = gen/foo\n"
470         "target_out_dir = obj/foo\n"
471         "target_output_name = bar\n"
472         "\n"
473         "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs "
474         "../../foo/main.rs obj/foo/libdirect.so obj/bar/libmylib.so "
475         "obj/baz/libinside.rlib\n"
476         "  source_file_part = main.rs\n"
477         "  source_name_part = main\n"
478         "  externs = --extern direct=obj/foo/libdirect.so "
479         "--extern mylib=obj/bar/libmylib.so "
480         "--extern inside=obj/baz/libinside.rlib\n"
481         "  rustdeps = -Ldependency=obj/foo -Ldependency=obj/bar "
482         "-Ldependency=obj/baz -Ldependency=obj/faz "
483         "-Ldependency=obj/private_dylib\n"
484         "  ldflags =\n"
485         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
486     std::string out_str = out.str();
487     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
488   }
489 }
490 
TEST_F(NinjaRustBinaryTargetWriterTest,RlibDepsAcrossGroups)491 TEST_F(NinjaRustBinaryTargetWriterTest, RlibDepsAcrossGroups) {
492   Err err;
493   TestWithScope setup;
494 
495   Target procmacro(setup.settings(), Label(SourceDir("//bar/"), "mymacro"));
496   procmacro.set_output_type(Target::RUST_PROC_MACRO);
497   procmacro.visibility().SetPublic();
498   SourceFile barproc("//bar/lib.rs");
499   procmacro.sources().push_back(SourceFile("//bar/mylib.rs"));
500   procmacro.sources().push_back(barproc);
501   procmacro.source_types_used().Set(SourceFile::SOURCE_RS);
502   procmacro.rust_values().set_crate_root(barproc);
503   procmacro.rust_values().crate_name() = "mymacro";
504   procmacro.rust_values().set_crate_type(RustValues::CRATE_PROC_MACRO);
505   procmacro.SetToolchain(setup.toolchain());
506   ASSERT_TRUE(procmacro.OnResolved(&err));
507 
508   {
509     std::ostringstream out;
510     NinjaRustBinaryTargetWriter writer(&procmacro, out);
511     writer.Run();
512 
513     const char expected[] =
514         "crate_name = mymacro\n"
515         "crate_type = proc-macro\n"
516         "output_extension = .so\n"
517         "output_dir = \n"
518         "rustflags =\n"
519         "rustenv =\n"
520         "root_out_dir = .\n"
521         "target_gen_dir = gen/bar\n"
522         "target_out_dir = obj/bar\n"
523         "target_output_name = libmymacro\n"
524         "\n"
525         "build obj/bar/libmymacro.so: rust_macro ../../bar/lib.rs | "
526         "../../bar/mylib.rs ../../bar/lib.rs\n"
527         "  source_file_part = lib.rs\n"
528         "  source_name_part = lib\n"
529         "  externs =\n"
530         "  rustdeps =\n"
531         "  ldflags =\n"
532         "  sources = ../../bar/mylib.rs ../../bar/lib.rs\n";
533     std::string out_str = out.str();
534     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
535   }
536 
537   // A group produces an order-only dependency in ninja:
538   // https://ninja-build.org/manual.html#ref_dependencies.
539   //
540   // If a crate D inside the group is visible to a crate C depending on the
541   // group, the crate C needs to be rebuilt when D is changed. The group
542   // dependency does not guarantee that it would, so we test that C has an
543   // indirect dependency on D through this group.
544   Target group(setup.settings(), Label(SourceDir("//baz/"), "group"));
545   group.set_output_type(Target::GROUP);
546   group.visibility().SetPublic();
547   group.public_deps().push_back(LabelTargetPair(&procmacro));
548   group.SetToolchain(setup.toolchain());
549   ASSERT_TRUE(group.OnResolved(&err));
550 
551   Target rlib(setup.settings(), Label(SourceDir("//bar/"), "mylib"));
552   rlib.set_output_type(Target::RUST_LIBRARY);
553   rlib.visibility().SetPublic();
554   SourceFile barlib("//bar/lib.rs");
555   rlib.sources().push_back(SourceFile("//bar/mylib.rs"));
556   rlib.sources().push_back(barlib);
557   rlib.source_types_used().Set(SourceFile::SOURCE_RS);
558   rlib.rust_values().set_crate_root(barlib);
559   rlib.rust_values().crate_name() = "mylib";
560   rlib.SetToolchain(setup.toolchain());
561   rlib.public_deps().push_back(LabelTargetPair(&group));
562   ASSERT_TRUE(rlib.OnResolved(&err));
563 
564   {
565     std::ostringstream out;
566     NinjaRustBinaryTargetWriter writer(&rlib, out);
567     writer.Run();
568 
569     // libmymacro.so is inside the obj/baz/group, so would be built before
570     // libmylib.rlib. However it must also cause libmylib.rlib to be recompiled
571     // when changed, so we expect an implicit dependency (appearing after `|` on
572     // the build line) from libmylib.rlib to libmymacro.so.
573     const char expected[] =
574         "crate_name = mylib\n"
575         "crate_type = rlib\n"
576         "output_extension = .rlib\n"
577         "output_dir = \n"
578         "rustflags =\n"
579         "rustenv =\n"
580         "root_out_dir = .\n"
581         "target_gen_dir = gen/bar\n"
582         "target_out_dir = obj/bar\n"
583         "target_output_name = libmylib\n"
584         "\n"
585         "build obj/bar/libmylib.rlib: rust_rlib ../../bar/lib.rs | "
586         "../../bar/mylib.rs ../../bar/lib.rs obj/bar/libmymacro.so || "
587         "obj/baz/group.stamp\n"
588         "  source_file_part = lib.rs\n"
589         "  source_name_part = lib\n"
590         "  externs = --extern mymacro=obj/bar/libmymacro.so\n"
591         "  rustdeps = -Ldependency=obj/bar\n"
592         "  ldflags =\n"
593         "  sources = ../../bar/mylib.rs ../../bar/lib.rs\n";
594     std::string out_str = out.str();
595     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
596   }
597 
598   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
599   target.set_output_type(Target::EXECUTABLE);
600   target.visibility().SetPublic();
601   SourceFile main("//foo/main.rs");
602   target.sources().push_back(SourceFile("//foo/source.rs"));
603   target.sources().push_back(main);
604   target.source_types_used().Set(SourceFile::SOURCE_RS);
605   target.rust_values().set_crate_root(main);
606   target.rust_values().crate_name() = "foo_bar";
607   target.private_deps().push_back(LabelTargetPair(&rlib));
608   target.SetToolchain(setup.toolchain());
609   ASSERT_TRUE(target.OnResolved(&err));
610 
611   {
612     std::ostringstream out;
613     NinjaRustBinaryTargetWriter writer(&target, out);
614     writer.Run();
615 
616     const char expected[] =
617         "crate_name = foo_bar\n"
618         "crate_type = bin\n"
619         "output_extension = \n"
620         "output_dir = \n"
621         "rustflags =\n"
622         "rustenv =\n"
623         "root_out_dir = .\n"
624         "target_gen_dir = gen/foo\n"
625         "target_out_dir = obj/foo\n"
626         "target_output_name = bar\n"
627         "\n"
628         "build ./foo_bar: rust_bin ../../foo/main.rs | "
629         "../../foo/source.rs ../../foo/main.rs "
630         "obj/bar/libmylib.rlib obj/bar/libmymacro.so\n"
631         "  source_file_part = main.rs\n"
632         "  source_name_part = main\n"
633         "  externs = --extern mylib=obj/bar/libmylib.rlib "
634         "--extern mymacro=obj/bar/libmymacro.so\n"
635         "  rustdeps = -Ldependency=obj/bar\n"
636         "  ldflags =\n"
637         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
638     std::string out_str = out.str();
639     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
640   }
641 }
642 
TEST_F(NinjaRustBinaryTargetWriterTest,RenamedDeps)643 TEST_F(NinjaRustBinaryTargetWriterTest, RenamedDeps) {
644   Err err;
645   TestWithScope setup;
646 
647   Target transitive(setup.settings(), Label(SourceDir("//faz/"), "transitive"));
648   transitive.set_output_type(Target::RUST_LIBRARY);
649   transitive.visibility().SetPublic();
650   SourceFile transitive_lib("//faz/transitive/lib.rs");
651   transitive.sources().push_back(SourceFile("//faz/transitive/transitive.rs"));
652   transitive.sources().push_back(transitive_lib);
653   transitive.source_types_used().Set(SourceFile::SOURCE_RS);
654   transitive.rust_values().set_crate_root(transitive_lib);
655   transitive.rust_values().crate_name() = "transitive";
656   transitive.SetToolchain(setup.toolchain());
657   ASSERT_TRUE(transitive.OnResolved(&err));
658 
659   Target rlib(setup.settings(), Label(SourceDir("//baz/"), "mylib"));
660   rlib.set_output_type(Target::RUST_LIBRARY);
661   rlib.visibility().SetPublic();
662   SourceFile barlib("//baz/bar/lib.rs");
663   rlib.sources().push_back(SourceFile("//baz/bar/mylib.rs"));
664   rlib.sources().push_back(barlib);
665   rlib.source_types_used().Set(SourceFile::SOURCE_RS);
666   rlib.rust_values().set_crate_root(barlib);
667   rlib.rust_values().crate_name() = "mylib";
668   rlib.SetToolchain(setup.toolchain());
669   rlib.public_deps().push_back(LabelTargetPair(&transitive));
670   ASSERT_TRUE(rlib.OnResolved(&err));
671 
672   Target direct(setup.settings(), Label(SourceDir("//bar/"), "direct"));
673   direct.set_output_type(Target::RUST_LIBRARY);
674   direct.visibility().SetPublic();
675   SourceFile direct_lib("//bar/direct/lib.rs");
676   direct.sources().push_back(SourceFile("//bar/direct/direct.rs"));
677   direct.sources().push_back(direct_lib);
678   direct.source_types_used().Set(SourceFile::SOURCE_RS);
679   direct.rust_values().set_crate_root(direct_lib);
680   direct.rust_values().crate_name() = "direct";
681   direct.SetToolchain(setup.toolchain());
682   ASSERT_TRUE(direct.OnResolved(&err));
683 
684   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
685   target.set_output_type(Target::EXECUTABLE);
686   target.visibility().SetPublic();
687   SourceFile main("//foo/main.rs");
688   target.sources().push_back(SourceFile("//foo/source.rs"));
689   target.sources().push_back(main);
690   target.source_types_used().Set(SourceFile::SOURCE_RS);
691   target.rust_values().set_crate_root(main);
692   target.rust_values().crate_name() = "foo_bar";
693   // A direct dependency is renamed.
694   target.rust_values().aliased_deps()[direct.label()] = "direct_renamed";
695   // A transitive public dependency, through `rlib`, is renamed.
696   target.rust_values().aliased_deps()[transitive.label()] =
697       "transitive_renamed";
698   target.private_deps().push_back(LabelTargetPair(&direct));
699   target.private_deps().push_back(LabelTargetPair(&rlib));
700   target.SetToolchain(setup.toolchain());
701   ASSERT_TRUE(target.OnResolved(&err));
702 
703   {
704     std::ostringstream out;
705     NinjaRustBinaryTargetWriter writer(&target, out);
706     writer.Run();
707 
708     const char expected[] =
709         "crate_name = foo_bar\n"
710         "crate_type = bin\n"
711         "output_extension = \n"
712         "output_dir = \n"
713         "rustflags =\n"
714         "rustenv =\n"
715         "root_out_dir = .\n"
716         "target_gen_dir = gen/foo\n"
717         "target_out_dir = obj/foo\n"
718         "target_output_name = bar\n"
719         "\n"
720         "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs "
721         "../../foo/main.rs obj/bar/libdirect.rlib obj/baz/libmylib.rlib "
722         "obj/faz/libtransitive.rlib\n"
723         "  source_file_part = main.rs\n"
724         "  source_name_part = main\n"
725         "  externs = --extern direct_renamed=obj/bar/libdirect.rlib "
726         "--extern mylib=obj/baz/libmylib.rlib "
727         "--extern transitive_renamed=obj/faz/libtransitive.rlib\n"
728         "  rustdeps = -Ldependency=obj/bar -Ldependency=obj/baz "
729         "-Ldependency=obj/faz\n"
730         "  ldflags =\n"
731         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
732     std::string out_str = out.str();
733     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
734   }
735 }
736 
TEST_F(NinjaRustBinaryTargetWriterTest,NonRustDeps)737 TEST_F(NinjaRustBinaryTargetWriterTest, NonRustDeps) {
738   Err err;
739   TestWithScope setup;
740 
741   Target staticlib(setup.settings(), Label(SourceDir("//foo/"), "static"));
742   staticlib.set_output_type(Target::STATIC_LIBRARY);
743   staticlib.visibility().SetPublic();
744   staticlib.sources().push_back(SourceFile("//foo/static.cpp"));
745   staticlib.source_types_used().Set(SourceFile::SOURCE_CPP);
746   staticlib.SetToolchain(setup.toolchain());
747   ASSERT_TRUE(staticlib.OnResolved(&err));
748 
749   Target rlib(setup.settings(), Label(SourceDir("//bar/"), "mylib"));
750   rlib.set_output_type(Target::RUST_LIBRARY);
751   rlib.visibility().SetPublic();
752   SourceFile barlib("//bar/lib.rs");
753   rlib.sources().push_back(SourceFile("//bar/mylib.rs"));
754   rlib.sources().push_back(barlib);
755   rlib.source_types_used().Set(SourceFile::SOURCE_RS);
756   rlib.rust_values().set_crate_root(barlib);
757   rlib.rust_values().crate_name() = "mylib";
758   rlib.SetToolchain(setup.toolchain());
759   ASSERT_TRUE(rlib.OnResolved(&err));
760 
761   Target sharedlib(setup.settings(), Label(SourceDir("//foo/"), "shared"));
762   sharedlib.set_output_type(Target::SHARED_LIBRARY);
763   sharedlib.visibility().SetPublic();
764   sharedlib.sources().push_back(SourceFile("//foo/static.cpp"));
765   sharedlib.source_types_used().Set(SourceFile::SOURCE_CPP);
766   sharedlib.SetToolchain(setup.toolchain());
767   ASSERT_TRUE(sharedlib.OnResolved(&err));
768 
769   Target csourceset(setup.settings(), Label(SourceDir("//baz/"), "sourceset"));
770   csourceset.set_output_type(Target::SOURCE_SET);
771   csourceset.visibility().SetPublic();
772   csourceset.sources().push_back(SourceFile("//baz/csourceset.cpp"));
773   csourceset.source_types_used().Set(SourceFile::SOURCE_CPP);
774   csourceset.SetToolchain(setup.toolchain());
775   ASSERT_TRUE(csourceset.OnResolved(&err));
776 
777   Toolchain toolchain_with_toc(
778       setup.settings(), Label(SourceDir("//toolchain_with_toc/"), "with_toc"));
779   TestWithScope::SetupToolchain(&toolchain_with_toc, true);
780   Target sharedlib_with_toc(setup.settings(),
781                             Label(SourceDir("//foo/"), "shared_with_toc"));
782   sharedlib_with_toc.set_output_type(Target::SHARED_LIBRARY);
783   sharedlib_with_toc.visibility().SetPublic();
784   sharedlib_with_toc.sources().push_back(SourceFile("//foo/static.cpp"));
785   sharedlib_with_toc.source_types_used().Set(SourceFile::SOURCE_CPP);
786   sharedlib_with_toc.SetToolchain(&toolchain_with_toc);
787   ASSERT_TRUE(sharedlib_with_toc.OnResolved(&err));
788 
789   Target nonrust(setup.settings(), Label(SourceDir("//foo/"), "bar"));
790   nonrust.set_output_type(Target::EXECUTABLE);
791   nonrust.visibility().SetPublic();
792   SourceFile main("//foo/main.rs");
793   nonrust.sources().push_back(SourceFile("//foo/source.rs"));
794   nonrust.sources().push_back(main);
795   nonrust.source_types_used().Set(SourceFile::SOURCE_RS);
796   nonrust.rust_values().set_crate_root(main);
797   nonrust.rust_values().crate_name() = "foo_bar";
798   nonrust.private_deps().push_back(LabelTargetPair(&rlib));
799   nonrust.private_deps().push_back(LabelTargetPair(&staticlib));
800   nonrust.private_deps().push_back(LabelTargetPair(&sharedlib));
801   nonrust.private_deps().push_back(LabelTargetPair(&csourceset));
802   nonrust.private_deps().push_back(LabelTargetPair(&sharedlib_with_toc));
803   nonrust.SetToolchain(setup.toolchain());
804   ASSERT_TRUE(nonrust.OnResolved(&err));
805 
806   {
807     std::ostringstream out;
808     NinjaRustBinaryTargetWriter writer(&nonrust, out);
809     writer.Run();
810 
811     const char expected[] =
812         "crate_name = foo_bar\n"
813         "crate_type = bin\n"
814         "output_extension = \n"
815         "output_dir = \n"
816         "rustflags =\n"
817         "rustenv =\n"
818         "root_out_dir = .\n"
819         "target_gen_dir = gen/foo\n"
820         "target_out_dir = obj/foo\n"
821         "target_output_name = bar\n"
822         "\n"
823         "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs "
824         "../../foo/main.rs obj/baz/sourceset.csourceset.o "
825         "obj/bar/libmylib.rlib "
826         "obj/foo/libstatic.a ./libshared.so ./libshared_with_toc.so.TOC "
827         "|| obj/baz/sourceset.stamp\n"
828         "  source_file_part = main.rs\n"
829         "  source_name_part = main\n"
830         "  externs = --extern mylib=obj/bar/libmylib.rlib\n"
831         "  rustdeps = -Ldependency=obj/bar "
832         "-Lnative=obj/baz -Lnative=obj/foo -Lnative=. "
833         "-Clink-arg=-Bdynamic -Clink-arg=obj/baz/sourceset.csourceset.o "
834         "-Clink-arg=obj/foo/libstatic.a -Clink-arg=./libshared.so "
835         "-Clink-arg=./libshared_with_toc.so\n"
836         "  ldflags =\n"
837         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
838     std::string out_str = out.str();
839     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
840   }
841 
842   Target nonrust_only(setup.settings(), Label(SourceDir("//foo/"), "bar"));
843   nonrust_only.set_output_type(Target::EXECUTABLE);
844   nonrust_only.visibility().SetPublic();
845   nonrust_only.sources().push_back(SourceFile("//foo/source.rs"));
846   nonrust_only.sources().push_back(main);
847   nonrust_only.source_types_used().Set(SourceFile::SOURCE_RS);
848   nonrust_only.rust_values().set_crate_root(main);
849   nonrust_only.rust_values().crate_name() = "foo_bar";
850   nonrust_only.private_deps().push_back(LabelTargetPair(&staticlib));
851   nonrust_only.SetToolchain(setup.toolchain());
852   ASSERT_TRUE(nonrust_only.OnResolved(&err));
853 
854   {
855     std::ostringstream out;
856     NinjaRustBinaryTargetWriter writer(&nonrust_only, out);
857     writer.Run();
858 
859     const char expected[] =
860         "crate_name = foo_bar\n"
861         "crate_type = bin\n"
862         "output_extension = \n"
863         "output_dir = \n"
864         "rustflags =\n"
865         "rustenv =\n"
866         "root_out_dir = .\n"
867         "target_gen_dir = gen/foo\n"
868         "target_out_dir = obj/foo\n"
869         "target_output_name = bar\n"
870         "\n"
871         "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs "
872         "../../foo/main.rs obj/foo/libstatic.a\n"
873         "  source_file_part = main.rs\n"
874         "  source_name_part = main\n"
875         "  externs =\n"
876         "  rustdeps = -Lnative=obj/foo -Clink-arg=-Bdynamic "
877         "-Clink-arg=obj/foo/libstatic.a\n"
878         "  ldflags =\n"
879         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
880     std::string out_str = out.str();
881     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
882   }
883 
884   Target rstaticlib(setup.settings(), Label(SourceDir("//baz/"), "baz"));
885   rstaticlib.set_output_type(Target::STATIC_LIBRARY);
886   rstaticlib.visibility().SetPublic();
887   SourceFile bazlib("//baz/lib.rs");
888   rstaticlib.sources().push_back(bazlib);
889   rstaticlib.source_types_used().Set(SourceFile::SOURCE_RS);
890   rstaticlib.rust_values().set_crate_root(bazlib);
891   rstaticlib.rust_values().crate_name() = "baz";
892   rstaticlib.private_deps().push_back(LabelTargetPair(&staticlib));
893   rstaticlib.SetToolchain(setup.toolchain());
894   ASSERT_TRUE(rstaticlib.OnResolved(&err));
895 
896   {
897     std::ostringstream out;
898     NinjaRustBinaryTargetWriter writer(&rstaticlib, out);
899     writer.Run();
900 
901     const char expected[] =
902         "crate_name = baz\n"
903         "crate_type = staticlib\n"
904         "output_extension = .a\n"
905         "output_dir = \n"
906         "rustflags =\n"
907         "rustenv =\n"
908         "root_out_dir = .\n"
909         "target_gen_dir = gen/baz\n"
910         "target_out_dir = obj/baz\n"
911         "target_output_name = libbaz\n"
912         "\n"
913         "build obj/baz/libbaz.a: rust_staticlib ../../baz/lib.rs | "
914         "../../baz/lib.rs "
915         "obj/foo/libstatic.a\n"
916         "  source_file_part = lib.rs\n"
917         "  source_name_part = lib\n"
918         "  externs =\n"
919         "  rustdeps = -Lnative=obj/foo -Clink-arg=-Balternative-dynamic "
920         "-Clink-arg=obj/foo/libstatic.a\n"
921         "  ldflags =\n"
922         "  sources = ../../baz/lib.rs\n";
923     std::string out_str = out.str();
924     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
925   }
926 }
927 
TEST_F(NinjaRustBinaryTargetWriterTest,RlibInLibrary)928 TEST_F(NinjaRustBinaryTargetWriterTest, RlibInLibrary) {
929   Err err;
930   TestWithScope setup;
931 
932   Target priv_sset_in_staticlib(
933       setup.settings(),
934       Label(SourceDir("//priv_sset_in_staticlib/"), "priv_sset_in_staticlib"));
935   priv_sset_in_staticlib.set_output_type(Target::SOURCE_SET);
936   priv_sset_in_staticlib.visibility().SetPublic();
937   priv_sset_in_staticlib.sources().push_back(
938       SourceFile("//priv_sset_in_staticlib/lib.cc"));
939   priv_sset_in_staticlib.source_types_used().Set(SourceFile::SOURCE_CPP);
940   priv_sset_in_staticlib.SetToolchain(setup.toolchain());
941   ASSERT_TRUE(priv_sset_in_staticlib.OnResolved(&err));
942 
943   Target pub_sset_in_staticlib(
944       setup.settings(),
945       Label(SourceDir("//pub_sset_in_staticlib/"), "pub_sset_in_staticlib"));
946   pub_sset_in_staticlib.set_output_type(Target::SOURCE_SET);
947   pub_sset_in_staticlib.visibility().SetPublic();
948   pub_sset_in_staticlib.sources().push_back(
949       SourceFile("//pub_sset_in_staticlib/lib.cc"));
950   pub_sset_in_staticlib.source_types_used().Set(SourceFile::SOURCE_CPP);
951   pub_sset_in_staticlib.SetToolchain(setup.toolchain());
952   ASSERT_TRUE(pub_sset_in_staticlib.OnResolved(&err));
953 
954   Target priv_sset_in_dylib(
955       setup.settings(),
956       Label(SourceDir("//priv_sset_in_dylib/"), "priv_sset_in_dylib"));
957   priv_sset_in_dylib.set_output_type(Target::SOURCE_SET);
958   priv_sset_in_dylib.visibility().SetPublic();
959   priv_sset_in_dylib.sources().push_back(
960       SourceFile("//priv_sset_in_dylib/lib.cc"));
961   priv_sset_in_dylib.source_types_used().Set(SourceFile::SOURCE_CPP);
962   priv_sset_in_dylib.SetToolchain(setup.toolchain());
963   ASSERT_TRUE(priv_sset_in_dylib.OnResolved(&err));
964 
965   Target pub_sset_in_dylib(
966       setup.settings(),
967       Label(SourceDir("//pub_sset_in_dylib"), "pub_sset_in_dylib"));
968   pub_sset_in_dylib.set_output_type(Target::SOURCE_SET);
969   pub_sset_in_dylib.visibility().SetPublic();
970   pub_sset_in_dylib.sources().push_back(
971       SourceFile("//pub_sset_in_dylib/lib.cc"));
972   pub_sset_in_dylib.source_types_used().Set(SourceFile::SOURCE_CPP);
973   pub_sset_in_dylib.SetToolchain(setup.toolchain());
974   ASSERT_TRUE(pub_sset_in_dylib.OnResolved(&err));
975 
976   Target priv_in_staticlib(
977       setup.settings(),
978       Label(SourceDir("//priv_in_staticlib/"), "priv_in_staticlib"));
979   priv_in_staticlib.set_output_type(Target::RUST_LIBRARY);
980   priv_in_staticlib.visibility().SetPublic();
981   SourceFile priv_in_staticlib_root("//priv_in_staticlib/lib.rs");
982   priv_in_staticlib.sources().push_back(priv_in_staticlib_root);
983   priv_in_staticlib.source_types_used().Set(SourceFile::SOURCE_RS);
984   priv_in_staticlib.rust_values().set_crate_root(priv_in_staticlib_root);
985   priv_in_staticlib.rust_values().crate_name() = "priv_in_staticlib";
986   priv_in_staticlib.SetToolchain(setup.toolchain());
987   priv_in_staticlib.private_deps().push_back(
988       LabelTargetPair(&priv_sset_in_staticlib));
989   ASSERT_TRUE(priv_in_staticlib.OnResolved(&err));
990 
991   Target pub_in_staticlib(
992       setup.settings(),
993       Label(SourceDir("//pub_in_staticlib/"), "pub_in_staticlib"));
994   pub_in_staticlib.set_output_type(Target::RUST_LIBRARY);
995   pub_in_staticlib.visibility().SetPublic();
996   SourceFile pub_in_staticlib_root("//pub_in_staticlib/lib.rs");
997   pub_in_staticlib.sources().push_back(pub_in_staticlib_root);
998   pub_in_staticlib.source_types_used().Set(SourceFile::SOURCE_RS);
999   pub_in_staticlib.rust_values().set_crate_root(pub_in_staticlib_root);
1000   pub_in_staticlib.rust_values().crate_name() = "pub_in_staticlib";
1001   pub_in_staticlib.SetToolchain(setup.toolchain());
1002   pub_in_staticlib.private_deps().push_back(
1003       LabelTargetPair(&pub_sset_in_staticlib));
1004   ASSERT_TRUE(pub_in_staticlib.OnResolved(&err));
1005 
1006   Target priv_in_dylib(setup.settings(),
1007                        Label(SourceDir("//priv_in_dylib/"), "priv_in_dylib"));
1008   priv_in_dylib.set_output_type(Target::RUST_LIBRARY);
1009   priv_in_dylib.visibility().SetPublic();
1010   SourceFile priv_in_dylib_root("//priv_in_dylib/lib.rs");
1011   priv_in_dylib.sources().push_back(priv_in_dylib_root);
1012   priv_in_dylib.source_types_used().Set(SourceFile::SOURCE_RS);
1013   priv_in_dylib.rust_values().set_crate_root(priv_in_dylib_root);
1014   priv_in_dylib.rust_values().crate_name() = "priv_in_dylib";
1015   priv_in_dylib.SetToolchain(setup.toolchain());
1016   priv_in_dylib.private_deps().push_back(LabelTargetPair(&priv_sset_in_dylib));
1017   ASSERT_TRUE(priv_in_dylib.OnResolved(&err));
1018 
1019   Target pub_in_dylib(setup.settings(),
1020                       Label(SourceDir("//pub_in_dylib/"), "pub_in_dylib"));
1021   pub_in_dylib.set_output_type(Target::RUST_LIBRARY);
1022   pub_in_dylib.visibility().SetPublic();
1023   SourceFile pub_in_dylib_root("//pub_in_dylib/lib.rs");
1024   pub_in_dylib.sources().push_back(pub_in_dylib_root);
1025   pub_in_dylib.source_types_used().Set(SourceFile::SOURCE_RS);
1026   pub_in_dylib.rust_values().set_crate_root(pub_in_dylib_root);
1027   pub_in_dylib.rust_values().crate_name() = "pub_in_dylib";
1028   pub_in_dylib.SetToolchain(setup.toolchain());
1029   pub_in_dylib.private_deps().push_back(LabelTargetPair(&pub_sset_in_dylib));
1030   ASSERT_TRUE(pub_in_dylib.OnResolved(&err));
1031 
1032   Target staticlib(setup.settings(),
1033                    Label(SourceDir("//staticlib/"), "staticlib"));
1034   staticlib.set_output_type(Target::STATIC_LIBRARY);
1035   staticlib.visibility().SetPublic();
1036   staticlib.sources().push_back(SourceFile("//staticlib/lib.cc"));
1037   staticlib.source_types_used().Set(SourceFile::SOURCE_CPP);
1038   staticlib.public_deps().push_back(LabelTargetPair(&pub_in_staticlib));
1039   staticlib.private_deps().push_back(LabelTargetPair(&priv_in_staticlib));
1040   staticlib.SetToolchain(setup.toolchain());
1041   ASSERT_TRUE(staticlib.OnResolved(&err));
1042 
1043   Target dylib(setup.settings(), Label(SourceDir("//dylib/"), "dylib"));
1044   dylib.set_output_type(Target::SHARED_LIBRARY);
1045   dylib.visibility().SetPublic();
1046   SourceFile dylib_root("//dylib/lib.rs");
1047   dylib.sources().push_back(dylib_root);
1048   dylib.source_types_used().Set(SourceFile::SOURCE_RS);
1049   dylib.rust_values().set_crate_root(dylib_root);
1050   dylib.rust_values().crate_name() = "dylib";
1051   dylib.public_deps().push_back(LabelTargetPair(&pub_in_dylib));
1052   dylib.private_deps().push_back(LabelTargetPair(&priv_in_dylib));
1053   dylib.SetToolchain(setup.toolchain());
1054   ASSERT_TRUE(dylib.OnResolved(&err));
1055 
1056   Target target(setup.settings(), Label(SourceDir("//exe/"), "exe"));
1057   target.set_output_type(Target::EXECUTABLE);
1058   target.visibility().SetPublic();
1059   SourceFile main("//exe/main.rs");
1060   target.sources().push_back(main);
1061   target.source_types_used().Set(SourceFile::SOURCE_RS);
1062   target.rust_values().set_crate_root(main);
1063   target.rust_values().crate_name() = "exe";
1064   target.private_deps().push_back(LabelTargetPair(&staticlib));
1065   target.private_deps().push_back(LabelTargetPair(&dylib));
1066   target.SetToolchain(setup.toolchain());
1067   ASSERT_TRUE(target.OnResolved(&err));
1068 
1069   std::ostringstream out;
1070   NinjaRustBinaryTargetWriter writer(&target, out);
1071   writer.Run();
1072 
1073   const char expected[] =
1074       "crate_name = exe\n"
1075       "crate_type = bin\n"
1076       "output_extension = \n"
1077       "output_dir = \n"
1078       "rustflags =\n"
1079       "rustenv =\n"
1080       "root_out_dir = .\n"
1081       "target_gen_dir = gen/exe\n"
1082       "target_out_dir = obj/exe\n"
1083       "target_output_name = exe\n"
1084       "\n"
1085       "build ./exe: rust_bin ../../exe/main.rs | "
1086       "../../exe/main.rs "
1087       "obj/pub_sset_in_staticlib/pub_sset_in_staticlib.lib.o "
1088       "obj/priv_sset_in_staticlib/priv_sset_in_staticlib.lib.o "
1089       "obj/staticlib/libstaticlib.a "
1090       "obj/dylib/libdylib.so "
1091       "obj/pub_in_staticlib/libpub_in_staticlib.rlib "
1092       "obj/priv_in_staticlib/libpriv_in_staticlib.rlib "
1093       "obj/pub_in_dylib/libpub_in_dylib.rlib || "
1094       "obj/pub_sset_in_staticlib/pub_sset_in_staticlib.stamp "
1095       "obj/priv_sset_in_staticlib/priv_sset_in_staticlib.stamp\n"
1096       "  source_file_part = main.rs\n"
1097       "  source_name_part = main\n"
1098       "  externs = "
1099       "--extern pub_in_staticlib=obj/pub_in_staticlib/libpub_in_staticlib.rlib "
1100       "--extern dylib=obj/dylib/libdylib.so "
1101       "--extern pub_in_dylib=obj/pub_in_dylib/libpub_in_dylib.rlib\n"
1102       "  rustdeps = -Ldependency=obj/pub_in_staticlib "
1103       "-Ldependency=obj/priv_in_staticlib -Ldependency=obj/dylib "
1104       "-Ldependency=obj/pub_in_dylib -Ldependency=obj/priv_in_dylib "
1105       "-Lnative=obj/pub_sset_in_staticlib "
1106       "-Lnative=obj/priv_sset_in_staticlib "
1107       "-Lnative=obj/staticlib -Clink-arg=-Bdynamic "
1108       "-Clink-arg=obj/pub_sset_in_staticlib/pub_sset_in_staticlib.lib.o "
1109       "-Clink-arg=obj/priv_sset_in_staticlib/priv_sset_in_staticlib.lib.o "
1110       "-Clink-arg=obj/staticlib/libstaticlib.a\n"
1111       "  ldflags =\n"
1112       "  sources = ../../exe/main.rs\n";
1113 
1114   std::string out_str = out.str();
1115   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1116 }
1117 
TEST_F(NinjaRustBinaryTargetWriterTest,RustOutputExtensionAndDir)1118 TEST_F(NinjaRustBinaryTargetWriterTest, RustOutputExtensionAndDir) {
1119   Err err;
1120   TestWithScope setup;
1121 
1122   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
1123   target.set_output_type(Target::EXECUTABLE);
1124   target.visibility().SetPublic();
1125   SourceFile main("//foo/main.rs");
1126   target.sources().push_back(SourceFile("//foo/input3.rs"));
1127   target.sources().push_back(main);
1128   target.source_types_used().Set(SourceFile::SOURCE_RS);
1129   target.set_output_extension(std::string("exe"));
1130   target.set_output_dir(SourceDir("//out/Debug/foo/"));
1131   target.rust_values().set_crate_root(main);
1132   target.rust_values().crate_name() = "foo_bar";
1133   target.SetToolchain(setup.toolchain());
1134   ASSERT_TRUE(target.OnResolved(&err));
1135 
1136   {
1137     std::ostringstream out;
1138     NinjaRustBinaryTargetWriter writer(&target, out);
1139     writer.Run();
1140 
1141     const char expected[] =
1142         "crate_name = foo_bar\n"
1143         "crate_type = bin\n"
1144         "output_extension = .exe\n"
1145         "output_dir = foo\n"
1146         "rustflags =\n"
1147         "rustenv =\n"
1148         "root_out_dir = .\n"
1149         "target_gen_dir = gen/foo\n"
1150         "target_out_dir = obj/foo\n"
1151         "target_output_name = bar\n"
1152         "\n"
1153         "build ./foo_bar.exe: rust_bin ../../foo/main.rs | ../../foo/input3.rs "
1154         "../../foo/main.rs\n"
1155         "  source_file_part = main.rs\n"
1156         "  source_name_part = main\n"
1157         "  externs =\n"
1158         "  rustdeps =\n"
1159         "  ldflags =\n"
1160         "  sources = ../../foo/input3.rs ../../foo/main.rs\n";
1161     std::string out_str = out.str();
1162     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1163   }
1164 }
1165 
TEST_F(NinjaRustBinaryTargetWriterTest,LibsAndLibDirs)1166 TEST_F(NinjaRustBinaryTargetWriterTest, LibsAndLibDirs) {
1167   Err err;
1168   TestWithScope setup;
1169 
1170   Target rlib(setup.settings(), Label(SourceDir("//bar/"), "rlib"));
1171   rlib.set_output_type(Target::RUST_LIBRARY);
1172   rlib.visibility().SetPublic();
1173   SourceFile barlib("//bar/lib.rs");
1174   rlib.sources().push_back(SourceFile("//bar/rlib.rs"));
1175   rlib.sources().push_back(barlib);
1176   rlib.source_types_used().Set(SourceFile::SOURCE_RS);
1177   rlib.rust_values().set_crate_root(barlib);
1178   rlib.rust_values().crate_name() = "rlibcrate";
1179   rlib.config_values().libs().push_back(LibFile("rliblib"));
1180   rlib.config_values().lib_dirs().push_back(SourceDir("//rliblibdir/"));
1181   rlib.config_values().framework_dirs().push_back(SourceDir("//rlibfwdir/"));
1182   rlib.SetToolchain(setup.toolchain());
1183   ASSERT_TRUE(rlib.OnResolved(&err));
1184 
1185   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
1186   target.set_output_type(Target::EXECUTABLE);
1187   target.visibility().SetPublic();
1188   SourceFile main("//foo/main.rs");
1189   target.sources().push_back(SourceFile("//foo/input.rs"));
1190   target.sources().push_back(main);
1191   target.source_types_used().Set(SourceFile::SOURCE_RS);
1192   target.set_output_dir(SourceDir("//out/Debug/foo/"));
1193   target.config_values().libs().push_back(LibFile(SourceFile("//dir1/ar.a")));
1194   target.config_values().libs().push_back(LibFile("binlib"));
1195   target.config_values().lib_dirs().push_back(SourceDir("//binlibdir/"));
1196   target.config_values().framework_dirs().push_back(SourceDir("//binfwdir/"));
1197   target.public_deps().push_back(LabelTargetPair(&rlib));
1198   target.rust_values().set_crate_root(main);
1199   target.rust_values().crate_name() = "foo_bar";
1200   target.SetToolchain(setup.toolchain());
1201   ASSERT_TRUE(target.OnResolved(&err));
1202 
1203   {
1204     std::ostringstream out;
1205     NinjaRustBinaryTargetWriter writer(&target, out);
1206     writer.Run();
1207 
1208     const char expected[] =
1209         "crate_name = foo_bar\n"
1210         "crate_type = bin\n"
1211         "output_extension = \n"
1212         "output_dir = foo\n"
1213         "rustflags =\n"
1214         "rustenv =\n"
1215         "root_out_dir = .\n"
1216         "target_gen_dir = gen/foo\n"
1217         "target_out_dir = obj/foo\n"
1218         "target_output_name = bar\n"
1219         "\n"
1220         "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/input.rs "
1221         "../../foo/main.rs obj/bar/librlib.rlib\n"
1222         "  source_file_part = main.rs\n"
1223         "  source_name_part = main\n"
1224         "  externs = --extern rlibcrate=obj/bar/librlib.rlib\n"
1225         "  rustdeps = -Ldependency=obj/bar -Lnative=../../binlibdir "
1226         "-Lnative=../../rliblibdir -Lframework=../../binfwdir "
1227         "-Lframework=../../rlibfwdir -Clink-arg=../../dir1/ar.a -lbinlib "
1228         "-lrliblib\n"
1229         "  ldflags =\n"
1230         "  sources = ../../foo/input.rs ../../foo/main.rs\n";
1231     std::string out_str = out.str();
1232     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1233   }
1234 }
1235 
TEST_F(NinjaRustBinaryTargetWriterTest,RlibWithLibDeps)1236 TEST_F(NinjaRustBinaryTargetWriterTest, RlibWithLibDeps) {
1237   Err err;
1238   TestWithScope setup;
1239 
1240   Target public_rlib(setup.settings(), Label(SourceDir("//bar/"), "publiclib"));
1241   public_rlib.set_output_type(Target::RUST_LIBRARY);
1242   public_rlib.visibility().SetPublic();
1243   SourceFile barlib("//bar/lib.rs");
1244   public_rlib.sources().push_back(SourceFile("//bar/publiclib.rs"));
1245   public_rlib.sources().push_back(barlib);
1246   public_rlib.source_types_used().Set(SourceFile::SOURCE_RS);
1247   public_rlib.rust_values().set_crate_root(barlib);
1248   public_rlib.rust_values().crate_name() = "publiccrate";
1249   public_rlib.SetToolchain(setup.toolchain());
1250   ASSERT_TRUE(public_rlib.OnResolved(&err));
1251 
1252   Target staticlib(setup.settings(), Label(SourceDir("//clib/"), "static"));
1253   staticlib.set_output_type(Target::STATIC_LIBRARY);
1254   staticlib.visibility().SetPublic();
1255   staticlib.sources().push_back(SourceFile("//foo/clib.cpp"));
1256   staticlib.source_types_used().Set(SourceFile::SOURCE_CPP);
1257   staticlib.SetToolchain(setup.toolchain());
1258   ASSERT_TRUE(staticlib.OnResolved(&err));
1259 
1260   Target rlib(setup.settings(), Label(SourceDir("//foo/"), "rlibcrate"));
1261   rlib.set_output_type(Target::RUST_LIBRARY);
1262   rlib.visibility().SetPublic();
1263   SourceFile lib("//foo/input.rs");
1264   rlib.sources().push_back(lib);
1265   rlib.source_types_used().Set(SourceFile::SOURCE_RS);
1266   rlib.rust_values().set_crate_root(lib);
1267   rlib.rust_values().crate_name() = "rlibcrate";
1268   rlib.SetToolchain(setup.toolchain());
1269   rlib.public_deps().push_back(LabelTargetPair(&public_rlib));
1270 
1271   // This adds dependencies on static libraries, which are not consumed by an
1272   // rlib since it does not get linked. None of these should appear in
1273   // `rustdeps` for a `rust_rlib`, though they would for a `rust_bin` (as tested
1274   // for above).
1275   //
1276   // 1. A dependency on an archive file directly as happens with a `libs` rule,
1277   //    requesting a system library. The path to that library must be specified
1278   //    separately with `-L` in ldflags, the library does not appear in the
1279   //    rustc compilation of an rlib.
1280   rlib.config_values().libs().push_back(LibFile(SourceFile("//dir1/ar.a")));
1281   // 2. A dependency on a library name as happens with a `libs` rule. Libraries
1282   //    need only be named when linking, they do not need to appear in an rlib
1283   //    compilation.
1284   rlib.config_values().libs().push_back(LibFile("quux"));
1285   // 3. A dependency on a library path which will be used for linking, which is
1286   //    separate from the dependency paths for finding Rust crates. But it may
1287   //    be needed to resolve the path to a native library in a #[link]
1288   //    directive.
1289   rlib.config_values().lib_dirs().push_back(SourceDir("//baz/"));
1290   // 4. A framework search directory will be used for linking frameworks, which
1291   //    is also separate from finding Rust crates. Again a #[link] directive can
1292   //    point to a framework, so these paths need to be present during
1293   //    compilation
1294   rlib.config_values().framework_dirs().push_back(SourceDir("//fwdir/"));
1295   // 5. A dependency on a C library through a `deps` rule, which points to a
1296   //    `static_library` target. GN guarantees that Rust can refer to that
1297   //    library through #[link] without having to specify the path in ldflags
1298   //    as well.
1299   rlib.private_deps().push_back(LabelTargetPair(&staticlib));
1300 
1301   ASSERT_TRUE(rlib.OnResolved(&err));
1302 
1303   {
1304     std::ostringstream out;
1305     NinjaRustBinaryTargetWriter writer(&rlib, out);
1306     writer.Run();
1307 
1308     const char expected[] =
1309         "crate_name = rlibcrate\n"
1310         "crate_type = rlib\n"
1311         "output_extension = .rlib\n"
1312         "output_dir = \n"
1313         "rustflags =\n"
1314         "rustenv =\n"
1315         "root_out_dir = .\n"
1316         "target_gen_dir = gen/foo\n"
1317         "target_out_dir = obj/foo\n"
1318         "target_output_name = librlibcrate\n"
1319         "\n"
1320         "build obj/foo/librlibcrate.rlib: rust_rlib ../../foo/input.rs | "
1321         "../../foo/input.rs obj/bar/libpubliclib.rlib obj/clib/libstatic.a\n"
1322         "  source_file_part = input.rs\n"
1323         "  source_name_part = input\n"
1324         "  externs = --extern publiccrate=obj/bar/libpubliclib.rlib\n"
1325         "  rustdeps = -Ldependency=obj/bar -Lnative=obj/clib "
1326         "-Clink-arg=-Bdynamic -Clink-arg=obj/clib/libstatic.a "
1327         "-Lnative=../../baz -Lframework=../../fwdir -Clink-arg=../../dir1/ar.a "
1328         "-lquux\n"
1329         "  ldflags =\n"
1330         "  sources = ../../foo/input.rs\n";
1331     std::string out_str = out.str();
1332     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1333   }
1334 }
1335 
1336 // Test that neither public nor private rust dependencies of a proc-macro are
1337 // transitively acquired as accessible dependencies by users of the macro. But
1338 // the macro itself is listed as an accessible dependency (via --extern).
TEST_F(NinjaRustBinaryTargetWriterTest,RustProcMacro)1339 TEST_F(NinjaRustBinaryTargetWriterTest, RustProcMacro) {
1340   Err err;
1341   TestWithScope setup;
1342 
1343   Target procmacropublicdep(
1344       setup.settings(), Label(SourceDir("//baz/public/"), "mymacropublicdep"));
1345   procmacropublicdep.set_output_type(Target::RUST_LIBRARY);
1346   procmacropublicdep.visibility().SetPublic();
1347   SourceFile publicbazlib("//baz/public/lib.rs");
1348   procmacropublicdep.sources().push_back(SourceFile("//baz/public/mylib.rs"));
1349   procmacropublicdep.sources().push_back(publicbazlib);
1350   procmacropublicdep.source_types_used().Set(SourceFile::SOURCE_RS);
1351   procmacropublicdep.rust_values().set_crate_root(publicbazlib);
1352   procmacropublicdep.rust_values().crate_name() = "publicdep";
1353   procmacropublicdep.SetToolchain(setup.toolchain());
1354   ASSERT_TRUE(procmacropublicdep.OnResolved(&err));
1355 
1356   Target procmacroprivatedep(
1357       setup.settings(),
1358       Label(SourceDir("//baz/private/"), "mymacroprivatedep"));
1359   procmacroprivatedep.set_output_type(Target::RUST_LIBRARY);
1360   procmacroprivatedep.visibility().SetPublic();
1361   SourceFile privatebazlib("//baz/private/lib.rs");
1362   procmacroprivatedep.sources().push_back(SourceFile("//baz/private/mylib.rs"));
1363   procmacroprivatedep.sources().push_back(privatebazlib);
1364   procmacroprivatedep.source_types_used().Set(SourceFile::SOURCE_RS);
1365   procmacroprivatedep.rust_values().set_crate_root(privatebazlib);
1366   procmacroprivatedep.rust_values().crate_name() = "privatedep";
1367   procmacroprivatedep.SetToolchain(setup.toolchain());
1368   ASSERT_TRUE(procmacroprivatedep.OnResolved(&err));
1369 
1370   Target procmacro(setup.settings(), Label(SourceDir("//bar/"), "mymacro"));
1371   procmacro.set_output_type(Target::RUST_PROC_MACRO);
1372   procmacro.visibility().SetPublic();
1373   SourceFile barlib("//bar/lib.rs");
1374   procmacro.sources().push_back(SourceFile("//bar/mylib.rs"));
1375   procmacro.sources().push_back(barlib);
1376   procmacro.source_types_used().Set(SourceFile::SOURCE_RS);
1377   procmacro.rust_values().set_crate_root(barlib);
1378   procmacro.rust_values().crate_name() = "mymacro";
1379   procmacro.rust_values().set_crate_type(RustValues::CRATE_PROC_MACRO);
1380   // Add a dependency to the procmacro so we can be sure its output
1381   // directory is not propagated downstream beyond the proc macro.
1382   procmacro.public_deps().push_back(LabelTargetPair(&procmacropublicdep));
1383   procmacro.private_deps().push_back(LabelTargetPair(&procmacroprivatedep));
1384   procmacro.SetToolchain(setup.toolchain());
1385   ASSERT_TRUE(procmacro.OnResolved(&err));
1386 
1387   {
1388     std::ostringstream out;
1389     NinjaRustBinaryTargetWriter writer(&procmacro, out);
1390     writer.Run();
1391 
1392     const char expected[] =
1393         "crate_name = mymacro\n"
1394         "crate_type = proc-macro\n"
1395         "output_extension = .so\n"
1396         "output_dir = \n"
1397         "rustflags =\n"
1398         "rustenv =\n"
1399         "root_out_dir = .\n"
1400         "target_gen_dir = gen/bar\n"
1401         "target_out_dir = obj/bar\n"
1402         "target_output_name = libmymacro\n"
1403         "\n"
1404         "build obj/bar/libmymacro.so: rust_macro ../../bar/lib.rs | "
1405         "../../bar/mylib.rs ../../bar/lib.rs "
1406         "obj/baz/public/libmymacropublicdep.rlib "
1407         "obj/baz/private/libmymacroprivatedep.rlib\n"
1408         "  source_file_part = lib.rs\n"
1409         "  source_name_part = lib\n"
1410         "  externs = "
1411         "--extern publicdep=obj/baz/public/libmymacropublicdep.rlib "
1412         "--extern privatedep=obj/baz/private/libmymacroprivatedep.rlib\n"
1413         "  rustdeps = -Ldependency=obj/baz/public "
1414         "-Ldependency=obj/baz/private\n"
1415         "  ldflags =\n"
1416         "  sources = ../../bar/mylib.rs ../../bar/lib.rs\n";
1417     std::string out_str = out.str();
1418     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1419   }
1420 
1421   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
1422   target.set_output_type(Target::EXECUTABLE);
1423   target.visibility().SetPublic();
1424   SourceFile main("//foo/main.rs");
1425   target.sources().push_back(SourceFile("//foo/source.rs"));
1426   target.sources().push_back(main);
1427   target.source_types_used().Set(SourceFile::SOURCE_RS);
1428   target.rust_values().set_crate_root(main);
1429   target.rust_values().crate_name() = "foo_bar";
1430   target.private_deps().push_back(LabelTargetPair(&procmacro));
1431   target.SetToolchain(setup.toolchain());
1432   ASSERT_TRUE(target.OnResolved(&err));
1433 
1434   {
1435     std::ostringstream out;
1436     NinjaRustBinaryTargetWriter writer(&target, out);
1437     writer.Run();
1438 
1439     const char expected[] =
1440         "crate_name = foo_bar\n"
1441         "crate_type = bin\n"
1442         "output_extension = \n"
1443         "output_dir = \n"
1444         "rustflags =\n"
1445         "rustenv =\n"
1446         "root_out_dir = .\n"
1447         "target_gen_dir = gen/foo\n"
1448         "target_out_dir = obj/foo\n"
1449         "target_output_name = bar\n"
1450         "\n"
1451         "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs "
1452         "../../foo/main.rs obj/bar/libmymacro.so\n"
1453         "  source_file_part = main.rs\n"
1454         "  source_name_part = main\n"
1455         "  externs = --extern mymacro=obj/bar/libmymacro.so\n"
1456         "  rustdeps = -Ldependency=obj/bar\n"
1457         "  ldflags =\n"
1458         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
1459     std::string out_str = out.str();
1460     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1461   }
1462 }
1463 
TEST_F(NinjaRustBinaryTargetWriterTest,GroupDeps)1464 TEST_F(NinjaRustBinaryTargetWriterTest, GroupDeps) {
1465   Err err;
1466   TestWithScope setup;
1467 
1468   Target rlib(setup.settings(), Label(SourceDir("//bar/"), "mylib"));
1469   rlib.set_output_type(Target::RUST_LIBRARY);
1470   rlib.visibility().SetPublic();
1471   SourceFile barlib("//bar/lib.rs");
1472   rlib.sources().push_back(SourceFile("//bar/mylib.rs"));
1473   rlib.sources().push_back(barlib);
1474   rlib.source_types_used().Set(SourceFile::SOURCE_RS);
1475   rlib.rust_values().set_crate_root(barlib);
1476   rlib.rust_values().crate_name() = "mylib";
1477   rlib.SetToolchain(setup.toolchain());
1478   ASSERT_TRUE(rlib.OnResolved(&err));
1479 
1480   {
1481     std::ostringstream out;
1482     NinjaRustBinaryTargetWriter writer(&rlib, out);
1483     writer.Run();
1484 
1485     const char expected[] =
1486         "crate_name = mylib\n"
1487         "crate_type = rlib\n"
1488         "output_extension = .rlib\n"
1489         "output_dir = \n"
1490         "rustflags =\n"
1491         "rustenv =\n"
1492         "root_out_dir = .\n"
1493         "target_gen_dir = gen/bar\n"
1494         "target_out_dir = obj/bar\n"
1495         "target_output_name = libmylib\n"
1496         "\n"
1497         "build obj/bar/libmylib.rlib: rust_rlib ../../bar/lib.rs | "
1498         "../../bar/mylib.rs ../../bar/lib.rs\n"
1499         "  source_file_part = lib.rs\n"
1500         "  source_name_part = lib\n"
1501         "  externs =\n"
1502         "  rustdeps =\n"
1503         "  ldflags =\n"
1504         "  sources = ../../bar/mylib.rs ../../bar/lib.rs\n";
1505     std::string out_str = out.str();
1506     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1507   }
1508 
1509   Target group(setup.settings(), Label(SourceDir("//baz/"), "group"));
1510   group.set_output_type(Target::GROUP);
1511   group.visibility().SetPublic();
1512   group.public_deps().push_back(LabelTargetPair(&rlib));
1513   group.SetToolchain(setup.toolchain());
1514   ASSERT_TRUE(group.OnResolved(&err));
1515 
1516   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
1517   target.set_output_type(Target::EXECUTABLE);
1518   target.visibility().SetPublic();
1519   SourceFile main("//foo/main.rs");
1520   target.sources().push_back(SourceFile("//foo/source.rs"));
1521   target.sources().push_back(main);
1522   target.source_types_used().Set(SourceFile::SOURCE_RS);
1523   target.rust_values().set_crate_root(main);
1524   target.rust_values().crate_name() = "foo_bar";
1525   target.private_deps().push_back(LabelTargetPair(&group));
1526   target.SetToolchain(setup.toolchain());
1527   ASSERT_TRUE(target.OnResolved(&err));
1528 
1529   {
1530     std::ostringstream out;
1531     NinjaRustBinaryTargetWriter writer(&target, out);
1532     writer.Run();
1533 
1534     const char expected[] =
1535         "crate_name = foo_bar\n"
1536         "crate_type = bin\n"
1537         "output_extension = \n"
1538         "output_dir = \n"
1539         "rustflags =\n"
1540         "rustenv =\n"
1541         "root_out_dir = .\n"
1542         "target_gen_dir = gen/foo\n"
1543         "target_out_dir = obj/foo\n"
1544         "target_output_name = bar\n"
1545         "\n"
1546         "build ./foo_bar: rust_bin ../../foo/main.rs | "
1547         "../../foo/source.rs ../../foo/main.rs obj/bar/libmylib.rlib || "
1548         "obj/baz/group.stamp\n"
1549         "  source_file_part = main.rs\n"
1550         "  source_name_part = main\n"
1551         "  externs = --extern mylib=obj/bar/libmylib.rlib\n"
1552         "  rustdeps = -Ldependency=obj/bar\n"
1553         "  ldflags =\n"
1554         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
1555     std::string out_str = out.str();
1556     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1557   }
1558 }
1559 
TEST_F(NinjaRustBinaryTargetWriterTest,Externs)1560 TEST_F(NinjaRustBinaryTargetWriterTest, Externs) {
1561   Err err;
1562   TestWithScope setup;
1563 
1564   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
1565   target.set_output_type(Target::EXECUTABLE);
1566   target.visibility().SetPublic();
1567   SourceFile main("//foo/main.rs");
1568   target.sources().push_back(SourceFile("//foo/source.rs"));
1569   target.sources().push_back(main);
1570   target.source_types_used().Set(SourceFile::SOURCE_RS);
1571   target.rust_values().set_crate_root(main);
1572   target.rust_values().crate_name() = "foo_bar";
1573 
1574   const char* lib = "lib1";
1575   target.config_values().externs().push_back(
1576       std::pair(lib, LibFile(SourceFile("//foo/lib1.rlib"))));
1577   lib = "lib2";
1578   target.config_values().externs().push_back(
1579       std::pair(lib, LibFile("lib2.rlib")));
1580 
1581   target.SetToolchain(setup.toolchain());
1582   ASSERT_TRUE(target.OnResolved(&err));
1583 
1584   {
1585     std::ostringstream out;
1586     NinjaRustBinaryTargetWriter writer(&target, out);
1587     writer.Run();
1588 
1589     const char expected[] =
1590         "crate_name = foo_bar\n"
1591         "crate_type = bin\n"
1592         "output_extension = \n"
1593         "output_dir = \n"
1594         "rustflags =\n"
1595         "rustenv =\n"
1596         "root_out_dir = .\n"
1597         "target_gen_dir = gen/foo\n"
1598         "target_out_dir = obj/foo\n"
1599         "target_output_name = bar\n"
1600         "\n"
1601         "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs "
1602         "../../foo/main.rs ../../foo/lib1.rlib\n"
1603         "  source_file_part = main.rs\n"
1604         "  source_name_part = main\n"
1605         "  externs = --extern lib1=../../foo/lib1.rlib --extern "
1606         "lib2=lib2.rlib\n"
1607         "  rustdeps =\n"
1608         "  ldflags =\n"
1609         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
1610     std::string out_str = out.str();
1611     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1612   }
1613 }
1614 
TEST_F(NinjaRustBinaryTargetWriterTest,Inputs)1615 TEST_F(NinjaRustBinaryTargetWriterTest, Inputs) {
1616   Err err;
1617   TestWithScope setup;
1618 
1619   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
1620   target.set_output_type(Target::EXECUTABLE);
1621   target.visibility().SetPublic();
1622   SourceFile main("//foo/main.rs");
1623   target.sources().push_back(SourceFile("//foo/source.rs"));
1624   target.sources().push_back(main);
1625   target.source_types_used().Set(SourceFile::SOURCE_RS);
1626   target.rust_values().set_crate_root(main);
1627   target.rust_values().crate_name() = "foo_bar";
1628   target.config_values().inputs().push_back(SourceFile("//foo/config.json"));
1629   target.config_values().inputs().push_back(SourceFile("//foo/template.h"));
1630   target.SetToolchain(setup.toolchain());
1631   ASSERT_TRUE(target.OnResolved(&err));
1632 
1633   {
1634     std::ostringstream out;
1635     NinjaRustBinaryTargetWriter writer(&target, out);
1636     writer.Run();
1637 
1638     const char expected[] =
1639         "build obj/foo/bar.inputs.stamp: stamp ../../foo/config.json "
1640         "../../foo/template.h\n"
1641         "crate_name = foo_bar\n"
1642         "crate_type = bin\n"
1643         "output_extension = \n"
1644         "output_dir = \n"
1645         "rustflags =\n"
1646         "rustenv =\n"
1647         "root_out_dir = .\n"
1648         "target_gen_dir = gen/foo\n"
1649         "target_out_dir = obj/foo\n"
1650         "target_output_name = bar\n"
1651         "\n"
1652         "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs "
1653         "../../foo/main.rs ../../foo/config.json ../../foo/template.h "
1654         "|| obj/foo/bar.inputs.stamp\n"
1655         "  source_file_part = main.rs\n"
1656         "  source_name_part = main\n"
1657         "  externs =\n"
1658         "  rustdeps =\n"
1659         "  ldflags =\n"
1660         "  sources = ../../foo/source.rs ../../foo/main.rs "
1661         "../../foo/config.json ../../foo/template.h\n";
1662     std::string out_str = out.str();
1663     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1664   }
1665 }
1666 
TEST_F(NinjaRustBinaryTargetWriterTest,CdylibDeps)1667 TEST_F(NinjaRustBinaryTargetWriterTest, CdylibDeps) {
1668   Err err;
1669   TestWithScope setup;
1670   Target cdylib(setup.settings(), Label(SourceDir("//bar/"), "mylib"));
1671   cdylib.set_output_type(Target::SHARED_LIBRARY);
1672   cdylib.visibility().SetPublic();
1673   SourceFile barlib("//bar/lib.rs");
1674   cdylib.sources().push_back(barlib);
1675   cdylib.source_types_used().Set(SourceFile::SOURCE_RS);
1676   cdylib.rust_values().set_crate_type(RustValues::CRATE_CDYLIB);
1677   cdylib.rust_values().set_crate_root(barlib);
1678   cdylib.rust_values().crate_name() = "mylib";
1679   cdylib.SetToolchain(setup.toolchain());
1680   ASSERT_TRUE(cdylib.OnResolved(&err));
1681   {
1682     std::ostringstream out;
1683     NinjaRustBinaryTargetWriter writer(&cdylib, out);
1684     writer.Run();
1685     const char expected[] =
1686         "crate_name = mylib\n"
1687         "crate_type = cdylib\n"
1688         "output_extension = .so\n"
1689         "output_dir = \n"
1690         "rustflags =\n"
1691         "rustenv =\n"
1692         "root_out_dir = .\n"
1693         "target_gen_dir = gen/bar\n"
1694         "target_out_dir = obj/bar\n"
1695         "target_output_name = libmylib\n"
1696         "\n"
1697         "build obj/bar/libmylib.so: rust_cdylib ../../bar/lib.rs | "
1698         "../../bar/lib.rs\n"
1699         "  source_file_part = lib.rs\n"
1700         "  source_name_part = lib\n"
1701         "  externs =\n"
1702         "  rustdeps =\n"
1703         "  ldflags =\n"
1704         "  sources = ../../bar/lib.rs\n";
1705     std::string out_str = out.str();
1706     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1707   }
1708 
1709   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
1710   target.set_output_type(Target::EXECUTABLE);
1711   target.visibility().SetPublic();
1712   SourceFile main("//foo/main.rs");
1713   target.sources().push_back(SourceFile("//foo/source.rs"));
1714   target.sources().push_back(main);
1715   target.source_types_used().Set(SourceFile::SOURCE_RS);
1716   target.rust_values().set_crate_root(main);
1717   target.rust_values().crate_name() = "foo_bar";
1718   target.private_deps().push_back(LabelTargetPair(&cdylib));
1719   target.SetToolchain(setup.toolchain());
1720   ASSERT_TRUE(target.OnResolved(&err));
1721   {
1722     std::ostringstream out;
1723     NinjaRustBinaryTargetWriter writer(&target, out);
1724     writer.Run();
1725 
1726     const char expected[] =
1727         "crate_name = foo_bar\n"
1728         "crate_type = bin\n"
1729         "output_extension = \n"
1730         "output_dir = \n"
1731         "rustflags =\n"
1732         "rustenv =\n"
1733         "root_out_dir = .\n"
1734         "target_gen_dir = gen/foo\n"
1735         "target_out_dir = obj/foo\n"
1736         "target_output_name = bar\n"
1737         "\n"
1738         "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs "
1739         "../../foo/main.rs obj/bar/libmylib.so\n"
1740         "  source_file_part = main.rs\n"
1741         "  source_name_part = main\n"
1742         "  externs =\n"
1743         "  rustdeps = -Lnative=obj/bar -Clink-arg=-Bdynamic "
1744         "-Clink-arg=obj/bar/libmylib.so\n"
1745         "  ldflags =\n"
1746         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
1747     std::string out_str = out.str();
1748     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1749   }
1750 }
1751 
TEST_F(NinjaRustBinaryTargetWriterTest,TransitivePublicNonRustDeps)1752 TEST_F(NinjaRustBinaryTargetWriterTest, TransitivePublicNonRustDeps) {
1753   Err err;
1754   TestWithScope setup;
1755 
1756   // This test verifies that the Rust binary "target" links against this lib.
1757   Target implicitlib(setup.settings(), Label(SourceDir("//foo/"), "implicit"));
1758   implicitlib.set_output_type(Target::SHARED_LIBRARY);
1759   implicitlib.visibility().SetPublic();
1760   implicitlib.sources().push_back(SourceFile("//foo/implicit.cpp"));
1761   implicitlib.source_types_used().Set(SourceFile::SOURCE_CPP);
1762   implicitlib.SetToolchain(setup.toolchain());
1763   ASSERT_TRUE(implicitlib.OnResolved(&err));
1764 
1765   Target sharedlib(setup.settings(), Label(SourceDir("//foo/"), "shared"));
1766   sharedlib.set_output_type(Target::SHARED_LIBRARY);
1767   sharedlib.visibility().SetPublic();
1768   sharedlib.sources().push_back(SourceFile("//foo/shared.cpp"));
1769   sharedlib.source_types_used().Set(SourceFile::SOURCE_CPP);
1770   sharedlib.SetToolchain(setup.toolchain());
1771   sharedlib.public_deps().push_back(LabelTargetPair(&implicitlib));
1772   ASSERT_TRUE(sharedlib.OnResolved(&err));
1773 
1774   Target rlib(setup.settings(), Label(SourceDir("//bar/"), "mylib"));
1775   rlib.set_output_type(Target::RUST_LIBRARY);
1776   rlib.visibility().SetPublic();
1777   SourceFile barlib("//bar/lib.rs");
1778   rlib.sources().push_back(SourceFile("//bar/mylib.rs"));
1779   rlib.sources().push_back(barlib);
1780   rlib.source_types_used().Set(SourceFile::SOURCE_RS);
1781   rlib.rust_values().set_crate_root(barlib);
1782   rlib.rust_values().crate_name() = "mylib";
1783   rlib.SetToolchain(setup.toolchain());
1784   rlib.private_deps().push_back(LabelTargetPair(&sharedlib));
1785   ASSERT_TRUE(rlib.OnResolved(&err));
1786 
1787   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
1788   target.set_output_type(Target::EXECUTABLE);
1789   target.visibility().SetPublic();
1790   SourceFile main("//foo/main.rs");
1791   target.sources().push_back(main);
1792   target.source_types_used().Set(SourceFile::SOURCE_RS);
1793   target.rust_values().set_crate_root(main);
1794   target.rust_values().crate_name() = "foo_bar";
1795   target.private_deps().push_back(LabelTargetPair(&rlib));
1796   target.SetToolchain(setup.toolchain());
1797   ASSERT_TRUE(target.OnResolved(&err));
1798 
1799   {
1800     std::ostringstream out;
1801     NinjaRustBinaryTargetWriter writer(&target, out);
1802     writer.Run();
1803 
1804     const char expected[] =
1805         "crate_name = foo_bar\n"
1806         "crate_type = bin\n"
1807         "output_extension = \n"
1808         "output_dir = \n"
1809         "rustflags =\n"
1810         "rustenv =\n"
1811         "root_out_dir = .\n"
1812         "target_gen_dir = gen/foo\n"
1813         "target_out_dir = obj/foo\n"
1814         "target_output_name = bar\n"
1815         "\n"
1816         "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/main.rs "
1817         "obj/bar/libmylib.rlib ./libshared.so ./libimplicit.so\n"
1818         "  source_file_part = main.rs\n"
1819         "  source_name_part = main\n"
1820         "  externs = --extern mylib=obj/bar/libmylib.rlib\n"
1821         "  rustdeps = -Ldependency=obj/bar -Lnative=. -Clink-arg=-Bdynamic "
1822         "-Clink-arg=./libshared.so -Clink-arg=./libimplicit.so\n"
1823         "  ldflags =\n"
1824         "  sources = ../../foo/main.rs\n";
1825     std::string out_str = out.str();
1826     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1827   }
1828 }
1829 
TEST_F(NinjaRustBinaryTargetWriterTest,TransitiveRustDepsThroughSourceSet)1830 TEST_F(NinjaRustBinaryTargetWriterTest, TransitiveRustDepsThroughSourceSet) {
1831   Err err;
1832   TestWithScope setup;
1833 
1834   Target rlib_pub(setup.settings(),
1835                   Label(SourceDir("//public/"), "behind_sourceset_public"));
1836   rlib_pub.set_output_type(Target::RUST_LIBRARY);
1837   rlib_pub.visibility().SetPublic();
1838   SourceFile rlib_pub_root("//public/lib.rs");
1839   rlib_pub.sources().push_back(
1840       SourceFile("//public/behind_sourceset_public.rs"));
1841   rlib_pub.sources().push_back(rlib_pub_root);
1842   rlib_pub.source_types_used().Set(SourceFile::SOURCE_RS);
1843   rlib_pub.rust_values().set_crate_root(rlib_pub_root);
1844   rlib_pub.rust_values().crate_name() = "behind_sourceset_public";
1845   rlib_pub.SetToolchain(setup.toolchain());
1846   ASSERT_TRUE(rlib_pub.OnResolved(&err));
1847 
1848   Target rlib_priv(setup.settings(),
1849                    Label(SourceDir("//private/"), "behind_sourceset_private"));
1850   rlib_priv.set_output_type(Target::RUST_LIBRARY);
1851   rlib_priv.visibility().SetPublic();
1852   SourceFile rlib_priv_root("//private/lib.rs");
1853   rlib_priv.sources().push_back(
1854       SourceFile("//private/behind_sourceset_private.rs"));
1855   rlib_priv.sources().push_back(rlib_priv_root);
1856   rlib_priv.source_types_used().Set(SourceFile::SOURCE_RS);
1857   rlib_priv.rust_values().set_crate_root(rlib_priv_root);
1858   rlib_priv.rust_values().crate_name() = "behind_sourceset_private";
1859   rlib_priv.SetToolchain(setup.toolchain());
1860   ASSERT_TRUE(rlib_priv.OnResolved(&err));
1861 
1862   Target sset(setup.settings(), Label(SourceDir("//sset/"), "bar"));
1863   sset.set_output_type(Target::SOURCE_SET);
1864   sset.visibility().SetPublic();
1865   sset.sources().push_back(SourceFile("//sset/input1.cc"));
1866   sset.source_types_used().Set(SourceFile::SOURCE_CPP);
1867   sset.SetToolchain(setup.toolchain());
1868   sset.public_deps().push_back(LabelTargetPair(&rlib_pub));
1869   sset.private_deps().push_back(LabelTargetPair(&rlib_priv));
1870   ASSERT_TRUE(sset.OnResolved(&err));
1871 
1872   Target target(setup.settings(), Label(SourceDir("//linked/"), "exe"));
1873   target.set_output_type(Target::EXECUTABLE);
1874   target.visibility().SetPublic();
1875   SourceFile main("//linked/exe.rs");
1876   target.sources().push_back(main);
1877   target.source_types_used().Set(SourceFile::SOURCE_RS);
1878   target.rust_values().set_crate_root(main);
1879   target.rust_values().crate_name() = "exe";
1880   target.private_deps().push_back(LabelTargetPair(&sset));
1881   target.SetToolchain(setup.toolchain());
1882   ASSERT_TRUE(target.OnResolved(&err));
1883 
1884   {
1885     std::ostringstream out;
1886     NinjaRustBinaryTargetWriter writer(&target, out);
1887     writer.Run();
1888 
1889     const char expected[] =
1890         "crate_name = exe\n"
1891         "crate_type = bin\n"
1892         "output_extension = \n"
1893         "output_dir = \n"
1894         "rustflags =\n"
1895         "rustenv =\n"
1896         "root_out_dir = .\n"
1897         "target_gen_dir = gen/linked\n"
1898         "target_out_dir = obj/linked\n"
1899         "target_output_name = exe\n"
1900         "\n"
1901         "build ./exe: rust_bin ../../linked/exe.rs | ../../linked/exe.rs "
1902         "obj/sset/bar.input1.o obj/public/libbehind_sourceset_public.rlib "
1903         "obj/private/libbehind_sourceset_private.rlib || obj/sset/bar.stamp\n"
1904         "  source_file_part = exe.rs\n"
1905         "  source_name_part = exe\n"
1906         "  externs = --extern "
1907         "behind_sourceset_public=obj/public/libbehind_sourceset_public.rlib\n"
1908         "  rustdeps = -Ldependency=obj/public -Ldependency=obj/private "
1909         "-Lnative=obj/sset -Clink-arg=-Bdynamic "
1910         "-Clink-arg=obj/sset/bar.input1.o\n"
1911         "  ldflags =\n"
1912         "  sources = ../../linked/exe.rs\n";
1913     std::string out_str = out.str();
1914     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1915   }
1916 }
1917 
TEST_F(NinjaRustBinaryTargetWriterTest,Pool)1918 TEST_F(NinjaRustBinaryTargetWriterTest, Pool) {
1919   Err err;
1920   TestWithScope setup;
1921 
1922   Pool pool(setup.settings(),
1923             Label(SourceDir("//foo/"), "pool", setup.toolchain()->label().dir(),
1924                   setup.toolchain()->label().name()));
1925   pool.set_depth(42);
1926 
1927   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
1928   SourceFile main("//foo/source.rs");
1929   target.sources().push_back(main);
1930   target.source_types_used().Set(SourceFile::SOURCE_RS);
1931   target.rust_values().set_crate_root(main);
1932   target.rust_values().crate_name() = "bar";
1933   target.set_output_type(Target::EXECUTABLE);
1934   target.set_pool(LabelPtrPair<Pool>(&pool));
1935   target.visibility().SetPublic();
1936   target.SetToolchain(setup.toolchain());
1937   ASSERT_TRUE(target.OnResolved(&err));
1938 
1939   std::ostringstream out;
1940   NinjaBinaryTargetWriter writer(&target, out);
1941   writer.Run();
1942 
1943   const char expected[] =
1944       "crate_name = bar\n"
1945       "crate_type = bin\n"
1946       "output_extension = \n"
1947       "output_dir = \n"
1948       "rustflags =\n"
1949       "rustenv =\n"
1950       "root_out_dir = .\n"
1951       "target_gen_dir = gen/foo\n"
1952       "target_out_dir = obj/foo\n"
1953       "target_output_name = bar\n"
1954       "\n"
1955       "build ./bar: rust_bin ../../foo/source.rs | ../../foo/source.rs\n"
1956       "  source_file_part = source.rs\n"
1957       "  source_name_part = source\n"
1958       "  externs =\n"
1959       "  rustdeps =\n"
1960       "  ldflags =\n"
1961       "  sources = ../../foo/source.rs\n"
1962       "  pool = foo_pool\n";
1963   std::string out_str = out.str();
1964   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
1965 }
1966