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