]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/test.rs
0d430c300368e2eb4da2b9f4b2b0872a0eb40684
[rust.git] / src / bootstrap / test.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Implementation of the test-related targets of the build system.
12 //!
13 //! This file implements the various regression test suites that we execute on
14 //! our CI.
15
16 use std::env;
17 use std::ffi::OsString;
18 use std::iter;
19 use std::fmt;
20 use std::fs::{self, File};
21 use std::path::{PathBuf, Path};
22 use std::process::Command;
23 use std::io::Read;
24
25 use build_helper::{self, output};
26
27 use builder::{Kind, RunConfig, ShouldRun, Builder, Compiler, Step};
28 use Crate as CargoCrate;
29 use cache::{INTERNER, Interned};
30 use compile;
31 use dist;
32 use native;
33 use tool::{self, Tool};
34 use util::{self, dylib_path, dylib_path_var};
35 use {Mode, DocTestsOption};
36 use toolstate::ToolState;
37
38 const ADB_TEST_DIR: &str = "/data/tmp/work";
39
40 /// The two modes of the test runner; tests or benchmarks.
41 #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
42 pub enum TestKind {
43     /// Run `cargo test`
44     Test,
45     /// Run `cargo bench`
46     Bench,
47 }
48
49 impl TestKind {
50     // Return the cargo subcommand for this test kind
51     fn subcommand(self) -> &'static str {
52         match self {
53             TestKind::Test => "test",
54             TestKind::Bench => "bench",
55         }
56     }
57 }
58
59 impl fmt::Display for TestKind {
60     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61         f.write_str(match *self {
62             TestKind::Test => "Testing",
63             TestKind::Bench => "Benchmarking",
64         })
65     }
66 }
67
68 fn try_run(builder: &Builder, cmd: &mut Command) -> bool {
69     if !builder.fail_fast {
70         if !builder.try_run(cmd) {
71             let mut failures = builder.delayed_failures.borrow_mut();
72             failures.push(format!("{:?}", cmd));
73             return false;
74         }
75     } else {
76         builder.run(cmd);
77     }
78     true
79 }
80
81 fn try_run_quiet(builder: &Builder, cmd: &mut Command) -> bool {
82     if !builder.fail_fast {
83         if !builder.try_run_quiet(cmd) {
84             let mut failures = builder.delayed_failures.borrow_mut();
85             failures.push(format!("{:?}", cmd));
86             return false;
87         }
88     } else {
89         builder.run_quiet(cmd);
90     }
91     true
92 }
93
94 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
95 pub struct Linkcheck {
96     host: Interned<String>,
97 }
98
99 impl Step for Linkcheck {
100     type Output = ();
101     const ONLY_HOSTS: bool = true;
102     const DEFAULT: bool = true;
103
104     /// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.
105     ///
106     /// This tool in `src/tools` will verify the validity of all our links in the
107     /// documentation to ensure we don't have a bunch of dead ones.
108     fn run(self, builder: &Builder) {
109         let host = self.host;
110
111         builder.info(&format!("Linkcheck ({})", host));
112
113         builder.default_doc(None);
114
115         let _time = util::timeit(&builder);
116         try_run(builder, builder.tool_cmd(Tool::Linkchecker)
117                               .arg(builder.out.join(host).join("doc")));
118     }
119
120     fn should_run(run: ShouldRun) -> ShouldRun {
121         let builder = run.builder;
122         run.path("src/tools/linkchecker").default_condition(builder.config.docs)
123     }
124
125     fn make_run(run: RunConfig) {
126         run.builder.ensure(Linkcheck { host: run.target });
127     }
128 }
129
130 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
131 pub struct Cargotest {
132     stage: u32,
133     host: Interned<String>,
134 }
135
136 impl Step for Cargotest {
137     type Output = ();
138     const ONLY_HOSTS: bool = true;
139
140     fn should_run(run: ShouldRun) -> ShouldRun {
141         run.path("src/tools/cargotest")
142     }
143
144     fn make_run(run: RunConfig) {
145         run.builder.ensure(Cargotest {
146             stage: run.builder.top_stage,
147             host: run.target,
148         });
149     }
150
151     /// Runs the `cargotest` tool as compiled in `stage` by the `host` compiler.
152     ///
153     /// This tool in `src/tools` will check out a few Rust projects and run `cargo
154     /// test` to ensure that we don't regress the test suites there.
155     fn run(self, builder: &Builder) {
156         let compiler = builder.compiler(self.stage, self.host);
157         builder.ensure(compile::Rustc { compiler, target: compiler.host });
158
159         // Note that this is a short, cryptic, and not scoped directory name. This
160         // is currently to minimize the length of path on Windows where we otherwise
161         // quickly run into path name limit constraints.
162         let out_dir = builder.out.join("ct");
163         t!(fs::create_dir_all(&out_dir));
164
165         let _time = util::timeit(&builder);
166         let mut cmd = builder.tool_cmd(Tool::CargoTest);
167         try_run(builder, cmd.arg(&builder.initial_cargo)
168                           .arg(&out_dir)
169                           .env("RUSTC", builder.rustc(compiler))
170                           .env("RUSTDOC", builder.rustdoc(compiler.host)));
171     }
172 }
173
174 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
175 pub struct Cargo {
176     stage: u32,
177     host: Interned<String>,
178 }
179
180 impl Step for Cargo {
181     type Output = ();
182     const ONLY_HOSTS: bool = true;
183
184     fn should_run(run: ShouldRun) -> ShouldRun {
185         run.path("src/tools/cargo")
186     }
187
188     fn make_run(run: RunConfig) {
189         run.builder.ensure(Cargo {
190             stage: run.builder.top_stage,
191             host: run.target,
192         });
193     }
194
195     /// Runs `cargo test` for `cargo` packaged with Rust.
196     fn run(self, builder: &Builder) {
197         let compiler = builder.compiler(self.stage, self.host);
198
199         builder.ensure(tool::Cargo { compiler, target: self.host });
200         let mut cargo = builder.cargo(compiler, Mode::Tool, self.host, "test");
201         cargo.arg("--manifest-path").arg(builder.src.join("src/tools/cargo/Cargo.toml"));
202         if !builder.fail_fast {
203             cargo.arg("--no-fail-fast");
204         }
205
206         // Don't build tests dynamically, just a pain to work with
207         cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
208
209         // Don't run cross-compile tests, we may not have cross-compiled libstd libs
210         // available.
211         cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
212
213         try_run(builder, cargo.env("PATH", &path_for_cargo(builder, compiler)));
214     }
215 }
216
217 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
218 pub struct Rls {
219     stage: u32,
220     host: Interned<String>,
221 }
222
223 impl Step for Rls {
224     type Output = ();
225     const ONLY_HOSTS: bool = true;
226
227     fn should_run(run: ShouldRun) -> ShouldRun {
228         run.path("src/tools/rls")
229     }
230
231     fn make_run(run: RunConfig) {
232         run.builder.ensure(Rls {
233             stage: run.builder.top_stage,
234             host: run.target,
235         });
236     }
237
238     /// Runs `cargo test` for the rls.
239     fn run(self, builder: &Builder) {
240         let stage = self.stage;
241         let host = self.host;
242         let compiler = builder.compiler(stage, host);
243
244         let build_result = builder.ensure(tool::Rls {
245             compiler,
246             target: self.host,
247             extra_features: Vec::new(),
248         });
249         if build_result.is_none() {
250             eprintln!("failed to test rls: could not build");
251             return;
252         }
253
254         let mut cargo = tool::prepare_tool_cargo(builder,
255                                                  compiler,
256                                                  host,
257                                                  "test",
258                                                  "src/tools/rls");
259
260         // Don't build tests dynamically, just a pain to work with
261         cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
262
263         builder.add_rustc_lib_path(compiler, &mut cargo);
264
265         if try_run(builder, &mut cargo) {
266             builder.save_toolstate("rls", ToolState::TestPass);
267         }
268     }
269 }
270
271 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
272 pub struct Rustfmt {
273     stage: u32,
274     host: Interned<String>,
275 }
276
277 impl Step for Rustfmt {
278     type Output = ();
279     const ONLY_HOSTS: bool = true;
280
281     fn should_run(run: ShouldRun) -> ShouldRun {
282         run.path("src/tools/rustfmt")
283     }
284
285     fn make_run(run: RunConfig) {
286         run.builder.ensure(Rustfmt {
287             stage: run.builder.top_stage,
288             host: run.target,
289         });
290     }
291
292     /// Runs `cargo test` for rustfmt.
293     fn run(self, builder: &Builder) {
294         let stage = self.stage;
295         let host = self.host;
296         let compiler = builder.compiler(stage, host);
297
298         let build_result = builder.ensure(tool::Rustfmt {
299             compiler,
300             target: self.host,
301             extra_features: Vec::new(),
302         });
303         if build_result.is_none() {
304             eprintln!("failed to test rustfmt: could not build");
305             return;
306         }
307
308         let mut cargo = tool::prepare_tool_cargo(builder,
309                                                  compiler,
310                                                  host,
311                                                  "test",
312                                                  "src/tools/rustfmt");
313
314         // Don't build tests dynamically, just a pain to work with
315         cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
316
317         builder.add_rustc_lib_path(compiler, &mut cargo);
318
319         if try_run(builder, &mut cargo) {
320             builder.save_toolstate("rustfmt", ToolState::TestPass);
321         }
322     }
323 }
324
325 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
326 pub struct Miri {
327     stage: u32,
328     host: Interned<String>,
329 }
330
331 impl Step for Miri {
332     type Output = ();
333     const ONLY_HOSTS: bool = true;
334     const DEFAULT: bool = true;
335
336     fn should_run(run: ShouldRun) -> ShouldRun {
337         let test_miri = run.builder.config.test_miri;
338         run.path("src/tools/miri").default_condition(test_miri)
339     }
340
341     fn make_run(run: RunConfig) {
342         run.builder.ensure(Miri {
343             stage: run.builder.top_stage,
344             host: run.target,
345         });
346     }
347
348     /// Runs `cargo test` for miri.
349     fn run(self, builder: &Builder) {
350         let stage = self.stage;
351         let host = self.host;
352         let compiler = builder.compiler(stage, host);
353
354         let miri = builder.ensure(tool::Miri {
355             compiler,
356             target: self.host,
357             extra_features: Vec::new(),
358         });
359         if let Some(miri) = miri {
360             let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
361             cargo.arg("--manifest-path").arg(builder.src.join("src/tools/miri/Cargo.toml"));
362
363             // Don't build tests dynamically, just a pain to work with
364             cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
365             // miri tests need to know about the stage sysroot
366             cargo.env("MIRI_SYSROOT", builder.sysroot(compiler));
367             cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
368             cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
369             cargo.env("MIRI_PATH", miri);
370
371             builder.add_rustc_lib_path(compiler, &mut cargo);
372
373             if try_run(builder, &mut cargo) {
374                 builder.save_toolstate("miri", ToolState::TestPass);
375             }
376         } else {
377             eprintln!("failed to test miri: could not build");
378         }
379     }
380 }
381
382 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
383 pub struct Clippy {
384     stage: u32,
385     host: Interned<String>,
386 }
387
388 impl Step for Clippy {
389     type Output = ();
390     const ONLY_HOSTS: bool = true;
391     const DEFAULT: bool = false;
392
393     fn should_run(run: ShouldRun) -> ShouldRun {
394         run.path("src/tools/clippy")
395     }
396
397     fn make_run(run: RunConfig) {
398         run.builder.ensure(Clippy {
399             stage: run.builder.top_stage,
400             host: run.target,
401         });
402     }
403
404     /// Runs `cargo test` for clippy.
405     fn run(self, builder: &Builder) {
406         let stage = self.stage;
407         let host = self.host;
408         let compiler = builder.compiler(stage, host);
409
410         let clippy = builder.ensure(tool::Clippy {
411             compiler,
412             target: self.host,
413             extra_features: Vec::new(),
414         });
415         if let Some(clippy) = clippy {
416             let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
417             cargo.arg("--manifest-path").arg(builder.src.join("src/tools/clippy/Cargo.toml"));
418
419             // Don't build tests dynamically, just a pain to work with
420             cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
421             // clippy tests need to know about the stage sysroot
422             cargo.env("SYSROOT", builder.sysroot(compiler));
423             cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
424             cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
425             let host_libs = builder.stage_out(compiler, Mode::Tool).join(builder.cargo_dir());
426             cargo.env("HOST_LIBS", host_libs);
427             // clippy tests need to find the driver
428             cargo.env("CLIPPY_DRIVER_PATH", clippy);
429
430             builder.add_rustc_lib_path(compiler, &mut cargo);
431
432             if try_run(builder, &mut cargo) {
433                 builder.save_toolstate("clippy-driver", ToolState::TestPass);
434             }
435         } else {
436             eprintln!("failed to test clippy: could not build");
437         }
438     }
439 }
440
441 fn path_for_cargo(builder: &Builder, compiler: Compiler) -> OsString {
442     // Configure PATH to find the right rustc. NB. we have to use PATH
443     // and not RUSTC because the Cargo test suite has tests that will
444     // fail if rustc is not spelled `rustc`.
445     let path = builder.sysroot(compiler).join("bin");
446     let old_path = env::var_os("PATH").unwrap_or_default();
447     env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("")
448 }
449
450 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
451 pub struct RustdocTheme {
452     pub compiler: Compiler,
453 }
454
455 impl Step for RustdocTheme {
456     type Output = ();
457     const DEFAULT: bool = true;
458     const ONLY_HOSTS: bool = true;
459
460     fn should_run(run: ShouldRun) -> ShouldRun {
461         run.path("src/tools/rustdoc-themes")
462     }
463
464     fn make_run(run: RunConfig) {
465         let compiler = run.builder.compiler(run.builder.top_stage, run.host);
466
467         run.builder.ensure(RustdocTheme {
468             compiler: compiler,
469         });
470     }
471
472     fn run(self, builder: &Builder) {
473         let rustdoc = builder.out.join("bootstrap/debug/rustdoc");
474         let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
475         cmd.arg(rustdoc.to_str().unwrap())
476            .arg(builder.src.join("src/librustdoc/html/static/themes").to_str().unwrap())
477            .env("RUSTC_STAGE", self.compiler.stage.to_string())
478            .env("RUSTC_SYSROOT", builder.sysroot(self.compiler))
479            .env("RUSTDOC_LIBDIR", builder.sysroot_libdir(self.compiler, self.compiler.host))
480            .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
481            .env("RUSTDOC_REAL", builder.rustdoc(self.compiler.host))
482            .env("RUSTDOC_CRATE_VERSION", builder.rust_version())
483            .env("RUSTC_BOOTSTRAP", "1");
484         if let Some(linker) = builder.linker(self.compiler.host) {
485             cmd.env("RUSTC_TARGET_LINKER", linker);
486         }
487         try_run(builder, &mut cmd);
488     }
489 }
490
491 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
492 pub struct RustdocJS {
493     pub host: Interned<String>,
494     pub target: Interned<String>,
495 }
496
497 impl Step for RustdocJS {
498     type Output = ();
499     const DEFAULT: bool = true;
500     const ONLY_HOSTS: bool = true;
501
502     fn should_run(run: ShouldRun) -> ShouldRun {
503         run.path("src/test/rustdoc-js")
504     }
505
506     fn make_run(run: RunConfig) {
507         run.builder.ensure(RustdocJS {
508             host: run.host,
509             target: run.target,
510         });
511     }
512
513     fn run(self, builder: &Builder) {
514         if let Some(ref nodejs) = builder.config.nodejs {
515             let mut command = Command::new(nodejs);
516             command.args(&["src/tools/rustdoc-js/tester.js", &*self.host]);
517             builder.ensure(::doc::Std {
518                 target: self.target,
519                 stage: builder.top_stage,
520             });
521             builder.run(&mut command);
522         } else {
523             builder.info(&format!("No nodejs found, skipping \"src/test/rustdoc-js\" tests"));
524         }
525     }
526 }
527
528 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
529 pub struct RustdocUi {
530     pub host: Interned<String>,
531     pub target: Interned<String>,
532     pub compiler: Compiler,
533 }
534
535 impl Step for RustdocUi {
536     type Output = ();
537     const DEFAULT: bool = true;
538     const ONLY_HOSTS: bool = true;
539
540     fn should_run(run: ShouldRun) -> ShouldRun {
541         run.path("src/test/rustdoc-ui")
542     }
543
544     fn make_run(run: RunConfig) {
545         let compiler = run.builder.compiler(run.builder.top_stage, run.host);
546         run.builder.ensure(RustdocUi {
547             host: run.host,
548             target: run.target,
549             compiler,
550         });
551     }
552
553     fn run(self, builder: &Builder) {
554         builder.ensure(Compiletest {
555             compiler: self.compiler,
556             target: self.target,
557             mode: "ui",
558             suite: "rustdoc-ui",
559             compare_mode: None,
560         })
561     }
562 }
563
564 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
565 pub struct Tidy;
566
567 impl Step for Tidy {
568     type Output = ();
569     const DEFAULT: bool = true;
570     const ONLY_HOSTS: bool = true;
571
572     /// Runs the `tidy` tool.
573     ///
574     /// This tool in `src/tools` checks up on various bits and pieces of style and
575     /// otherwise just implements a few lint-like checks that are specific to the
576     /// compiler itself.
577     fn run(self, builder: &Builder) {
578         let mut cmd = builder.tool_cmd(Tool::Tidy);
579         cmd.arg(builder.src.join("src"));
580         cmd.arg(&builder.initial_cargo);
581         if !builder.config.vendor {
582             cmd.arg("--no-vendor");
583         }
584         if builder.config.quiet_tests {
585             cmd.arg("--quiet");
586         }
587
588         let _folder = builder.fold_output(|| "tidy");
589         builder.info(&format!("tidy check"));
590         try_run(builder, &mut cmd);
591     }
592
593     fn should_run(run: ShouldRun) -> ShouldRun {
594         run.path("src/tools/tidy")
595     }
596
597     fn make_run(run: RunConfig) {
598         run.builder.ensure(Tidy);
599     }
600 }
601
602 fn testdir(builder: &Builder, host: Interned<String>) -> PathBuf {
603     builder.out.join(host).join("test")
604 }
605
606 macro_rules! default_test {
607     ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => {
608         test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: false });
609     }
610 }
611
612 macro_rules! default_test_with_compare_mode {
613     ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr,
614                    compare_mode: $compare_mode:expr }) => {
615         test_with_compare_mode!($name { path: $path, mode: $mode, suite: $suite, default: true,
616                                         host: false, compare_mode: $compare_mode });
617     }
618 }
619
620 macro_rules! host_test {
621     ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => {
622         test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: true });
623     }
624 }
625
626 macro_rules! test {
627     ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
628                    host: $host:expr }) => {
629         test_definitions!($name { path: $path, mode: $mode, suite: $suite, default: $default,
630                                   host: $host, compare_mode: None });
631     }
632 }
633
634 macro_rules! test_with_compare_mode {
635     ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
636                    host: $host:expr, compare_mode: $compare_mode:expr }) => {
637         test_definitions!($name { path: $path, mode: $mode, suite: $suite, default: $default,
638                                   host: $host, compare_mode: Some($compare_mode) });
639     }
640 }
641
642 macro_rules! test_definitions {
643     ($name:ident {
644         path: $path:expr,
645         mode: $mode:expr,
646         suite: $suite:expr,
647         default: $default:expr,
648         host: $host:expr,
649         compare_mode: $compare_mode:expr
650     }) => {
651         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
652         pub struct $name {
653             pub compiler: Compiler,
654             pub target: Interned<String>,
655         }
656
657         impl Step for $name {
658             type Output = ();
659             const DEFAULT: bool = $default;
660             const ONLY_HOSTS: bool = $host;
661
662             fn should_run(run: ShouldRun) -> ShouldRun {
663                 run.path($path)
664             }
665
666             fn make_run(run: RunConfig) {
667                 let compiler = run.builder.compiler(run.builder.top_stage, run.host);
668
669                 run.builder.ensure($name {
670                     compiler,
671                     target: run.target,
672                 });
673             }
674
675             fn run(self, builder: &Builder) {
676                 builder.ensure(Compiletest {
677                     compiler: self.compiler,
678                     target: self.target,
679                     mode: $mode,
680                     suite: $suite,
681                     compare_mode: $compare_mode,
682                 })
683             }
684         }
685     }
686 }
687
688 default_test_with_compare_mode!(Ui {
689     path: "src/test/ui",
690     mode: "ui",
691     suite: "ui",
692     compare_mode: "nll"
693 });
694
695 default_test!(RunPass {
696     path: "src/test/run-pass",
697     mode: "run-pass",
698     suite: "run-pass"
699 });
700
701 default_test!(CompileFail {
702     path: "src/test/compile-fail",
703     mode: "compile-fail",
704     suite: "compile-fail"
705 });
706
707 default_test!(ParseFail {
708     path: "src/test/parse-fail",
709     mode: "parse-fail",
710     suite: "parse-fail"
711 });
712
713 default_test!(RunFail {
714     path: "src/test/run-fail",
715     mode: "run-fail",
716     suite: "run-fail"
717 });
718
719 default_test!(RunPassValgrind {
720     path: "src/test/run-pass-valgrind",
721     mode: "run-pass-valgrind",
722     suite: "run-pass-valgrind"
723 });
724
725 default_test!(MirOpt {
726     path: "src/test/mir-opt",
727     mode: "mir-opt",
728     suite: "mir-opt"
729 });
730
731 default_test!(Codegen {
732     path: "src/test/codegen",
733     mode: "codegen",
734     suite: "codegen"
735 });
736
737 default_test!(CodegenUnits {
738     path: "src/test/codegen-units",
739     mode: "codegen-units",
740     suite: "codegen-units"
741 });
742
743 default_test!(Incremental {
744     path: "src/test/incremental",
745     mode: "incremental",
746     suite: "incremental"
747 });
748
749 default_test!(Debuginfo {
750     path: "src/test/debuginfo",
751     // What this runs varies depending on the native platform being apple
752     mode: "debuginfo-XXX",
753     suite: "debuginfo"
754 });
755
756 host_test!(UiFullDeps {
757     path: "src/test/ui-fulldeps",
758     mode: "ui",
759     suite: "ui-fulldeps"
760 });
761
762 host_test!(RunPassFullDeps {
763     path: "src/test/run-pass-fulldeps",
764     mode: "run-pass",
765     suite: "run-pass-fulldeps"
766 });
767
768 host_test!(RunFailFullDeps {
769     path: "src/test/run-fail-fulldeps",
770     mode: "run-fail",
771     suite: "run-fail-fulldeps"
772 });
773
774 host_test!(CompileFailFullDeps {
775     path: "src/test/compile-fail-fulldeps",
776     mode: "compile-fail",
777     suite: "compile-fail-fulldeps"
778 });
779
780 host_test!(IncrementalFullDeps {
781     path: "src/test/incremental-fulldeps",
782     mode: "incremental",
783     suite: "incremental-fulldeps"
784 });
785
786 host_test!(Rustdoc {
787     path: "src/test/rustdoc",
788     mode: "rustdoc",
789     suite: "rustdoc"
790 });
791
792 test!(Pretty {
793     path: "src/test/pretty",
794     mode: "pretty",
795     suite: "pretty",
796     default: false,
797     host: true
798 });
799 test!(RunPassPretty {
800     path: "src/test/run-pass/pretty",
801     mode: "pretty",
802     suite: "run-pass",
803     default: false,
804     host: true
805 });
806 test!(RunFailPretty {
807     path: "src/test/run-fail/pretty",
808     mode: "pretty",
809     suite: "run-fail",
810     default: false,
811     host: true
812 });
813 test!(RunPassValgrindPretty {
814     path: "src/test/run-pass-valgrind/pretty",
815     mode: "pretty",
816     suite: "run-pass-valgrind",
817     default: false,
818     host: true
819 });
820 test!(RunPassFullDepsPretty {
821     path: "src/test/run-pass-fulldeps/pretty",
822     mode: "pretty",
823     suite: "run-pass-fulldeps",
824     default: false,
825     host: true
826 });
827 test!(RunFailFullDepsPretty {
828     path: "src/test/run-fail-fulldeps/pretty",
829     mode: "pretty",
830     suite: "run-fail-fulldeps",
831     default: false,
832     host: true
833 });
834
835 default_test!(RunMake {
836     path: "src/test/run-make",
837     mode: "run-make",
838     suite: "run-make"
839 });
840
841 host_test!(RunMakeFullDeps {
842     path: "src/test/run-make-fulldeps",
843     mode: "run-make",
844     suite: "run-make-fulldeps"
845 });
846
847 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
848 struct Compiletest {
849     compiler: Compiler,
850     target: Interned<String>,
851     mode: &'static str,
852     suite: &'static str,
853     compare_mode: Option<&'static str>,
854 }
855
856 impl Step for Compiletest {
857     type Output = ();
858
859     fn should_run(run: ShouldRun) -> ShouldRun {
860         run.never()
861     }
862
863     /// Executes the `compiletest` tool to run a suite of tests.
864     ///
865     /// Compiles all tests with `compiler` for `target` with the specified
866     /// compiletest `mode` and `suite` arguments. For example `mode` can be
867     /// "run-pass" or `suite` can be something like `debuginfo`.
868     fn run(self, builder: &Builder) {
869         let compiler = self.compiler;
870         let target = self.target;
871         let mode = self.mode;
872         let suite = self.suite;
873         let compare_mode = self.compare_mode;
874
875         // Skip codegen tests if they aren't enabled in configuration.
876         if !builder.config.codegen_tests && suite == "codegen" {
877             return;
878         }
879
880         if suite == "debuginfo" {
881             // Skip debuginfo tests on MSVC
882             if builder.config.build.contains("msvc") {
883                 return;
884             }
885
886             if mode == "debuginfo-XXX" {
887                 return if builder.config.build.contains("apple") {
888                     builder.ensure(Compiletest {
889                         mode: "debuginfo-lldb",
890                         ..self
891                     });
892                 } else {
893                     builder.ensure(Compiletest {
894                         mode: "debuginfo-gdb",
895                         ..self
896                     });
897                 };
898             }
899
900             builder.ensure(dist::DebuggerScripts {
901                 sysroot: builder.sysroot(compiler),
902                 host: target
903             });
904         }
905
906         if suite.ends_with("fulldeps") ||
907             // FIXME: Does pretty need librustc compiled? Note that there are
908             // fulldeps test suites with mode = pretty as well.
909             mode == "pretty" ||
910             mode == "rustdoc" {
911             builder.ensure(compile::Rustc { compiler, target });
912         }
913
914         builder.ensure(compile::Test { compiler, target });
915         builder.ensure(native::TestHelpers { target });
916         builder.ensure(RemoteCopyLibs { compiler, target });
917
918         let mut cmd = builder.tool_cmd(Tool::Compiletest);
919
920         // compiletest currently has... a lot of arguments, so let's just pass all
921         // of them!
922
923         cmd.arg("--compile-lib-path").arg(builder.rustc_libdir(compiler));
924         cmd.arg("--run-lib-path").arg(builder.sysroot_libdir(compiler, target));
925         cmd.arg("--rustc-path").arg(builder.rustc(compiler));
926
927         let is_rustdoc_ui = suite.ends_with("rustdoc-ui");
928
929         // Avoid depending on rustdoc when we don't need it.
930         if mode == "rustdoc" ||
931            (mode == "run-make" && suite.ends_with("fulldeps")) ||
932            (mode == "ui" && is_rustdoc_ui) {
933             cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler.host));
934         }
935
936         cmd.arg("--src-base").arg(builder.src.join("src/test").join(suite));
937         cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite));
938         cmd.arg("--stage-id").arg(format!("stage{}-{}", compiler.stage, target));
939         cmd.arg("--mode").arg(mode);
940         cmd.arg("--target").arg(target);
941         cmd.arg("--host").arg(&*compiler.host);
942         cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build));
943
944         if let Some(ref nodejs) = builder.config.nodejs {
945             cmd.arg("--nodejs").arg(nodejs);
946         }
947
948         let mut flags = if is_rustdoc_ui {
949             Vec::new()
950         } else {
951             vec!["-Crpath".to_string()]
952         };
953         if !is_rustdoc_ui {
954             if builder.config.rust_optimize_tests {
955                 flags.push("-O".to_string());
956             }
957             if builder.config.rust_debuginfo_tests {
958                 flags.push("-g".to_string());
959             }
960         }
961         flags.push("-Zunstable-options".to_string());
962         flags.push(builder.config.cmd.rustc_args().join(" "));
963
964         if let Some(linker) = builder.linker(target) {
965             cmd.arg("--linker").arg(linker);
966         }
967
968         let hostflags = flags.clone();
969         cmd.arg("--host-rustcflags").arg(hostflags.join(" "));
970
971         let mut targetflags = flags.clone();
972         targetflags.push(format!("-Lnative={}",
973                                  builder.test_helpers_out(target).display()));
974         cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
975
976         cmd.arg("--docck-python").arg(builder.python());
977
978         if builder.config.build.ends_with("apple-darwin") {
979             // Force /usr/bin/python on macOS for LLDB tests because we're loading the
980             // LLDB plugin's compiled module which only works with the system python
981             // (namely not Homebrew-installed python)
982             cmd.arg("--lldb-python").arg("/usr/bin/python");
983         } else {
984             cmd.arg("--lldb-python").arg(builder.python());
985         }
986
987         if let Some(ref gdb) = builder.config.gdb {
988             cmd.arg("--gdb").arg(gdb);
989         }
990         if let Some(ref vers) = builder.lldb_version {
991             cmd.arg("--lldb-version").arg(vers);
992         }
993         if let Some(ref dir) = builder.lldb_python_dir {
994             cmd.arg("--lldb-python-dir").arg(dir);
995         }
996
997         cmd.args(&builder.config.cmd.test_args());
998
999         if builder.is_verbose() {
1000             cmd.arg("--verbose");
1001         }
1002
1003         if builder.config.quiet_tests {
1004             cmd.arg("--quiet");
1005         }
1006
1007         if builder.config.llvm_enabled {
1008             let llvm_config = builder.ensure(native::Llvm {
1009                 target: builder.config.build,
1010                 emscripten: false,
1011             });
1012             if !builder.config.dry_run {
1013                 let llvm_version = output(Command::new(&llvm_config).arg("--version"));
1014                 cmd.arg("--llvm-version").arg(llvm_version);
1015             }
1016             if !builder.is_rust_llvm(target) {
1017                 cmd.arg("--system-llvm");
1018             }
1019
1020             // Only pass correct values for these flags for the `run-make` suite as it
1021             // requires that a C++ compiler was configured which isn't always the case.
1022             if !builder.config.dry_run && suite == "run-make-fulldeps" {
1023                 let llvm_components = output(Command::new(&llvm_config).arg("--components"));
1024                 let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags"));
1025                 cmd.arg("--cc").arg(builder.cc(target))
1026                 .arg("--cxx").arg(builder.cxx(target).unwrap())
1027                 .arg("--cflags").arg(builder.cflags(target).join(" "))
1028                 .arg("--llvm-components").arg(llvm_components.trim())
1029                 .arg("--llvm-cxxflags").arg(llvm_cxxflags.trim());
1030                 if let Some(ar) = builder.ar(target) {
1031                     cmd.arg("--ar").arg(ar);
1032                 }
1033             }
1034         }
1035         if suite == "run-make-fulldeps" && !builder.config.llvm_enabled {
1036             builder.info(
1037                 &format!("Ignoring run-make test suite as they generally don't work without LLVM"));
1038             return;
1039         }
1040
1041         if suite != "run-make-fulldeps" {
1042             cmd.arg("--cc").arg("")
1043                .arg("--cxx").arg("")
1044                .arg("--cflags").arg("")
1045                .arg("--llvm-components").arg("")
1046                .arg("--llvm-cxxflags").arg("");
1047         }
1048
1049         if builder.remote_tested(target) {
1050             cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient));
1051         }
1052
1053         // Running a C compiler on MSVC requires a few env vars to be set, to be
1054         // sure to set them here.
1055         //
1056         // Note that if we encounter `PATH` we make sure to append to our own `PATH`
1057         // rather than stomp over it.
1058         if target.contains("msvc") {
1059             for &(ref k, ref v) in builder.cc[&target].env() {
1060                 if k != "PATH" {
1061                     cmd.env(k, v);
1062                 }
1063             }
1064         }
1065         cmd.env("RUSTC_BOOTSTRAP", "1");
1066         builder.add_rust_test_threads(&mut cmd);
1067
1068         if builder.config.sanitizers {
1069             cmd.env("SANITIZER_SUPPORT", "1");
1070         }
1071
1072         if builder.config.profiler {
1073             cmd.env("PROFILER_SUPPORT", "1");
1074         }
1075
1076         cmd.env("RUST_TEST_TMPDIR", builder.out.join("tmp"));
1077
1078         cmd.arg("--adb-path").arg("adb");
1079         cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
1080         if target.contains("android") {
1081             // Assume that cc for this target comes from the android sysroot
1082             cmd.arg("--android-cross-path")
1083                .arg(builder.cc(target).parent().unwrap().parent().unwrap());
1084         } else {
1085             cmd.arg("--android-cross-path").arg("");
1086         }
1087
1088         builder.ci_env.force_coloring_in_ci(&mut cmd);
1089
1090         let _folder = builder.fold_output(|| format!("test_{}", suite));
1091         builder.info(&format!("Check compiletest suite={} mode={} ({} -> {})",
1092                  suite, mode, &compiler.host, target));
1093         let _time = util::timeit(&builder);
1094         try_run(builder, &mut cmd);
1095
1096         if let Some(compare_mode) = compare_mode {
1097             cmd.arg("--compare-mode").arg(compare_mode);
1098             let _folder = builder.fold_output(|| format!("test_{}_{}", suite, compare_mode));
1099             builder.info(&format!("Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
1100                                   suite, mode, compare_mode, &compiler.host, target));
1101             let _time = util::timeit(&builder);
1102             try_run(builder, &mut cmd);
1103         }
1104     }
1105 }
1106
1107 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1108 struct DocTest {
1109     compiler: Compiler,
1110     path: &'static str,
1111     name: &'static str,
1112     is_ext_doc: bool,
1113 }
1114
1115 impl Step for DocTest {
1116     type Output = ();
1117     const ONLY_HOSTS: bool = true;
1118
1119     fn should_run(run: ShouldRun) -> ShouldRun {
1120         run.never()
1121     }
1122
1123     /// Run `rustdoc --test` for all documentation in `src/doc`.
1124     ///
1125     /// This will run all tests in our markdown documentation (e.g. the book)
1126     /// located in `src/doc`. The `rustdoc` that's run is the one that sits next to
1127     /// `compiler`.
1128     fn run(self, builder: &Builder) {
1129         let compiler = self.compiler;
1130
1131         builder.ensure(compile::Test { compiler, target: compiler.host });
1132
1133         // Do a breadth-first traversal of the `src/doc` directory and just run
1134         // tests for all files that end in `*.md`
1135         let mut stack = vec![builder.src.join(self.path)];
1136         let _time = util::timeit(&builder);
1137         let _folder = builder.fold_output(|| format!("test_{}", self.name));
1138
1139         let mut files = Vec::new();
1140         while let Some(p) = stack.pop() {
1141             if p.is_dir() {
1142                 stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
1143                 continue
1144             }
1145
1146             if p.extension().and_then(|s| s.to_str()) != Some("md") {
1147                 continue;
1148             }
1149
1150             // The nostarch directory in the book is for no starch, and so isn't
1151             // guaranteed to builder. We don't care if it doesn't build, so skip it.
1152             if p.to_str().map_or(false, |p| p.contains("nostarch")) {
1153                 continue;
1154             }
1155
1156             files.push(p);
1157         }
1158
1159         files.sort();
1160
1161         for file in files {
1162             let test_result = markdown_test(builder, compiler, &file);
1163             if self.is_ext_doc {
1164                 let toolstate = if test_result {
1165                     ToolState::TestPass
1166                 } else {
1167                     ToolState::TestFail
1168                 };
1169                 builder.save_toolstate(self.name, toolstate);
1170             }
1171         }
1172     }
1173 }
1174
1175 macro_rules! test_book {
1176     ($($name:ident, $path:expr, $book_name:expr, default=$default:expr;)+) => {
1177         $(
1178             #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1179             pub struct $name {
1180                 compiler: Compiler,
1181             }
1182
1183             impl Step for $name {
1184                 type Output = ();
1185                 const DEFAULT: bool = $default;
1186                 const ONLY_HOSTS: bool = true;
1187
1188                 fn should_run(run: ShouldRun) -> ShouldRun {
1189                     run.path($path)
1190                 }
1191
1192                 fn make_run(run: RunConfig) {
1193                     run.builder.ensure($name {
1194                         compiler: run.builder.compiler(run.builder.top_stage, run.host),
1195                     });
1196                 }
1197
1198                 fn run(self, builder: &Builder) {
1199                     builder.ensure(DocTest {
1200                         compiler: self.compiler,
1201                         path: $path,
1202                         name: $book_name,
1203                         is_ext_doc: !$default,
1204                     });
1205                 }
1206             }
1207         )+
1208     }
1209 }
1210
1211 test_book!(
1212     Nomicon, "src/doc/nomicon", "nomicon", default=false;
1213     Reference, "src/doc/reference", "reference", default=false;
1214     RustdocBook, "src/doc/rustdoc", "rustdoc", default=true;
1215     RustcBook, "src/doc/rustc", "rustc", default=true;
1216     RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false;
1217     TheBook, "src/doc/book", "book", default=false;
1218     UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
1219 );
1220
1221 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1222 pub struct ErrorIndex {
1223     compiler: Compiler,
1224 }
1225
1226 impl Step for ErrorIndex {
1227     type Output = ();
1228     const DEFAULT: bool = true;
1229     const ONLY_HOSTS: bool = true;
1230
1231     fn should_run(run: ShouldRun) -> ShouldRun {
1232         run.path("src/tools/error_index_generator")
1233     }
1234
1235     fn make_run(run: RunConfig) {
1236         run.builder.ensure(ErrorIndex {
1237             compiler: run.builder.compiler(run.builder.top_stage, run.host),
1238         });
1239     }
1240
1241     /// Run the error index generator tool to execute the tests located in the error
1242     /// index.
1243     ///
1244     /// The `error_index_generator` tool lives in `src/tools` and is used to
1245     /// generate a markdown file from the error indexes of the code base which is
1246     /// then passed to `rustdoc --test`.
1247     fn run(self, builder: &Builder) {
1248         let compiler = self.compiler;
1249
1250         builder.ensure(compile::Std { compiler, target: compiler.host });
1251
1252         let dir = testdir(builder, compiler.host);
1253         t!(fs::create_dir_all(&dir));
1254         let output = dir.join("error-index.md");
1255
1256         let mut tool = builder.tool_cmd(Tool::ErrorIndex);
1257         tool.arg("markdown")
1258             .arg(&output)
1259             .env("CFG_BUILD", &builder.config.build)
1260             .env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir());
1261
1262
1263         let _folder = builder.fold_output(|| "test_error_index");
1264         builder.info(&format!("Testing error-index stage{}", compiler.stage));
1265         let _time = util::timeit(&builder);
1266         builder.run(&mut tool);
1267         markdown_test(builder, compiler, &output);
1268     }
1269 }
1270
1271 fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) -> bool {
1272     match File::open(markdown) {
1273         Ok(mut file) => {
1274             let mut contents = String::new();
1275             t!(file.read_to_string(&mut contents));
1276             if !contents.contains("```") {
1277                 return true;
1278             }
1279         }
1280         Err(_) => {},
1281     }
1282
1283     builder.info(&format!("doc tests for: {}", markdown.display()));
1284     let mut cmd = builder.rustdoc_cmd(compiler.host);
1285     builder.add_rust_test_threads(&mut cmd);
1286     cmd.arg("--test");
1287     cmd.arg(markdown);
1288     cmd.env("RUSTC_BOOTSTRAP", "1");
1289
1290     let test_args = builder.config.cmd.test_args().join(" ");
1291     cmd.arg("--test-args").arg(test_args);
1292
1293     if builder.config.quiet_tests {
1294         try_run_quiet(builder, &mut cmd)
1295     } else {
1296         try_run(builder, &mut cmd)
1297     }
1298 }
1299
1300 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1301 pub struct CrateLibrustc {
1302     compiler: Compiler,
1303     target: Interned<String>,
1304     test_kind: TestKind,
1305     krate: Interned<String>,
1306 }
1307
1308 impl Step for CrateLibrustc {
1309     type Output = ();
1310     const DEFAULT: bool = true;
1311     const ONLY_HOSTS: bool = true;
1312
1313     fn should_run(run: ShouldRun) -> ShouldRun {
1314         run.krate("rustc-main")
1315     }
1316
1317     fn make_run(run: RunConfig) {
1318         let builder = run.builder;
1319         let compiler = builder.compiler(builder.top_stage, run.host);
1320
1321         for krate in builder.in_tree_crates("rustc-main") {
1322             if run.path.ends_with(&krate.path) {
1323                 let test_kind = if builder.kind == Kind::Test {
1324                     TestKind::Test
1325                 } else if builder.kind == Kind::Bench {
1326                     TestKind::Bench
1327                 } else {
1328                     panic!("unexpected builder.kind in crate: {:?}", builder.kind);
1329                 };
1330
1331                 builder.ensure(CrateLibrustc {
1332                     compiler,
1333                     target: run.target,
1334                     test_kind,
1335                     krate: krate.name,
1336                 });
1337             }
1338         }
1339     }
1340
1341     fn run(self, builder: &Builder) {
1342         builder.ensure(Crate {
1343             compiler: self.compiler,
1344             target: self.target,
1345             mode: Mode::Librustc,
1346             test_kind: self.test_kind,
1347             krate: self.krate,
1348         });
1349     }
1350 }
1351
1352 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1353 pub struct CrateNotDefault {
1354     compiler: Compiler,
1355     target: Interned<String>,
1356     test_kind: TestKind,
1357     krate: &'static str,
1358 }
1359
1360 impl Step for CrateNotDefault {
1361     type Output = ();
1362
1363     fn should_run(run: ShouldRun) -> ShouldRun {
1364         run.path("src/liballoc_jemalloc")
1365             .path("src/librustc_asan")
1366             .path("src/librustc_lsan")
1367             .path("src/librustc_msan")
1368             .path("src/librustc_tsan")
1369     }
1370
1371     fn make_run(run: RunConfig) {
1372         let builder = run.builder;
1373         let compiler = builder.compiler(builder.top_stage, run.host);
1374
1375         let test_kind = if builder.kind == Kind::Test {
1376             TestKind::Test
1377         } else if builder.kind == Kind::Bench {
1378             TestKind::Bench
1379         } else {
1380             panic!("unexpected builder.kind in crate: {:?}", builder.kind);
1381         };
1382
1383         builder.ensure(CrateNotDefault {
1384             compiler,
1385             target: run.target,
1386             test_kind,
1387             krate: match run.path {
1388                 _ if run.path.ends_with("src/liballoc_jemalloc") => "alloc_jemalloc",
1389                 _ if run.path.ends_with("src/librustc_asan") => "rustc_asan",
1390                 _ if run.path.ends_with("src/librustc_lsan") => "rustc_lsan",
1391                 _ if run.path.ends_with("src/librustc_msan") => "rustc_msan",
1392                 _ if run.path.ends_with("src/librustc_tsan") => "rustc_tsan",
1393                 _ => panic!("unexpected path {:?}", run.path),
1394             },
1395         });
1396     }
1397
1398     fn run(self, builder: &Builder) {
1399         builder.ensure(Crate {
1400             compiler: self.compiler,
1401             target: self.target,
1402             mode: Mode::Libstd,
1403             test_kind: self.test_kind,
1404             krate: INTERNER.intern_str(self.krate),
1405         });
1406     }
1407 }
1408
1409
1410 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1411 pub struct Crate {
1412     compiler: Compiler,
1413     target: Interned<String>,
1414     mode: Mode,
1415     test_kind: TestKind,
1416     krate: Interned<String>,
1417 }
1418
1419 impl Step for Crate {
1420     type Output = ();
1421     const DEFAULT: bool = true;
1422
1423     fn should_run(mut run: ShouldRun) -> ShouldRun {
1424         let builder = run.builder;
1425         run = run.krate("test");
1426         for krate in run.builder.in_tree_crates("std") {
1427             if krate.is_local(&run.builder) &&
1428                 !krate.name.contains("jemalloc") &&
1429                 !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) &&
1430                 krate.name != "dlmalloc" {
1431                 run = run.path(krate.local_path(&builder).to_str().unwrap());
1432             }
1433         }
1434         run
1435     }
1436
1437     fn make_run(run: RunConfig) {
1438         let builder = run.builder;
1439         let compiler = builder.compiler(builder.top_stage, run.host);
1440
1441         let make = |mode: Mode, krate: &CargoCrate| {
1442             let test_kind = if builder.kind == Kind::Test {
1443                 TestKind::Test
1444             } else if builder.kind == Kind::Bench {
1445                 TestKind::Bench
1446             } else {
1447                 panic!("unexpected builder.kind in crate: {:?}", builder.kind);
1448             };
1449
1450             builder.ensure(Crate {
1451                 compiler,
1452                 target: run.target,
1453                 mode,
1454                 test_kind,
1455                 krate: krate.name,
1456             });
1457         };
1458
1459         for krate in builder.in_tree_crates("std") {
1460             if run.path.ends_with(&krate.local_path(&builder)) {
1461                 make(Mode::Libstd, krate);
1462             }
1463         }
1464         for krate in builder.in_tree_crates("test") {
1465             if run.path.ends_with(&krate.local_path(&builder)) {
1466                 make(Mode::Libtest, krate);
1467             }
1468         }
1469     }
1470
1471     /// Run all unit tests plus documentation tests for a given crate defined
1472     /// by a `Cargo.toml` (single manifest)
1473     ///
1474     /// This is what runs tests for crates like the standard library, compiler, etc.
1475     /// It essentially is the driver for running `cargo test`.
1476     ///
1477     /// Currently this runs all tests for a DAG by passing a bunch of `-p foo`
1478     /// arguments, and those arguments are discovered from `cargo metadata`.
1479     fn run(self, builder: &Builder) {
1480         let compiler = self.compiler;
1481         let target = self.target;
1482         let mode = self.mode;
1483         let test_kind = self.test_kind;
1484         let krate = self.krate;
1485
1486         builder.ensure(compile::Test { compiler, target });
1487         builder.ensure(RemoteCopyLibs { compiler, target });
1488
1489         // If we're not doing a full bootstrap but we're testing a stage2 version of
1490         // libstd, then what we're actually testing is the libstd produced in
1491         // stage1. Reflect that here by updating the compiler that we're working
1492         // with automatically.
1493         let compiler = if builder.force_use_stage1(compiler, target) {
1494             builder.compiler(1, compiler.host)
1495         } else {
1496             compiler.clone()
1497         };
1498
1499         let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand());
1500         match mode {
1501             Mode::Libstd => {
1502                 compile::std_cargo(builder, &compiler, target, &mut cargo);
1503             }
1504             Mode::Libtest => {
1505                 compile::test_cargo(builder, &compiler, target, &mut cargo);
1506             }
1507             Mode::Librustc => {
1508                 builder.ensure(compile::Rustc { compiler, target });
1509                 compile::rustc_cargo(builder, &mut cargo);
1510             }
1511             _ => panic!("can only test libraries"),
1512         };
1513
1514         // Build up the base `cargo test` command.
1515         //
1516         // Pass in some standard flags then iterate over the graph we've discovered
1517         // in `cargo metadata` with the maps above and figure out what `-p`
1518         // arguments need to get passed.
1519         if test_kind.subcommand() == "test" && !builder.fail_fast {
1520             cargo.arg("--no-fail-fast");
1521         }
1522         match builder.doc_tests {
1523             DocTestsOption::Only => {
1524                 cargo.arg("--doc");
1525             }
1526             DocTestsOption::No => {
1527                 cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
1528             }
1529             DocTestsOption::Yes => {}
1530         }
1531
1532         cargo.arg("-p").arg(krate);
1533
1534         // The tests are going to run with the *target* libraries, so we need to
1535         // ensure that those libraries show up in the LD_LIBRARY_PATH equivalent.
1536         //
1537         // Note that to run the compiler we need to run with the *host* libraries,
1538         // but our wrapper scripts arrange for that to be the case anyway.
1539         let mut dylib_path = dylib_path();
1540         dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target)));
1541         cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
1542
1543         cargo.arg("--");
1544         cargo.args(&builder.config.cmd.test_args());
1545
1546         if builder.config.quiet_tests {
1547             cargo.arg("--quiet");
1548         }
1549
1550         if target.contains("emscripten") {
1551             cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
1552                       builder.config.nodejs.as_ref().expect("nodejs not configured"));
1553         } else if target.starts_with("wasm32") {
1554             // Warn about running tests without the `wasm_syscall` feature enabled.
1555             // The javascript shim implements the syscall interface so that test
1556             // output can be correctly reported.
1557             if !builder.config.wasm_syscall {
1558                 builder.info(&format!("Libstd was built without `wasm_syscall` feature enabled: \
1559                           test output may not be visible."));
1560             }
1561
1562             // On the wasm32-unknown-unknown target we're using LTO which is
1563             // incompatible with `-C prefer-dynamic`, so disable that here
1564             cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
1565
1566             let node = builder.config.nodejs.as_ref()
1567                 .expect("nodejs not configured");
1568             let runner = format!("{} {}/src/etc/wasm32-shim.js",
1569                                  node.display(),
1570                                  builder.src.display());
1571             cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), &runner);
1572         } else if builder.remote_tested(target) {
1573             cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
1574                       format!("{} run",
1575                               builder.tool_exe(Tool::RemoteTestClient).display()));
1576         }
1577
1578         let _folder = builder.fold_output(|| {
1579             format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, krate)
1580         });
1581         builder.info(&format!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage,
1582                 &compiler.host, target));
1583         let _time = util::timeit(&builder);
1584         try_run(builder, &mut cargo);
1585     }
1586 }
1587
1588 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1589 pub struct CrateRustdoc {
1590     host: Interned<String>,
1591     test_kind: TestKind,
1592 }
1593
1594 impl Step for CrateRustdoc {
1595     type Output = ();
1596     const DEFAULT: bool = true;
1597     const ONLY_HOSTS: bool = true;
1598
1599     fn should_run(run: ShouldRun) -> ShouldRun {
1600         run.paths(&["src/librustdoc", "src/tools/rustdoc"])
1601     }
1602
1603     fn make_run(run: RunConfig) {
1604         let builder = run.builder;
1605
1606         let test_kind = if builder.kind == Kind::Test {
1607             TestKind::Test
1608         } else if builder.kind == Kind::Bench {
1609             TestKind::Bench
1610         } else {
1611             panic!("unexpected builder.kind in crate: {:?}", builder.kind);
1612         };
1613
1614         builder.ensure(CrateRustdoc {
1615             host: run.host,
1616             test_kind,
1617         });
1618     }
1619
1620     fn run(self, builder: &Builder) {
1621         let test_kind = self.test_kind;
1622
1623         let compiler = builder.compiler(builder.top_stage, self.host);
1624         let target = compiler.host;
1625
1626         let mut cargo = tool::prepare_tool_cargo(builder,
1627                                                  compiler,
1628                                                  target,
1629                                                  test_kind.subcommand(),
1630                                                  "src/tools/rustdoc");
1631         if test_kind.subcommand() == "test" && !builder.fail_fast {
1632             cargo.arg("--no-fail-fast");
1633         }
1634
1635         cargo.arg("-p").arg("rustdoc:0.0.0");
1636
1637         cargo.arg("--");
1638         cargo.args(&builder.config.cmd.test_args());
1639
1640         if builder.config.quiet_tests {
1641             cargo.arg("--quiet");
1642         }
1643
1644         let _folder = builder.fold_output(|| {
1645             format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage)
1646         });
1647         builder.info(&format!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage,
1648                 &compiler.host, target));
1649         let _time = util::timeit(&builder);
1650
1651         try_run(builder, &mut cargo);
1652     }
1653 }
1654
1655 fn envify(s: &str) -> String {
1656     s.chars().map(|c| {
1657         match c {
1658             '-' => '_',
1659             c => c,
1660         }
1661     }).flat_map(|c| c.to_uppercase()).collect()
1662 }
1663
1664 /// Some test suites are run inside emulators or on remote devices, and most
1665 /// of our test binaries are linked dynamically which means we need to ship
1666 /// the standard library and such to the emulator ahead of time. This step
1667 /// represents this and is a dependency of all test suites.
1668 ///
1669 /// Most of the time this is a noop. For some steps such as shipping data to
1670 /// QEMU we have to build our own tools so we've got conditional dependencies
1671 /// on those programs as well. Note that the remote test client is built for
1672 /// the build target (us) and the server is built for the target.
1673 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1674 pub struct RemoteCopyLibs {
1675     compiler: Compiler,
1676     target: Interned<String>,
1677 }
1678
1679 impl Step for RemoteCopyLibs {
1680     type Output = ();
1681
1682     fn should_run(run: ShouldRun) -> ShouldRun {
1683         run.never()
1684     }
1685
1686     fn run(self, builder: &Builder) {
1687         let compiler = self.compiler;
1688         let target = self.target;
1689         if !builder.remote_tested(target) {
1690             return
1691         }
1692
1693         builder.ensure(compile::Test { compiler, target });
1694
1695         builder.info(&format!("REMOTE copy libs to emulator ({})", target));
1696         t!(fs::create_dir_all(builder.out.join("tmp")));
1697
1698         let server = builder.ensure(tool::RemoteTestServer { compiler, target });
1699
1700         // Spawn the emulator and wait for it to come online
1701         let tool = builder.tool_exe(Tool::RemoteTestClient);
1702         let mut cmd = Command::new(&tool);
1703         cmd.arg("spawn-emulator")
1704            .arg(target)
1705            .arg(&server)
1706            .arg(builder.out.join("tmp"));
1707         if let Some(rootfs) = builder.qemu_rootfs(target) {
1708             cmd.arg(rootfs);
1709         }
1710         builder.run(&mut cmd);
1711
1712         // Push all our dylibs to the emulator
1713         for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) {
1714             let f = t!(f);
1715             let name = f.file_name().into_string().unwrap();
1716             if util::is_dylib(&name) {
1717                 builder.run(Command::new(&tool)
1718                                   .arg("push")
1719                                   .arg(f.path()));
1720             }
1721         }
1722     }
1723 }
1724
1725 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1726 pub struct Distcheck;
1727
1728 impl Step for Distcheck {
1729     type Output = ();
1730
1731     fn should_run(run: ShouldRun) -> ShouldRun {
1732         run.path("distcheck")
1733     }
1734
1735     fn make_run(run: RunConfig) {
1736         run.builder.ensure(Distcheck);
1737     }
1738
1739     /// Run "distcheck", a 'make check' from a tarball
1740     fn run(self, builder: &Builder) {
1741         builder.info(&format!("Distcheck"));
1742         let dir = builder.out.join("tmp").join("distcheck");
1743         let _ = fs::remove_dir_all(&dir);
1744         t!(fs::create_dir_all(&dir));
1745
1746         // Guarantee that these are built before we begin running.
1747         builder.ensure(dist::PlainSourceTarball);
1748         builder.ensure(dist::Src);
1749
1750         let mut cmd = Command::new("tar");
1751         cmd.arg("-xzf")
1752            .arg(builder.ensure(dist::PlainSourceTarball))
1753            .arg("--strip-components=1")
1754            .current_dir(&dir);
1755         builder.run(&mut cmd);
1756         builder.run(Command::new("./configure")
1757                          .args(&builder.config.configure_args)
1758                          .arg("--enable-vendor")
1759                          .current_dir(&dir));
1760         builder.run(Command::new(build_helper::make(&builder.config.build))
1761                          .arg("check")
1762                          .current_dir(&dir));
1763
1764         // Now make sure that rust-src has all of libstd's dependencies
1765         builder.info(&format!("Distcheck rust-src"));
1766         let dir = builder.out.join("tmp").join("distcheck-src");
1767         let _ = fs::remove_dir_all(&dir);
1768         t!(fs::create_dir_all(&dir));
1769
1770         let mut cmd = Command::new("tar");
1771         cmd.arg("-xzf")
1772            .arg(builder.ensure(dist::Src))
1773            .arg("--strip-components=1")
1774            .current_dir(&dir);
1775         builder.run(&mut cmd);
1776
1777         let toml = dir.join("rust-src/lib/rustlib/src/rust/src/libstd/Cargo.toml");
1778         builder.run(Command::new(&builder.initial_cargo)
1779                          .arg("generate-lockfile")
1780                          .arg("--manifest-path")
1781                          .arg(&toml)
1782                          .current_dir(&dir));
1783     }
1784 }
1785
1786 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1787 pub struct Bootstrap;
1788
1789 impl Step for Bootstrap {
1790     type Output = ();
1791     const DEFAULT: bool = true;
1792     const ONLY_HOSTS: bool = true;
1793
1794     /// Test the build system itself
1795     fn run(self, builder: &Builder) {
1796         let mut cmd = Command::new(&builder.initial_cargo);
1797         cmd.arg("test")
1798            .current_dir(builder.src.join("src/bootstrap"))
1799            .env("RUSTFLAGS", "-Cdebuginfo=2")
1800            .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
1801            .env("RUSTC_BOOTSTRAP", "1")
1802            .env("RUSTC", &builder.initial_rustc);
1803         if let Some(flags) = option_env!("RUSTFLAGS") {
1804             // Use the same rustc flags for testing as for "normal" compilation,
1805             // so that Cargo doesn’t recompile the entire dependency graph every time:
1806             // https://github.com/rust-lang/rust/issues/49215
1807             cmd.env("RUSTFLAGS", flags);
1808         }
1809         if !builder.fail_fast {
1810             cmd.arg("--no-fail-fast");
1811         }
1812         cmd.arg("--").args(&builder.config.cmd.test_args());
1813         try_run(builder, &mut cmd);
1814     }
1815
1816     fn should_run(run: ShouldRun) -> ShouldRun {
1817         run.path("src/bootstrap")
1818     }
1819
1820     fn make_run(run: RunConfig) {
1821         run.builder.ensure(Bootstrap);
1822     }
1823 }