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