]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/test.rs
Use () for all_traits.
[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;
18 use crate::compile;
19 use crate::config::TargetSelection;
20 use crate::dist;
21 use crate::flags::Subcommand;
22 use crate::native;
23 use crate::tool::{self, SourceType, Tool};
24 use crate::toolstate::ToolState;
25 use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var};
26 use crate::Crate as CargoCrate;
27 use crate::{envify, DocTests, GitRepo, Mode};
28
29 const ADB_TEST_DIR: &str = "/data/tmp/work";
30
31 /// The two modes of the test runner; tests or benchmarks.
32 #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord)]
33 pub enum TestKind {
34     /// Run `cargo test`.
35     Test,
36     /// Run `cargo bench`.
37     Bench,
38 }
39
40 impl From<Kind> for TestKind {
41     fn from(kind: Kind) -> Self {
42         match kind {
43             Kind::Test => TestKind::Test,
44             Kind::Bench => TestKind::Bench,
45             _ => panic!("unexpected kind in crate: {:?}", kind),
46         }
47     }
48 }
49
50 impl TestKind {
51     // Return the cargo subcommand for this test kind
52     fn subcommand(self) -> &'static str {
53         match self {
54             TestKind::Test => "test",
55             TestKind::Bench => "bench",
56         }
57     }
58 }
59
60 impl fmt::Display for TestKind {
61     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62         f.write_str(match *self {
63             TestKind::Test => "Testing",
64             TestKind::Bench => "Benchmarking",
65         })
66     }
67 }
68
69 fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> bool {
70     if !builder.fail_fast {
71         if !builder.try_run(cmd) {
72             let mut failures = builder.delayed_failures.borrow_mut();
73             failures.push(format!("{:?}", cmd));
74             return false;
75         }
76     } else {
77         builder.run(cmd);
78     }
79     true
80 }
81
82 fn try_run_quiet(builder: &Builder<'_>, cmd: &mut Command) -> bool {
83     if !builder.fail_fast {
84         if !builder.try_run_quiet(cmd) {
85             let mut failures = builder.delayed_failures.borrow_mut();
86             failures.push(format!("{:?}", cmd));
87             return false;
88         }
89     } else {
90         builder.run_quiet(cmd);
91     }
92     true
93 }
94
95 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
96 pub struct Linkcheck {
97     host: TargetSelection,
98 }
99
100 impl Step for Linkcheck {
101     type Output = ();
102     const ONLY_HOSTS: bool = true;
103     const DEFAULT: bool = true;
104
105     /// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.
106     ///
107     /// This tool in `src/tools` will verify the validity of all our links in the
108     /// documentation to ensure we don't have a bunch of dead ones.
109     fn run(self, builder: &Builder<'_>) {
110         let host = self.host;
111         let hosts = &builder.hosts;
112         let targets = &builder.targets;
113
114         // if we have different hosts and targets, some things may be built for
115         // the host (e.g. rustc) and others for the target (e.g. std). The
116         // documentation built for each will contain broken links to
117         // docs built for the other platform (e.g. rustc linking to cargo)
118         if (hosts != targets) && !hosts.is_empty() && !targets.is_empty() {
119             panic!(
120                 "Linkcheck currently does not support builds with different hosts and targets.
121 You can skip linkcheck with --exclude src/tools/linkchecker"
122             );
123         }
124
125         builder.info(&format!("Linkcheck ({})", host));
126
127         builder.default_doc(&[]);
128
129         let _time = util::timeit(&builder);
130         try_run(
131             builder,
132             builder.tool_cmd(Tool::Linkchecker).arg(builder.out.join(host.triple).join("doc")),
133         );
134     }
135
136     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
137         let builder = run.builder;
138         let run = run.path("src/tools/linkchecker");
139         run.default_condition(builder.config.docs)
140     }
141
142     fn make_run(run: RunConfig<'_>) {
143         run.builder.ensure(Linkcheck { host: run.target });
144     }
145 }
146
147 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
148 pub struct Cargotest {
149     stage: u32,
150     host: TargetSelection,
151 }
152
153 impl Step for Cargotest {
154     type Output = ();
155     const ONLY_HOSTS: bool = true;
156
157     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
158         run.path("src/tools/cargotest")
159     }
160
161     fn make_run(run: RunConfig<'_>) {
162         run.builder.ensure(Cargotest { stage: run.builder.top_stage, host: run.target });
163     }
164
165     /// Runs the `cargotest` tool as compiled in `stage` by the `host` compiler.
166     ///
167     /// This tool in `src/tools` will check out a few Rust projects and run `cargo
168     /// test` to ensure that we don't regress the test suites there.
169     fn run(self, builder: &Builder<'_>) {
170         let compiler = builder.compiler(self.stage, self.host);
171         builder.ensure(compile::Rustc { compiler, target: compiler.host });
172         let cargo = builder.ensure(tool::Cargo { compiler, target: compiler.host });
173
174         // Note that this is a short, cryptic, and not scoped directory name. This
175         // is currently to minimize the length of path on Windows where we otherwise
176         // quickly run into path name limit constraints.
177         let out_dir = builder.out.join("ct");
178         t!(fs::create_dir_all(&out_dir));
179
180         let _time = util::timeit(&builder);
181         let mut cmd = builder.tool_cmd(Tool::CargoTest);
182         try_run(
183             builder,
184             cmd.arg(&cargo)
185                 .arg(&out_dir)
186                 .args(builder.config.cmd.test_args())
187                 .env("RUSTC", builder.rustc(compiler))
188                 .env("RUSTDOC", builder.rustdoc(compiler)),
189         );
190     }
191 }
192
193 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
194 pub struct Cargo {
195     stage: u32,
196     host: TargetSelection,
197 }
198
199 impl Step for Cargo {
200     type Output = ();
201     const ONLY_HOSTS: bool = true;
202
203     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
204         run.path("src/tools/cargo")
205     }
206
207     fn make_run(run: RunConfig<'_>) {
208         run.builder.ensure(Cargo { stage: run.builder.top_stage, host: run.target });
209     }
210
211     /// Runs `cargo test` for `cargo` packaged with Rust.
212     fn run(self, builder: &Builder<'_>) {
213         let compiler = builder.compiler(self.stage, self.host);
214
215         builder.ensure(tool::Cargo { compiler, target: self.host });
216         let mut cargo = tool::prepare_tool_cargo(
217             builder,
218             compiler,
219             Mode::ToolRustc,
220             self.host,
221             "test",
222             "src/tools/cargo",
223             SourceType::Submodule,
224             &[],
225         );
226
227         if !builder.fail_fast {
228             cargo.arg("--no-fail-fast");
229         }
230         cargo.arg("--").args(builder.config.cmd.test_args());
231
232         // Don't run cross-compile tests, we may not have cross-compiled libstd libs
233         // available.
234         cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
235         // Disable a test that has issues with mingw.
236         cargo.env("CARGO_TEST_DISABLE_GIT_CLI", "1");
237         // Forcibly disable tests using nightly features since any changes to
238         // those features won't be able to land.
239         cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1");
240
241         cargo.env("PATH", &path_for_cargo(builder, compiler));
242
243         try_run(builder, &mut cargo.into());
244     }
245 }
246
247 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
248 pub struct Rls {
249     stage: u32,
250     host: TargetSelection,
251 }
252
253 impl Step for Rls {
254     type Output = ();
255     const ONLY_HOSTS: bool = true;
256
257     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
258         run.path("src/tools/rls")
259     }
260
261     fn make_run(run: RunConfig<'_>) {
262         run.builder.ensure(Rls { stage: run.builder.top_stage, host: run.target });
263     }
264
265     /// Runs `cargo test` for the rls.
266     fn run(self, builder: &Builder<'_>) {
267         let stage = self.stage;
268         let host = self.host;
269         let compiler = builder.compiler(stage, host);
270
271         let build_result =
272             builder.ensure(tool::Rls { compiler, target: self.host, extra_features: Vec::new() });
273         if build_result.is_none() {
274             eprintln!("failed to test rls: could not build");
275             return;
276         }
277
278         let mut cargo = tool::prepare_tool_cargo(
279             builder,
280             compiler,
281             Mode::ToolRustc,
282             host,
283             "test",
284             "src/tools/rls",
285             SourceType::Submodule,
286             &[],
287         );
288
289         cargo.add_rustc_lib_path(builder, compiler);
290         cargo.arg("--").args(builder.config.cmd.test_args());
291
292         if try_run(builder, &mut cargo.into()) {
293             builder.save_toolstate("rls", ToolState::TestPass);
294         }
295     }
296 }
297
298 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
299 pub struct Rustfmt {
300     stage: u32,
301     host: TargetSelection,
302 }
303
304 impl Step for Rustfmt {
305     type Output = ();
306     const ONLY_HOSTS: bool = true;
307
308     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
309         run.path("src/tools/rustfmt")
310     }
311
312     fn make_run(run: RunConfig<'_>) {
313         run.builder.ensure(Rustfmt { stage: run.builder.top_stage, host: run.target });
314     }
315
316     /// Runs `cargo test` for rustfmt.
317     fn run(self, builder: &Builder<'_>) {
318         let stage = self.stage;
319         let host = self.host;
320         let compiler = builder.compiler(stage, host);
321
322         let build_result = builder.ensure(tool::Rustfmt {
323             compiler,
324             target: self.host,
325             extra_features: Vec::new(),
326         });
327         if build_result.is_none() {
328             eprintln!("failed to test rustfmt: could not build");
329             return;
330         }
331
332         let mut cargo = tool::prepare_tool_cargo(
333             builder,
334             compiler,
335             Mode::ToolRustc,
336             host,
337             "test",
338             "src/tools/rustfmt",
339             SourceType::Submodule,
340             &[],
341         );
342
343         let dir = testdir(builder, compiler.host);
344         t!(fs::create_dir_all(&dir));
345         cargo.env("RUSTFMT_TEST_DIR", dir);
346
347         cargo.add_rustc_lib_path(builder, compiler);
348
349         if try_run(builder, &mut cargo.into()) {
350             builder.save_toolstate("rustfmt", ToolState::TestPass);
351         }
352     }
353 }
354
355 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
356 pub struct RustDemangler {
357     stage: u32,
358     host: TargetSelection,
359 }
360
361 impl Step for RustDemangler {
362     type Output = ();
363     const ONLY_HOSTS: bool = true;
364
365     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
366         run.path("src/tools/rust-demangler")
367     }
368
369     fn make_run(run: RunConfig<'_>) {
370         run.builder.ensure(RustDemangler { stage: run.builder.top_stage, host: run.target });
371     }
372
373     /// Runs `cargo test` for rust-demangler.
374     fn run(self, builder: &Builder<'_>) {
375         let stage = self.stage;
376         let host = self.host;
377         let compiler = builder.compiler(stage, host);
378
379         let rust_demangler = builder
380             .ensure(tool::RustDemangler { compiler, target: self.host, extra_features: Vec::new() })
381             .expect("in-tree tool");
382         let mut cargo = tool::prepare_tool_cargo(
383             builder,
384             compiler,
385             Mode::ToolRustc,
386             host,
387             "test",
388             "src/tools/rust-demangler",
389             SourceType::InTree,
390             &[],
391         );
392
393         let dir = testdir(builder, compiler.host);
394         t!(fs::create_dir_all(&dir));
395
396         cargo.env("RUST_DEMANGLER_DRIVER_PATH", rust_demangler);
397
398         cargo.arg("--").args(builder.config.cmd.test_args());
399
400         cargo.add_rustc_lib_path(builder, compiler);
401
402         builder.run(&mut cargo.into());
403     }
404 }
405
406 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
407 pub struct Miri {
408     stage: u32,
409     host: TargetSelection,
410 }
411
412 impl Step for Miri {
413     type Output = ();
414     const ONLY_HOSTS: bool = true;
415
416     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
417         run.path("src/tools/miri")
418     }
419
420     fn make_run(run: RunConfig<'_>) {
421         run.builder.ensure(Miri { stage: run.builder.top_stage, host: run.target });
422     }
423
424     /// Runs `cargo test` for miri.
425     fn run(self, builder: &Builder<'_>) {
426         let stage = self.stage;
427         let host = self.host;
428         let compiler = builder.compiler(stage, host);
429
430         let miri =
431             builder.ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() });
432         let cargo_miri = builder.ensure(tool::CargoMiri {
433             compiler,
434             target: self.host,
435             extra_features: Vec::new(),
436         });
437         if let (Some(miri), Some(_cargo_miri)) = (miri, cargo_miri) {
438             let mut cargo =
439                 builder.cargo(compiler, Mode::ToolRustc, SourceType::Submodule, host, "install");
440             cargo.arg("xargo");
441             // Configure `cargo install` path. cargo adds a `bin/`.
442             cargo.env("CARGO_INSTALL_ROOT", &builder.out);
443
444             let mut cargo = Command::from(cargo);
445             if !try_run(builder, &mut cargo) {
446                 return;
447             }
448
449             // # Run `cargo miri setup`.
450             let mut cargo = tool::prepare_tool_cargo(
451                 builder,
452                 compiler,
453                 Mode::ToolRustc,
454                 host,
455                 "run",
456                 "src/tools/miri/cargo-miri",
457                 SourceType::Submodule,
458                 &[],
459             );
460             cargo.arg("--").arg("miri").arg("setup");
461
462             // Tell `cargo miri setup` where to find the sources.
463             cargo.env("XARGO_RUST_SRC", builder.src.join("library"));
464             // Tell it where to find Miri.
465             cargo.env("MIRI", &miri);
466             // Debug things.
467             cargo.env("RUST_BACKTRACE", "1");
468             // Let cargo-miri know where xargo ended up.
469             cargo.env("XARGO_CHECK", builder.out.join("bin").join("xargo-check"));
470
471             let mut cargo = Command::from(cargo);
472             if !try_run(builder, &mut cargo) {
473                 return;
474             }
475
476             // # Determine where Miri put its sysroot.
477             // To this end, we run `cargo miri setup --print-sysroot` and capture the output.
478             // (We do this separately from the above so that when the setup actually
479             // happens we get some output.)
480             // We re-use the `cargo` from above.
481             cargo.arg("--print-sysroot");
482
483             // FIXME: Is there a way in which we can re-use the usual `run` helpers?
484             let miri_sysroot = if builder.config.dry_run {
485                 String::new()
486             } else {
487                 builder.verbose(&format!("running: {:?}", cargo));
488                 let out = cargo
489                     .output()
490                     .expect("We already ran `cargo miri setup` before and that worked");
491                 assert!(out.status.success(), "`cargo miri setup` returned with non-0 exit code");
492                 // Output is "<sysroot>\n".
493                 let stdout = String::from_utf8(out.stdout)
494                     .expect("`cargo miri setup` stdout is not valid UTF-8");
495                 let sysroot = stdout.trim_end();
496                 builder.verbose(&format!("`cargo miri setup --print-sysroot` said: {:?}", sysroot));
497                 sysroot.to_owned()
498             };
499
500             // # Run `cargo test`.
501             let mut cargo = tool::prepare_tool_cargo(
502                 builder,
503                 compiler,
504                 Mode::ToolRustc,
505                 host,
506                 "test",
507                 "src/tools/miri",
508                 SourceType::Submodule,
509                 &[],
510             );
511
512             // miri tests need to know about the stage sysroot
513             cargo.env("MIRI_SYSROOT", miri_sysroot);
514             cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
515             cargo.env("MIRI", miri);
516
517             cargo.arg("--").args(builder.config.cmd.test_args());
518
519             cargo.add_rustc_lib_path(builder, compiler);
520
521             let mut cargo = Command::from(cargo);
522             if !try_run(builder, &mut cargo) {
523                 return;
524             }
525
526             // # Run `cargo test` with `-Zmir-opt-level=4`.
527             cargo.env("MIRIFLAGS", "-O -Zmir-opt-level=4");
528             if !try_run(builder, &mut cargo) {
529                 return;
530             }
531
532             // # Done!
533             builder.save_toolstate("miri", ToolState::TestPass);
534         } else {
535             eprintln!("failed to test miri: could not build");
536         }
537     }
538 }
539
540 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
541 pub struct CompiletestTest {
542     host: TargetSelection,
543 }
544
545 impl Step for CompiletestTest {
546     type Output = ();
547
548     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
549         run.path("src/tools/compiletest")
550     }
551
552     fn make_run(run: RunConfig<'_>) {
553         run.builder.ensure(CompiletestTest { host: run.target });
554     }
555
556     /// Runs `cargo test` for compiletest.
557     fn run(self, builder: &Builder<'_>) {
558         let host = self.host;
559         let compiler = builder.compiler(0, host);
560
561         // We need `ToolStd` for the locally-built sysroot because
562         // compiletest uses unstable features of the `test` crate.
563         builder.ensure(compile::Std { compiler, target: host });
564         let cargo = tool::prepare_tool_cargo(
565             builder,
566             compiler,
567             Mode::ToolStd,
568             host,
569             "test",
570             "src/tools/compiletest",
571             SourceType::InTree,
572             &[],
573         );
574
575         try_run(builder, &mut cargo.into());
576     }
577 }
578
579 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
580 pub struct Clippy {
581     stage: u32,
582     host: TargetSelection,
583 }
584
585 impl Step for Clippy {
586     type Output = ();
587     const ONLY_HOSTS: bool = true;
588     const DEFAULT: bool = false;
589
590     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
591         run.path("src/tools/clippy")
592     }
593
594     fn make_run(run: RunConfig<'_>) {
595         run.builder.ensure(Clippy { stage: run.builder.top_stage, host: run.target });
596     }
597
598     /// Runs `cargo test` for clippy.
599     fn run(self, builder: &Builder<'_>) {
600         let stage = self.stage;
601         let host = self.host;
602         let compiler = builder.compiler(stage, host);
603
604         let clippy = builder
605             .ensure(tool::Clippy { compiler, target: self.host, extra_features: Vec::new() })
606             .expect("in-tree tool");
607         let mut cargo = tool::prepare_tool_cargo(
608             builder,
609             compiler,
610             Mode::ToolRustc,
611             host,
612             "test",
613             "src/tools/clippy",
614             SourceType::InTree,
615             &[],
616         );
617
618         // clippy tests need to know about the stage sysroot
619         cargo.env("SYSROOT", builder.sysroot(compiler));
620         cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
621         cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
622         let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir());
623         let target_libs = builder
624             .stage_out(compiler, Mode::ToolRustc)
625             .join(&self.host.triple)
626             .join(builder.cargo_dir());
627         cargo.env("HOST_LIBS", host_libs);
628         cargo.env("TARGET_LIBS", target_libs);
629         // clippy tests need to find the driver
630         cargo.env("CLIPPY_DRIVER_PATH", clippy);
631
632         cargo.arg("--").args(builder.config.cmd.test_args());
633
634         cargo.add_rustc_lib_path(builder, compiler);
635
636         if builder.try_run(&mut cargo.into()) {
637             // The tests succeeded; nothing to do.
638             return;
639         }
640
641         if !builder.config.cmd.bless() {
642             std::process::exit(1);
643         }
644
645         let mut cargo = builder.cargo(compiler, Mode::ToolRustc, SourceType::InTree, host, "run");
646         cargo.arg("-p").arg("clippy_dev");
647         // clippy_dev gets confused if it can't find `clippy/Cargo.toml`
648         cargo.current_dir(&builder.src.join("src").join("tools").join("clippy"));
649         if builder.config.rust_optimize {
650             cargo.env("PROFILE", "release");
651         } else {
652             cargo.env("PROFILE", "debug");
653         }
654         cargo.arg("--");
655         cargo.arg("bless");
656         builder.run(&mut cargo.into());
657     }
658 }
659
660 fn path_for_cargo(builder: &Builder<'_>, compiler: Compiler) -> OsString {
661     // Configure PATH to find the right rustc. NB. we have to use PATH
662     // and not RUSTC because the Cargo test suite has tests that will
663     // fail if rustc is not spelled `rustc`.
664     let path = builder.sysroot(compiler).join("bin");
665     let old_path = env::var_os("PATH").unwrap_or_default();
666     env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("")
667 }
668
669 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
670 pub struct RustdocTheme {
671     pub compiler: Compiler,
672 }
673
674 impl Step for RustdocTheme {
675     type Output = ();
676     const DEFAULT: bool = true;
677     const ONLY_HOSTS: bool = true;
678
679     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
680         run.path("src/tools/rustdoc-themes")
681     }
682
683     fn make_run(run: RunConfig<'_>) {
684         let compiler = run.builder.compiler(run.builder.top_stage, run.target);
685
686         run.builder.ensure(RustdocTheme { compiler });
687     }
688
689     fn run(self, builder: &Builder<'_>) {
690         let rustdoc = builder.out.join("bootstrap/debug/rustdoc");
691         let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
692         cmd.arg(rustdoc.to_str().unwrap())
693             .arg(builder.src.join("src/librustdoc/html/static/themes").to_str().unwrap())
694             .env("RUSTC_STAGE", self.compiler.stage.to_string())
695             .env("RUSTC_SYSROOT", builder.sysroot(self.compiler))
696             .env("RUSTDOC_LIBDIR", builder.sysroot_libdir(self.compiler, self.compiler.host))
697             .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
698             .env("RUSTDOC_REAL", builder.rustdoc(self.compiler))
699             .env("RUSTC_BOOTSTRAP", "1");
700         if let Some(linker) = builder.linker(self.compiler.host) {
701             cmd.env("RUSTDOC_LINKER", linker);
702         }
703         if builder.is_fuse_ld_lld(self.compiler.host) {
704             cmd.env("RUSTDOC_FUSE_LD_LLD", "1");
705         }
706         try_run(builder, &mut cmd);
707     }
708 }
709
710 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
711 pub struct RustdocJSStd {
712     pub target: TargetSelection,
713 }
714
715 impl Step for RustdocJSStd {
716     type Output = ();
717     const DEFAULT: bool = true;
718     const ONLY_HOSTS: bool = true;
719
720     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
721         run.path("src/test/rustdoc-js-std")
722     }
723
724     fn make_run(run: RunConfig<'_>) {
725         run.builder.ensure(RustdocJSStd { target: run.target });
726     }
727
728     fn run(self, builder: &Builder<'_>) {
729         if let Some(ref nodejs) = builder.config.nodejs {
730             let mut command = Command::new(nodejs);
731             command
732                 .arg(builder.src.join("src/tools/rustdoc-js/tester.js"))
733                 .arg("--crate-name")
734                 .arg("std")
735                 .arg("--resource-suffix")
736                 .arg(&builder.version)
737                 .arg("--doc-folder")
738                 .arg(builder.doc_out(self.target))
739                 .arg("--test-folder")
740                 .arg(builder.src.join("src/test/rustdoc-js-std"));
741             builder.ensure(crate::doc::Std { target: self.target, stage: builder.top_stage });
742             builder.run(&mut command);
743         } else {
744             builder.info("No nodejs found, skipping \"src/test/rustdoc-js-std\" tests");
745         }
746     }
747 }
748
749 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
750 pub struct RustdocJSNotStd {
751     pub target: TargetSelection,
752     pub compiler: Compiler,
753 }
754
755 impl Step for RustdocJSNotStd {
756     type Output = ();
757     const DEFAULT: bool = true;
758     const ONLY_HOSTS: bool = true;
759
760     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
761         run.path("src/test/rustdoc-js")
762     }
763
764     fn make_run(run: RunConfig<'_>) {
765         let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
766         run.builder.ensure(RustdocJSNotStd { target: run.target, compiler });
767     }
768
769     fn run(self, builder: &Builder<'_>) {
770         if builder.config.nodejs.is_some() {
771             builder.ensure(Compiletest {
772                 compiler: self.compiler,
773                 target: self.target,
774                 mode: "js-doc-test",
775                 suite: "rustdoc-js",
776                 path: "src/test/rustdoc-js",
777                 compare_mode: None,
778             });
779         } else {
780             builder.info("No nodejs found, skipping \"src/test/rustdoc-js\" tests");
781         }
782     }
783 }
784
785 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
786 pub struct RustdocGUI {
787     pub target: TargetSelection,
788     pub compiler: Compiler,
789 }
790
791 impl Step for RustdocGUI {
792     type Output = ();
793     const DEFAULT: bool = true;
794     const ONLY_HOSTS: bool = true;
795
796     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
797         run.path("src/test/rustdoc-gui")
798     }
799
800     fn make_run(run: RunConfig<'_>) {
801         let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
802         run.builder.ensure(RustdocGUI { target: run.target, compiler });
803     }
804
805     fn run(self, builder: &Builder<'_>) {
806         if let (Some(nodejs), Some(npm)) = (&builder.config.nodejs, &builder.config.npm) {
807             builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
808
809             // The goal here is to check if the necessary packages are installed, and if not, we
810             // display a warning and move on.
811             let mut command = Command::new(&npm);
812             command.arg("list").arg("--depth=0");
813             let lines = command
814                 .output()
815                 .map(|output| String::from_utf8_lossy(&output.stdout).to_string())
816                 .unwrap_or(String::new());
817             if !lines.contains(&" browser-ui-test@") {
818                 println!(
819                     "warning: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \
820                      dependency is missing",
821                 );
822                 println!(
823                     "If you want to install the `{0}` dependency, run `npm install {0}`",
824                     "browser-ui-test",
825                 );
826                 return;
827             }
828
829             let out_dir = builder.test_out(self.target).join("rustdoc-gui");
830
831             // We remove existing folder to be sure there won't be artifacts remaining.
832             let _ = fs::remove_dir_all(&out_dir);
833
834             // We generate docs for the libraries present in the rustdoc-gui's src folder.
835             let libs_dir = builder.build.src.join("src/test/rustdoc-gui/src");
836             for entry in libs_dir.read_dir().expect("read_dir call failed") {
837                 let entry = entry.expect("invalid entry");
838                 let path = entry.path();
839                 if path.extension().map(|e| e == "rs").unwrap_or(false) {
840                     let mut command = builder.rustdoc_cmd(self.compiler);
841                     command.arg(path).arg("-o").arg(&out_dir);
842                     builder.run(&mut command);
843                 }
844             }
845
846             // We now run GUI tests.
847             let mut command = Command::new(&nodejs);
848             command
849                 .arg(builder.build.src.join("src/tools/rustdoc-gui/tester.js"))
850                 .arg("--doc-folder")
851                 .arg(out_dir)
852                 .arg("--tests-folder")
853                 .arg(builder.build.src.join("src/test/rustdoc-gui"));
854             builder.run(&mut command);
855         } else {
856             builder.info("No nodejs found, skipping \"src/test/rustdoc-gui\" tests");
857         }
858     }
859 }
860
861 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
862 pub struct Tidy;
863
864 impl Step for Tidy {
865     type Output = ();
866     const DEFAULT: bool = true;
867     const ONLY_HOSTS: bool = true;
868
869     /// Runs the `tidy` tool.
870     ///
871     /// This tool in `src/tools` checks up on various bits and pieces of style and
872     /// otherwise just implements a few lint-like checks that are specific to the
873     /// compiler itself.
874     ///
875     /// Once tidy passes, this step also runs `fmt --check` if tests are being run
876     /// for the `dev` or `nightly` channels.
877     fn run(self, builder: &Builder<'_>) {
878         let mut cmd = builder.tool_cmd(Tool::Tidy);
879         cmd.arg(&builder.src);
880         cmd.arg(&builder.initial_cargo);
881         cmd.arg(&builder.out);
882         cmd.arg(builder.jobs().to_string());
883         if builder.is_verbose() {
884             cmd.arg("--verbose");
885         }
886
887         builder.info("tidy check");
888         try_run(builder, &mut cmd);
889
890         if builder.config.channel == "dev" || builder.config.channel == "nightly" {
891             builder.info("fmt check");
892             if builder.config.initial_rustfmt.is_none() {
893                 let inferred_rustfmt_dir = builder.config.initial_rustc.parent().unwrap();
894                 eprintln!(
895                     "\
896 error: no `rustfmt` binary found in {PATH}
897 info: `rust.channel` is currently set to \"{CHAN}\"
898 help: if you are testing a beta branch, set `rust.channel` to \"beta\" in the `config.toml` file
899 help: to skip test's attempt to check tidiness, pass `--exclude src/tools/tidy` to `x.py test`",
900                     PATH = inferred_rustfmt_dir.display(),
901                     CHAN = builder.config.channel,
902                 );
903                 std::process::exit(1);
904             }
905             crate::format::format(&builder.build, !builder.config.cmd.bless(), &[]);
906         }
907     }
908
909     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
910         run.path("src/tools/tidy")
911     }
912
913     fn make_run(run: RunConfig<'_>) {
914         run.builder.ensure(Tidy);
915     }
916 }
917
918 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
919 pub struct ExpandYamlAnchors;
920
921 impl Step for ExpandYamlAnchors {
922     type Output = ();
923     const ONLY_HOSTS: bool = true;
924
925     /// Ensure the `generate-ci-config` tool was run locally.
926     ///
927     /// The tool in `src/tools` reads the CI definition in `src/ci/builders.yml` and generates the
928     /// appropriate configuration for all our CI providers. This step ensures the tool was called
929     /// by the user before committing CI changes.
930     fn run(self, builder: &Builder<'_>) {
931         builder.info("Ensuring the YAML anchors in the GitHub Actions config were expanded");
932         try_run(
933             builder,
934             &mut builder.tool_cmd(Tool::ExpandYamlAnchors).arg("check").arg(&builder.src),
935         );
936     }
937
938     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
939         run.path("src/tools/expand-yaml-anchors")
940     }
941
942     fn make_run(run: RunConfig<'_>) {
943         run.builder.ensure(ExpandYamlAnchors);
944     }
945 }
946
947 fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf {
948     builder.out.join(host.triple).join("test")
949 }
950
951 macro_rules! default_test {
952     ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => {
953         test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: false });
954     };
955 }
956
957 macro_rules! default_test_with_compare_mode {
958     ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr,
959                    compare_mode: $compare_mode:expr }) => {
960         test_with_compare_mode!($name {
961             path: $path,
962             mode: $mode,
963             suite: $suite,
964             default: true,
965             host: false,
966             compare_mode: $compare_mode
967         });
968     };
969 }
970
971 macro_rules! host_test {
972     ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => {
973         test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: true });
974     };
975 }
976
977 macro_rules! test {
978     ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
979                    host: $host:expr }) => {
980         test_definitions!($name {
981             path: $path,
982             mode: $mode,
983             suite: $suite,
984             default: $default,
985             host: $host,
986             compare_mode: None
987         });
988     };
989 }
990
991 macro_rules! test_with_compare_mode {
992     ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
993                    host: $host:expr, compare_mode: $compare_mode:expr }) => {
994         test_definitions!($name {
995             path: $path,
996             mode: $mode,
997             suite: $suite,
998             default: $default,
999             host: $host,
1000             compare_mode: Some($compare_mode)
1001         });
1002     };
1003 }
1004
1005 macro_rules! test_definitions {
1006     ($name:ident {
1007         path: $path:expr,
1008         mode: $mode:expr,
1009         suite: $suite:expr,
1010         default: $default:expr,
1011         host: $host:expr,
1012         compare_mode: $compare_mode:expr
1013     }) => {
1014         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1015         pub struct $name {
1016             pub compiler: Compiler,
1017             pub target: TargetSelection,
1018         }
1019
1020         impl Step for $name {
1021             type Output = ();
1022             const DEFAULT: bool = $default;
1023             const ONLY_HOSTS: bool = $host;
1024
1025             fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1026                 run.suite_path($path)
1027             }
1028
1029             fn make_run(run: RunConfig<'_>) {
1030                 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1031
1032                 run.builder.ensure($name { compiler, target: run.target });
1033             }
1034
1035             fn run(self, builder: &Builder<'_>) {
1036                 builder.ensure(Compiletest {
1037                     compiler: self.compiler,
1038                     target: self.target,
1039                     mode: $mode,
1040                     suite: $suite,
1041                     path: $path,
1042                     compare_mode: $compare_mode,
1043                 })
1044             }
1045         }
1046     };
1047 }
1048
1049 default_test_with_compare_mode!(Ui {
1050     path: "src/test/ui",
1051     mode: "ui",
1052     suite: "ui",
1053     compare_mode: "nll"
1054 });
1055
1056 default_test!(RunPassValgrind {
1057     path: "src/test/run-pass-valgrind",
1058     mode: "run-pass-valgrind",
1059     suite: "run-pass-valgrind"
1060 });
1061
1062 default_test!(MirOpt { path: "src/test/mir-opt", mode: "mir-opt", suite: "mir-opt" });
1063
1064 default_test!(Codegen { path: "src/test/codegen", mode: "codegen", suite: "codegen" });
1065
1066 default_test!(CodegenUnits {
1067     path: "src/test/codegen-units",
1068     mode: "codegen-units",
1069     suite: "codegen-units"
1070 });
1071
1072 default_test!(Incremental {
1073     path: "src/test/incremental",
1074     mode: "incremental",
1075     suite: "incremental"
1076 });
1077
1078 default_test_with_compare_mode!(Debuginfo {
1079     path: "src/test/debuginfo",
1080     mode: "debuginfo",
1081     suite: "debuginfo",
1082     compare_mode: "split-dwarf"
1083 });
1084
1085 host_test!(UiFullDeps { path: "src/test/ui-fulldeps", mode: "ui", suite: "ui-fulldeps" });
1086
1087 host_test!(Rustdoc { path: "src/test/rustdoc", mode: "rustdoc", suite: "rustdoc" });
1088 host_test!(RustdocUi { path: "src/test/rustdoc-ui", mode: "ui", suite: "rustdoc-ui" });
1089
1090 host_test!(RustdocJson {
1091     path: "src/test/rustdoc-json",
1092     mode: "rustdoc-json",
1093     suite: "rustdoc-json"
1094 });
1095
1096 host_test!(Pretty { path: "src/test/pretty", mode: "pretty", suite: "pretty" });
1097
1098 default_test!(RunMake { path: "src/test/run-make", mode: "run-make", suite: "run-make" });
1099
1100 host_test!(RunMakeFullDeps {
1101     path: "src/test/run-make-fulldeps",
1102     mode: "run-make",
1103     suite: "run-make-fulldeps"
1104 });
1105
1106 default_test!(Assembly { path: "src/test/assembly", mode: "assembly", suite: "assembly" });
1107
1108 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1109 struct Compiletest {
1110     compiler: Compiler,
1111     target: TargetSelection,
1112     mode: &'static str,
1113     suite: &'static str,
1114     path: &'static str,
1115     compare_mode: Option<&'static str>,
1116 }
1117
1118 impl Compiletest {
1119     fn add_lld_flags(builder: &Builder<'_>, target: TargetSelection, flags: &mut Vec<String>) {
1120         if builder.config.use_lld {
1121             if builder.is_fuse_ld_lld(target) {
1122                 flags.push("-Clink-arg=-fuse-ld=lld".to_string());
1123             }
1124
1125             let threads = if target.contains("windows") { "/threads:1" } else { "--threads=1" };
1126             flags.push(format!("-Clink-arg=-Wl,{}", threads));
1127         }
1128     }
1129 }
1130
1131 impl Step for Compiletest {
1132     type Output = ();
1133
1134     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1135         run.never()
1136     }
1137
1138     /// Executes the `compiletest` tool to run a suite of tests.
1139     ///
1140     /// Compiles all tests with `compiler` for `target` with the specified
1141     /// compiletest `mode` and `suite` arguments. For example `mode` can be
1142     /// "run-pass" or `suite` can be something like `debuginfo`.
1143     fn run(self, builder: &Builder<'_>) {
1144         if builder.top_stage == 0 && env::var("COMPILETEST_FORCE_STAGE0").is_err() {
1145             eprintln!("\
1146 error: `--stage 0` runs compiletest on the beta compiler, not your local changes, and will almost always cause tests to fail
1147 help: to test the compiler, use `--stage 1` instead
1148 help: to test the standard library, use `--stage 0 library/std` instead
1149 note: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`."
1150             );
1151             std::process::exit(1);
1152         }
1153
1154         let compiler = self.compiler;
1155         let target = self.target;
1156         let mode = self.mode;
1157         let suite = self.suite;
1158
1159         // Path for test suite
1160         let suite_path = self.path;
1161
1162         // Skip codegen tests if they aren't enabled in configuration.
1163         if !builder.config.codegen_tests && suite == "codegen" {
1164             return;
1165         }
1166
1167         if suite == "debuginfo" {
1168             builder
1169                 .ensure(dist::DebuggerScripts { sysroot: builder.sysroot(compiler), host: target });
1170         }
1171
1172         if suite.ends_with("fulldeps") {
1173             builder.ensure(compile::Rustc { compiler, target });
1174         }
1175
1176         builder.ensure(compile::Std { compiler, target });
1177         // ensure that `libproc_macro` is available on the host.
1178         builder.ensure(compile::Std { compiler, target: compiler.host });
1179
1180         // Also provide `rust_test_helpers` for the host.
1181         builder.ensure(native::TestHelpers { target: compiler.host });
1182
1183         // As well as the target, except for plain wasm32, which can't build it
1184         if !target.contains("wasm32") || target.contains("emscripten") {
1185             builder.ensure(native::TestHelpers { target });
1186         }
1187
1188         builder.ensure(RemoteCopyLibs { compiler, target });
1189
1190         let mut cmd = builder.tool_cmd(Tool::Compiletest);
1191
1192         // compiletest currently has... a lot of arguments, so let's just pass all
1193         // of them!
1194
1195         cmd.arg("--compile-lib-path").arg(builder.rustc_libdir(compiler));
1196         cmd.arg("--run-lib-path").arg(builder.sysroot_libdir(compiler, target));
1197         cmd.arg("--rustc-path").arg(builder.rustc(compiler));
1198
1199         let is_rustdoc = suite.ends_with("rustdoc-ui") || suite.ends_with("rustdoc-js");
1200
1201         // Avoid depending on rustdoc when we don't need it.
1202         if mode == "rustdoc"
1203             || mode == "run-make"
1204             || (mode == "ui" && is_rustdoc)
1205             || mode == "js-doc-test"
1206             || mode == "rustdoc-json"
1207         {
1208             cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler));
1209         }
1210
1211         if mode == "rustdoc-json" {
1212             // Use the beta compiler for jsondocck
1213             let json_compiler = compiler.with_stage(0);
1214             cmd.arg("--jsondocck-path")
1215                 .arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target }));
1216         }
1217
1218         if mode == "run-make" && suite.ends_with("fulldeps") {
1219             let rust_demangler = builder
1220                 .ensure(tool::RustDemangler { compiler, target, extra_features: Vec::new() })
1221                 .expect("in-tree tool");
1222             cmd.arg("--rust-demangler-path").arg(rust_demangler);
1223         }
1224
1225         cmd.arg("--src-base").arg(builder.src.join("src/test").join(suite));
1226         cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite));
1227         cmd.arg("--stage-id").arg(format!("stage{}-{}", compiler.stage, target));
1228         cmd.arg("--suite").arg(suite);
1229         cmd.arg("--mode").arg(mode);
1230         cmd.arg("--target").arg(target.rustc_target_arg());
1231         cmd.arg("--host").arg(&*compiler.host.triple);
1232         cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build));
1233
1234         if builder.config.cmd.bless() {
1235             cmd.arg("--bless");
1236         }
1237
1238         let compare_mode =
1239             builder.config.cmd.compare_mode().or_else(|| {
1240                 if builder.config.test_compare_mode { self.compare_mode } else { None }
1241             });
1242
1243         if let Some(ref pass) = builder.config.cmd.pass() {
1244             cmd.arg("--pass");
1245             cmd.arg(pass);
1246         }
1247
1248         if let Some(ref run) = builder.config.cmd.run() {
1249             cmd.arg("--run");
1250             cmd.arg(run);
1251         }
1252
1253         if let Some(ref nodejs) = builder.config.nodejs {
1254             cmd.arg("--nodejs").arg(nodejs);
1255         }
1256         if let Some(ref npm) = builder.config.npm {
1257             cmd.arg("--npm").arg(npm);
1258         }
1259
1260         let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
1261         if !is_rustdoc {
1262             if builder.config.rust_optimize_tests {
1263                 flags.push("-O".to_string());
1264             }
1265         }
1266         flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
1267         flags.push("-Zunstable-options".to_string());
1268         flags.push(builder.config.cmd.rustc_args().join(" "));
1269
1270         if let Some(linker) = builder.linker(target) {
1271             cmd.arg("--linker").arg(linker);
1272         }
1273
1274         let mut hostflags = flags.clone();
1275         hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display()));
1276         Self::add_lld_flags(builder, compiler.host, &mut hostflags);
1277         cmd.arg("--host-rustcflags").arg(hostflags.join(" "));
1278
1279         let mut targetflags = flags;
1280         targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
1281         Self::add_lld_flags(builder, target, &mut targetflags);
1282         cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
1283
1284         cmd.arg("--docck-python").arg(builder.python());
1285
1286         if builder.config.build.ends_with("apple-darwin") {
1287             // Force /usr/bin/python3 on macOS for LLDB tests because we're loading the
1288             // LLDB plugin's compiled module which only works with the system python
1289             // (namely not Homebrew-installed python)
1290             cmd.arg("--lldb-python").arg("/usr/bin/python3");
1291         } else {
1292             cmd.arg("--lldb-python").arg(builder.python());
1293         }
1294
1295         if let Some(ref gdb) = builder.config.gdb {
1296             cmd.arg("--gdb").arg(gdb);
1297         }
1298
1299         let run = |cmd: &mut Command| {
1300             cmd.output().map(|output| {
1301                 String::from_utf8_lossy(&output.stdout)
1302                     .lines()
1303                     .next()
1304                     .unwrap_or_else(|| panic!("{:?} failed {:?}", cmd, output))
1305                     .to_string()
1306             })
1307         };
1308         let lldb_exe = "lldb";
1309         let lldb_version = Command::new(lldb_exe)
1310             .arg("--version")
1311             .output()
1312             .map(|output| String::from_utf8_lossy(&output.stdout).to_string())
1313             .ok();
1314         if let Some(ref vers) = lldb_version {
1315             cmd.arg("--lldb-version").arg(vers);
1316             let lldb_python_dir = run(Command::new(lldb_exe).arg("-P")).ok();
1317             if let Some(ref dir) = lldb_python_dir {
1318                 cmd.arg("--lldb-python-dir").arg(dir);
1319             }
1320         }
1321
1322         if util::forcing_clang_based_tests() {
1323             let clang_exe = builder.llvm_out(target).join("bin").join("clang");
1324             cmd.arg("--run-clang-based-tests-with").arg(clang_exe);
1325         }
1326
1327         // Get paths from cmd args
1328         let paths = match &builder.config.cmd {
1329             Subcommand::Test { ref paths, .. } => &paths[..],
1330             _ => &[],
1331         };
1332
1333         // Get test-args by striping suite path
1334         let mut test_args: Vec<&str> = paths
1335             .iter()
1336             .map(|p| match p.strip_prefix(".") {
1337                 Ok(path) => path,
1338                 Err(_) => p,
1339             })
1340             .filter(|p| p.starts_with(suite_path))
1341             .filter(|p| {
1342                 let exists = p.is_dir() || p.is_file();
1343                 if !exists {
1344                     if let Some(p) = p.to_str() {
1345                         builder.info(&format!(
1346                             "Warning: Skipping \"{}\": not a regular file or directory",
1347                             p
1348                         ));
1349                     }
1350                 }
1351                 exists
1352             })
1353             .filter_map(|p| {
1354                 // Since test suite paths are themselves directories, if we don't
1355                 // specify a directory or file, we'll get an empty string here
1356                 // (the result of the test suite directory without its suite prefix).
1357                 // Therefore, we need to filter these out, as only the first --test-args
1358                 // flag is respected, so providing an empty --test-args conflicts with
1359                 // any following it.
1360                 match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
1361                     Some(s) if !s.is_empty() => Some(s),
1362                     _ => None,
1363                 }
1364             })
1365             .collect();
1366
1367         test_args.append(&mut builder.config.cmd.test_args());
1368
1369         cmd.args(&test_args);
1370
1371         if builder.is_verbose() {
1372             cmd.arg("--verbose");
1373         }
1374
1375         if !builder.config.verbose_tests {
1376             cmd.arg("--quiet");
1377         }
1378
1379         let mut llvm_components_passed = false;
1380         let mut copts_passed = false;
1381         if builder.config.llvm_enabled() {
1382             let llvm_config = builder.ensure(native::Llvm { target: builder.config.build });
1383             if !builder.config.dry_run {
1384                 let llvm_version = output(Command::new(&llvm_config).arg("--version"));
1385                 let llvm_components = output(Command::new(&llvm_config).arg("--components"));
1386                 // Remove trailing newline from llvm-config output.
1387                 cmd.arg("--llvm-version")
1388                     .arg(llvm_version.trim())
1389                     .arg("--llvm-components")
1390                     .arg(llvm_components.trim());
1391                 llvm_components_passed = true;
1392             }
1393             if !builder.is_rust_llvm(target) {
1394                 cmd.arg("--system-llvm");
1395             }
1396
1397             // Tests that use compiler libraries may inherit the `-lLLVM` link
1398             // requirement, but the `-L` library path is not propagated across
1399             // separate compilations. We can add LLVM's library path to the
1400             // platform-specific environment variable as a workaround.
1401             if !builder.config.dry_run && suite.ends_with("fulldeps") {
1402                 let llvm_libdir = output(Command::new(&llvm_config).arg("--libdir"));
1403                 add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cmd);
1404             }
1405
1406             // Only pass correct values for these flags for the `run-make` suite as it
1407             // requires that a C++ compiler was configured which isn't always the case.
1408             if !builder.config.dry_run && matches!(suite, "run-make" | "run-make-fulldeps") {
1409                 // The llvm/bin directory contains many useful cross-platform
1410                 // tools. Pass the path to run-make tests so they can use them.
1411                 let llvm_bin_path = llvm_config
1412                     .parent()
1413                     .expect("Expected llvm-config to be contained in directory");
1414                 assert!(llvm_bin_path.is_dir());
1415                 cmd.arg("--llvm-bin-dir").arg(llvm_bin_path);
1416
1417                 // If LLD is available, add it to the PATH
1418                 if builder.config.lld_enabled {
1419                     let lld_install_root =
1420                         builder.ensure(native::Lld { target: builder.config.build });
1421
1422                     let lld_bin_path = lld_install_root.join("bin");
1423
1424                     let old_path = env::var_os("PATH").unwrap_or_default();
1425                     let new_path = env::join_paths(
1426                         std::iter::once(lld_bin_path).chain(env::split_paths(&old_path)),
1427                     )
1428                     .expect("Could not add LLD bin path to PATH");
1429                     cmd.env("PATH", new_path);
1430                 }
1431             }
1432         }
1433
1434         // Only pass correct values for these flags for the `run-make` suite as it
1435         // requires that a C++ compiler was configured which isn't always the case.
1436         if !builder.config.dry_run && matches!(suite, "run-make" | "run-make-fulldeps") {
1437             cmd.arg("--cc")
1438                 .arg(builder.cc(target))
1439                 .arg("--cxx")
1440                 .arg(builder.cxx(target).unwrap())
1441                 .arg("--cflags")
1442                 .arg(builder.cflags(target, GitRepo::Rustc).join(" "));
1443             copts_passed = true;
1444             if let Some(ar) = builder.ar(target) {
1445                 cmd.arg("--ar").arg(ar);
1446             }
1447         }
1448
1449         if !llvm_components_passed {
1450             cmd.arg("--llvm-components").arg("");
1451         }
1452         if !copts_passed {
1453             cmd.arg("--cc").arg("").arg("--cxx").arg("").arg("--cflags").arg("");
1454         }
1455
1456         if builder.remote_tested(target) {
1457             cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient));
1458         }
1459
1460         // Running a C compiler on MSVC requires a few env vars to be set, to be
1461         // sure to set them here.
1462         //
1463         // Note that if we encounter `PATH` we make sure to append to our own `PATH`
1464         // rather than stomp over it.
1465         if target.contains("msvc") {
1466             for &(ref k, ref v) in builder.cc[&target].env() {
1467                 if k != "PATH" {
1468                     cmd.env(k, v);
1469                 }
1470             }
1471         }
1472         cmd.env("RUSTC_BOOTSTRAP", "1");
1473         builder.add_rust_test_threads(&mut cmd);
1474
1475         if builder.config.sanitizers_enabled(target) {
1476             cmd.env("RUSTC_SANITIZER_SUPPORT", "1");
1477         }
1478
1479         if builder.config.profiler_enabled(target) {
1480             cmd.env("RUSTC_PROFILER_SUPPORT", "1");
1481         }
1482
1483         let tmp = builder.out.join("tmp");
1484         std::fs::create_dir_all(&tmp).unwrap();
1485         cmd.env("RUST_TEST_TMPDIR", tmp);
1486
1487         cmd.arg("--adb-path").arg("adb");
1488         cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
1489         if target.contains("android") {
1490             // Assume that cc for this target comes from the android sysroot
1491             cmd.arg("--android-cross-path")
1492                 .arg(builder.cc(target).parent().unwrap().parent().unwrap());
1493         } else {
1494             cmd.arg("--android-cross-path").arg("");
1495         }
1496
1497         if builder.config.cmd.rustfix_coverage() {
1498             cmd.arg("--rustfix-coverage");
1499         }
1500
1501         cmd.env("BOOTSTRAP_CARGO", &builder.initial_cargo);
1502
1503         builder.ci_env.force_coloring_in_ci(&mut cmd);
1504
1505         builder.info(&format!(
1506             "Check compiletest suite={} mode={} ({} -> {})",
1507             suite, mode, &compiler.host, target
1508         ));
1509         let _time = util::timeit(&builder);
1510         try_run(builder, &mut cmd);
1511
1512         if let Some(compare_mode) = compare_mode {
1513             cmd.arg("--compare-mode").arg(compare_mode);
1514             builder.info(&format!(
1515                 "Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
1516                 suite, mode, compare_mode, &compiler.host, target
1517             ));
1518             let _time = util::timeit(&builder);
1519             try_run(builder, &mut cmd);
1520         }
1521     }
1522 }
1523
1524 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
1525 struct BookTest {
1526     compiler: Compiler,
1527     path: PathBuf,
1528     name: &'static str,
1529     is_ext_doc: bool,
1530 }
1531
1532 impl Step for BookTest {
1533     type Output = ();
1534     const ONLY_HOSTS: bool = true;
1535
1536     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1537         run.never()
1538     }
1539
1540     /// Runs the documentation tests for a book in `src/doc`.
1541     ///
1542     /// This uses the `rustdoc` that sits next to `compiler`.
1543     fn run(self, builder: &Builder<'_>) {
1544         // External docs are different from local because:
1545         // - Some books need pre-processing by mdbook before being tested.
1546         // - They need to save their state to toolstate.
1547         // - They are only tested on the "checktools" builders.
1548         //
1549         // The local docs are tested by default, and we don't want to pay the
1550         // cost of building mdbook, so they use `rustdoc --test` directly.
1551         // Also, the unstable book is special because SUMMARY.md is generated,
1552         // so it is easier to just run `rustdoc` on its files.
1553         if self.is_ext_doc {
1554             self.run_ext_doc(builder);
1555         } else {
1556             self.run_local_doc(builder);
1557         }
1558     }
1559 }
1560
1561 impl BookTest {
1562     /// This runs the equivalent of `mdbook test` (via the rustbook wrapper)
1563     /// which in turn runs `rustdoc --test` on each file in the book.
1564     fn run_ext_doc(self, builder: &Builder<'_>) {
1565         let compiler = self.compiler;
1566
1567         builder.ensure(compile::Std { compiler, target: compiler.host });
1568
1569         // mdbook just executes a binary named "rustdoc", so we need to update
1570         // PATH so that it points to our rustdoc.
1571         let mut rustdoc_path = builder.rustdoc(compiler);
1572         rustdoc_path.pop();
1573         let old_path = env::var_os("PATH").unwrap_or_default();
1574         let new_path = env::join_paths(iter::once(rustdoc_path).chain(env::split_paths(&old_path)))
1575             .expect("could not add rustdoc to PATH");
1576
1577         let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
1578         let path = builder.src.join(&self.path);
1579         rustbook_cmd.env("PATH", new_path).arg("test").arg(path);
1580         builder.add_rust_test_threads(&mut rustbook_cmd);
1581         builder.info(&format!("Testing rustbook {}", self.path.display()));
1582         let _time = util::timeit(&builder);
1583         let toolstate = if try_run(builder, &mut rustbook_cmd) {
1584             ToolState::TestPass
1585         } else {
1586             ToolState::TestFail
1587         };
1588         builder.save_toolstate(self.name, toolstate);
1589     }
1590
1591     /// This runs `rustdoc --test` on all `.md` files in the path.
1592     fn run_local_doc(self, builder: &Builder<'_>) {
1593         let compiler = self.compiler;
1594
1595         builder.ensure(compile::Std { compiler, target: compiler.host });
1596
1597         // Do a breadth-first traversal of the `src/doc` directory and just run
1598         // tests for all files that end in `*.md`
1599         let mut stack = vec![builder.src.join(self.path)];
1600         let _time = util::timeit(&builder);
1601         let mut files = Vec::new();
1602         while let Some(p) = stack.pop() {
1603             if p.is_dir() {
1604                 stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
1605                 continue;
1606             }
1607
1608             if p.extension().and_then(|s| s.to_str()) != Some("md") {
1609                 continue;
1610             }
1611
1612             files.push(p);
1613         }
1614
1615         files.sort();
1616
1617         for file in files {
1618             markdown_test(builder, compiler, &file);
1619         }
1620     }
1621 }
1622
1623 macro_rules! test_book {
1624     ($($name:ident, $path:expr, $book_name:expr, default=$default:expr;)+) => {
1625         $(
1626             #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1627             pub struct $name {
1628                 compiler: Compiler,
1629             }
1630
1631             impl Step for $name {
1632                 type Output = ();
1633                 const DEFAULT: bool = $default;
1634                 const ONLY_HOSTS: bool = true;
1635
1636                 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1637                     run.path($path)
1638                 }
1639
1640                 fn make_run(run: RunConfig<'_>) {
1641                     run.builder.ensure($name {
1642                         compiler: run.builder.compiler(run.builder.top_stage, run.target),
1643                     });
1644                 }
1645
1646                 fn run(self, builder: &Builder<'_>) {
1647                     builder.ensure(BookTest {
1648                         compiler: self.compiler,
1649                         path: PathBuf::from($path),
1650                         name: $book_name,
1651                         is_ext_doc: !$default,
1652                     });
1653                 }
1654             }
1655         )+
1656     }
1657 }
1658
1659 test_book!(
1660     Nomicon, "src/doc/nomicon", "nomicon", default=false;
1661     Reference, "src/doc/reference", "reference", default=false;
1662     RustdocBook, "src/doc/rustdoc", "rustdoc", default=true;
1663     RustcBook, "src/doc/rustc", "rustc", default=true;
1664     RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false;
1665     EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false;
1666     TheBook, "src/doc/book", "book", default=false;
1667     UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
1668     EditionGuide, "src/doc/edition-guide", "edition-guide", default=false;
1669 );
1670
1671 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1672 pub struct ErrorIndex {
1673     compiler: Compiler,
1674 }
1675
1676 impl Step for ErrorIndex {
1677     type Output = ();
1678     const DEFAULT: bool = true;
1679     const ONLY_HOSTS: bool = true;
1680
1681     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1682         run.path("src/tools/error_index_generator")
1683     }
1684
1685     fn make_run(run: RunConfig<'_>) {
1686         // error_index_generator depends on librustdoc. Use the compiler that
1687         // is normally used to build rustdoc for other tests (like compiletest
1688         // tests in src/test/rustdoc) so that it shares the same artifacts.
1689         let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.build);
1690         run.builder.ensure(ErrorIndex { compiler });
1691     }
1692
1693     /// Runs the error index generator tool to execute the tests located in the error
1694     /// index.
1695     ///
1696     /// The `error_index_generator` tool lives in `src/tools` and is used to
1697     /// generate a markdown file from the error indexes of the code base which is
1698     /// then passed to `rustdoc --test`.
1699     fn run(self, builder: &Builder<'_>) {
1700         let compiler = self.compiler;
1701
1702         let dir = testdir(builder, compiler.host);
1703         t!(fs::create_dir_all(&dir));
1704         let output = dir.join("error-index.md");
1705
1706         let mut tool = tool::ErrorIndex::command(builder);
1707         tool.arg("markdown").arg(&output);
1708
1709         builder.info(&format!("Testing error-index stage{}", compiler.stage));
1710         let _time = util::timeit(&builder);
1711         builder.run_quiet(&mut tool);
1712         // The tests themselves need to link to std, so make sure it is
1713         // available.
1714         builder.ensure(compile::Std { compiler, target: compiler.host });
1715         markdown_test(builder, compiler, &output);
1716     }
1717 }
1718
1719 fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool {
1720     if let Ok(contents) = fs::read_to_string(markdown) {
1721         if !contents.contains("```") {
1722             return true;
1723         }
1724     }
1725
1726     builder.info(&format!("doc tests for: {}", markdown.display()));
1727     let mut cmd = builder.rustdoc_cmd(compiler);
1728     builder.add_rust_test_threads(&mut cmd);
1729     // allow for unstable options such as new editions
1730     cmd.arg("-Z");
1731     cmd.arg("unstable-options");
1732     cmd.arg("--test");
1733     cmd.arg(markdown);
1734     cmd.env("RUSTC_BOOTSTRAP", "1");
1735
1736     let test_args = builder.config.cmd.test_args().join(" ");
1737     cmd.arg("--test-args").arg(test_args);
1738
1739     if builder.config.verbose_tests {
1740         try_run(builder, &mut cmd)
1741     } else {
1742         try_run_quiet(builder, &mut cmd)
1743     }
1744 }
1745
1746 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1747 pub struct RustcGuide;
1748
1749 impl Step for RustcGuide {
1750     type Output = ();
1751     const DEFAULT: bool = false;
1752     const ONLY_HOSTS: bool = true;
1753
1754     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1755         run.path("src/doc/rustc-dev-guide")
1756     }
1757
1758     fn make_run(run: RunConfig<'_>) {
1759         run.builder.ensure(RustcGuide);
1760     }
1761
1762     fn run(self, builder: &Builder<'_>) {
1763         let src = builder.src.join("src/doc/rustc-dev-guide");
1764         let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
1765         let toolstate = if try_run(builder, rustbook_cmd.arg("linkcheck").arg(&src)) {
1766             ToolState::TestPass
1767         } else {
1768             ToolState::TestFail
1769         };
1770         builder.save_toolstate("rustc-dev-guide", toolstate);
1771     }
1772 }
1773
1774 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1775 pub struct CrateLibrustc {
1776     compiler: Compiler,
1777     target: TargetSelection,
1778     test_kind: TestKind,
1779     krate: Interned<String>,
1780 }
1781
1782 impl Step for CrateLibrustc {
1783     type Output = ();
1784     const DEFAULT: bool = true;
1785     const ONLY_HOSTS: bool = true;
1786
1787     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1788         run.krate("rustc-main")
1789     }
1790
1791     fn make_run(run: RunConfig<'_>) {
1792         let builder = run.builder;
1793         let compiler = builder.compiler(builder.top_stage, run.build_triple());
1794
1795         for krate in builder.in_tree_crates("rustc-main", Some(run.target)) {
1796             if krate.path.ends_with(&run.path) {
1797                 let test_kind = builder.kind.into();
1798
1799                 builder.ensure(CrateLibrustc {
1800                     compiler,
1801                     target: run.target,
1802                     test_kind,
1803                     krate: krate.name,
1804                 });
1805             }
1806         }
1807     }
1808
1809     fn run(self, builder: &Builder<'_>) {
1810         builder.ensure(Crate {
1811             compiler: self.compiler,
1812             target: self.target,
1813             mode: Mode::Rustc,
1814             test_kind: self.test_kind,
1815             krate: self.krate,
1816         });
1817     }
1818 }
1819
1820 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1821 pub struct Crate {
1822     pub compiler: Compiler,
1823     pub target: TargetSelection,
1824     pub mode: Mode,
1825     pub test_kind: TestKind,
1826     pub krate: Interned<String>,
1827 }
1828
1829 impl Step for Crate {
1830     type Output = ();
1831     const DEFAULT: bool = true;
1832
1833     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1834         run.krate("test")
1835     }
1836
1837     fn make_run(run: RunConfig<'_>) {
1838         let builder = run.builder;
1839         let compiler = builder.compiler(builder.top_stage, run.build_triple());
1840
1841         let make = |mode: Mode, krate: &CargoCrate| {
1842             let test_kind = builder.kind.into();
1843
1844             builder.ensure(Crate {
1845                 compiler,
1846                 target: run.target,
1847                 mode,
1848                 test_kind,
1849                 krate: krate.name,
1850             });
1851         };
1852
1853         for krate in builder.in_tree_crates("test", Some(run.target)) {
1854             if krate.path.ends_with(&run.path) {
1855                 make(Mode::Std, krate);
1856             }
1857         }
1858     }
1859
1860     /// Runs all unit tests plus documentation tests for a given crate defined
1861     /// by a `Cargo.toml` (single manifest)
1862     ///
1863     /// This is what runs tests for crates like the standard library, compiler, etc.
1864     /// It essentially is the driver for running `cargo test`.
1865     ///
1866     /// Currently this runs all tests for a DAG by passing a bunch of `-p foo`
1867     /// arguments, and those arguments are discovered from `cargo metadata`.
1868     fn run(self, builder: &Builder<'_>) {
1869         let compiler = self.compiler;
1870         let target = self.target;
1871         let mode = self.mode;
1872         let test_kind = self.test_kind;
1873         let krate = self.krate;
1874
1875         builder.ensure(compile::Std { compiler, target });
1876         builder.ensure(RemoteCopyLibs { compiler, target });
1877
1878         // If we're not doing a full bootstrap but we're testing a stage2
1879         // version of libstd, then what we're actually testing is the libstd
1880         // produced in stage1. Reflect that here by updating the compiler that
1881         // we're working with automatically.
1882         let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
1883
1884         let mut cargo =
1885             builder.cargo(compiler, mode, SourceType::InTree, target, test_kind.subcommand());
1886         match mode {
1887             Mode::Std => {
1888                 compile::std_cargo(builder, target, compiler.stage, &mut cargo);
1889             }
1890             Mode::Rustc => {
1891                 builder.ensure(compile::Rustc { compiler, target });
1892                 compile::rustc_cargo(builder, &mut cargo, target);
1893             }
1894             _ => panic!("can only test libraries"),
1895         };
1896
1897         // Build up the base `cargo test` command.
1898         //
1899         // Pass in some standard flags then iterate over the graph we've discovered
1900         // in `cargo metadata` with the maps above and figure out what `-p`
1901         // arguments need to get passed.
1902         if test_kind.subcommand() == "test" && !builder.fail_fast {
1903             cargo.arg("--no-fail-fast");
1904         }
1905         match builder.doc_tests {
1906             DocTests::Only => {
1907                 cargo.arg("--doc");
1908             }
1909             DocTests::No => {
1910                 cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
1911             }
1912             DocTests::Yes => {}
1913         }
1914
1915         cargo.arg("-p").arg(krate);
1916
1917         // The tests are going to run with the *target* libraries, so we need to
1918         // ensure that those libraries show up in the LD_LIBRARY_PATH equivalent.
1919         //
1920         // Note that to run the compiler we need to run with the *host* libraries,
1921         // but our wrapper scripts arrange for that to be the case anyway.
1922         let mut dylib_path = dylib_path();
1923         dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target)));
1924         cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
1925
1926         cargo.arg("--");
1927         cargo.args(&builder.config.cmd.test_args());
1928
1929         if !builder.config.verbose_tests {
1930             cargo.arg("--quiet");
1931         }
1932
1933         if target.contains("emscripten") {
1934             cargo.env(
1935                 format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
1936                 builder.config.nodejs.as_ref().expect("nodejs not configured"),
1937             );
1938         } else if target.starts_with("wasm32") {
1939             let node = builder.config.nodejs.as_ref().expect("nodejs not configured");
1940             let runner =
1941                 format!("{} {}/src/etc/wasm32-shim.js", node.display(), builder.src.display());
1942             cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), &runner);
1943         } else if builder.remote_tested(target) {
1944             cargo.env(
1945                 format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
1946                 format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
1947             );
1948         }
1949
1950         builder.info(&format!(
1951             "{} {} stage{} ({} -> {})",
1952             test_kind, krate, compiler.stage, &compiler.host, target
1953         ));
1954         let _time = util::timeit(&builder);
1955         try_run(builder, &mut cargo.into());
1956     }
1957 }
1958
1959 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1960 pub struct CrateRustdoc {
1961     host: TargetSelection,
1962     test_kind: TestKind,
1963 }
1964
1965 impl Step for CrateRustdoc {
1966     type Output = ();
1967     const DEFAULT: bool = true;
1968     const ONLY_HOSTS: bool = true;
1969
1970     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1971         run.paths(&["src/librustdoc", "src/tools/rustdoc"])
1972     }
1973
1974     fn make_run(run: RunConfig<'_>) {
1975         let builder = run.builder;
1976
1977         let test_kind = builder.kind.into();
1978
1979         builder.ensure(CrateRustdoc { host: run.target, test_kind });
1980     }
1981
1982     fn run(self, builder: &Builder<'_>) {
1983         let test_kind = self.test_kind;
1984         let target = self.host;
1985
1986         // Use the previous stage compiler to reuse the artifacts that are
1987         // created when running compiletest for src/test/rustdoc. If this used
1988         // `compiler`, then it would cause rustdoc to be built *again*, which
1989         // isn't really necessary.
1990         let compiler = builder.compiler_for(builder.top_stage, target, target);
1991         builder.ensure(compile::Rustc { compiler, target });
1992
1993         let mut cargo = tool::prepare_tool_cargo(
1994             builder,
1995             compiler,
1996             Mode::ToolRustc,
1997             target,
1998             test_kind.subcommand(),
1999             "src/tools/rustdoc",
2000             SourceType::InTree,
2001             &[],
2002         );
2003         if test_kind.subcommand() == "test" && !builder.fail_fast {
2004             cargo.arg("--no-fail-fast");
2005         }
2006
2007         cargo.arg("-p").arg("rustdoc:0.0.0");
2008
2009         cargo.arg("--");
2010         cargo.args(&builder.config.cmd.test_args());
2011
2012         if self.host.contains("musl") {
2013             cargo.arg("'-Ctarget-feature=-crt-static'");
2014         }
2015
2016         // This is needed for running doctests on librustdoc. This is a bit of
2017         // an unfortunate interaction with how bootstrap works and how cargo
2018         // sets up the dylib path, and the fact that the doctest (in
2019         // html/markdown.rs) links to rustc-private libs. For stage1, the
2020         // compiler host dylibs (in stage1/lib) are not the same as the target
2021         // dylibs (in stage1/lib/rustlib/...). This is different from a normal
2022         // rust distribution where they are the same.
2023         //
2024         // On the cargo side, normal tests use `target_process` which handles
2025         // setting up the dylib for a *target* (stage1/lib/rustlib/... in this
2026         // case). However, for doctests it uses `rustdoc_process` which only
2027         // sets up the dylib path for the *host* (stage1/lib), which is the
2028         // wrong directory.
2029         //
2030         // It should be considered to just stop running doctests on
2031         // librustdoc. There is only one test, and it doesn't look too
2032         // important. There might be other ways to avoid this, but it seems
2033         // pretty convoluted.
2034         //
2035         // See also https://github.com/rust-lang/rust/issues/13983 where the
2036         // host vs target dylibs for rustdoc are consistently tricky to deal
2037         // with.
2038         let mut dylib_path = dylib_path();
2039         dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target)));
2040         cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
2041
2042         if !builder.config.verbose_tests {
2043             cargo.arg("--quiet");
2044         }
2045
2046         builder.info(&format!(
2047             "{} rustdoc stage{} ({} -> {})",
2048             test_kind, compiler.stage, &compiler.host, target
2049         ));
2050         let _time = util::timeit(&builder);
2051
2052         try_run(builder, &mut cargo.into());
2053     }
2054 }
2055
2056 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2057 pub struct CrateRustdocJsonTypes {
2058     host: TargetSelection,
2059     test_kind: TestKind,
2060 }
2061
2062 impl Step for CrateRustdocJsonTypes {
2063     type Output = ();
2064     const DEFAULT: bool = true;
2065     const ONLY_HOSTS: bool = true;
2066
2067     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2068         run.path("src/rustdoc-json-types")
2069     }
2070
2071     fn make_run(run: RunConfig<'_>) {
2072         let builder = run.builder;
2073
2074         let test_kind = builder.kind.into();
2075
2076         builder.ensure(CrateRustdocJsonTypes { host: run.target, test_kind });
2077     }
2078
2079     fn run(self, builder: &Builder<'_>) {
2080         let test_kind = self.test_kind;
2081         let target = self.host;
2082
2083         // Use the previous stage compiler to reuse the artifacts that are
2084         // created when running compiletest for src/test/rustdoc. If this used
2085         // `compiler`, then it would cause rustdoc to be built *again*, which
2086         // isn't really necessary.
2087         let compiler = builder.compiler_for(builder.top_stage, target, target);
2088         builder.ensure(compile::Rustc { compiler, target });
2089
2090         let mut cargo = tool::prepare_tool_cargo(
2091             builder,
2092             compiler,
2093             Mode::ToolRustc,
2094             target,
2095             test_kind.subcommand(),
2096             "src/rustdoc-json-types",
2097             SourceType::InTree,
2098             &[],
2099         );
2100         if test_kind.subcommand() == "test" && !builder.fail_fast {
2101             cargo.arg("--no-fail-fast");
2102         }
2103
2104         cargo.arg("-p").arg("rustdoc-json-types");
2105
2106         cargo.arg("--");
2107         cargo.args(&builder.config.cmd.test_args());
2108
2109         if self.host.contains("musl") {
2110             cargo.arg("'-Ctarget-feature=-crt-static'");
2111         }
2112
2113         if !builder.config.verbose_tests {
2114             cargo.arg("--quiet");
2115         }
2116
2117         builder.info(&format!(
2118             "{} rustdoc-json-types stage{} ({} -> {})",
2119             test_kind, compiler.stage, &compiler.host, target
2120         ));
2121         let _time = util::timeit(&builder);
2122
2123         try_run(builder, &mut cargo.into());
2124     }
2125 }
2126
2127 /// Some test suites are run inside emulators or on remote devices, and most
2128 /// of our test binaries are linked dynamically which means we need to ship
2129 /// the standard library and such to the emulator ahead of time. This step
2130 /// represents this and is a dependency of all test suites.
2131 ///
2132 /// Most of the time this is a no-op. For some steps such as shipping data to
2133 /// QEMU we have to build our own tools so we've got conditional dependencies
2134 /// on those programs as well. Note that the remote test client is built for
2135 /// the build target (us) and the server is built for the target.
2136 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2137 pub struct RemoteCopyLibs {
2138     compiler: Compiler,
2139     target: TargetSelection,
2140 }
2141
2142 impl Step for RemoteCopyLibs {
2143     type Output = ();
2144
2145     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2146         run.never()
2147     }
2148
2149     fn run(self, builder: &Builder<'_>) {
2150         let compiler = self.compiler;
2151         let target = self.target;
2152         if !builder.remote_tested(target) {
2153             return;
2154         }
2155
2156         builder.ensure(compile::Std { compiler, target });
2157
2158         builder.info(&format!("REMOTE copy libs to emulator ({})", target));
2159         t!(fs::create_dir_all(builder.out.join("tmp")));
2160
2161         let server = builder.ensure(tool::RemoteTestServer { compiler, target });
2162
2163         // Spawn the emulator and wait for it to come online
2164         let tool = builder.tool_exe(Tool::RemoteTestClient);
2165         let mut cmd = Command::new(&tool);
2166         cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.out.join("tmp"));
2167         if let Some(rootfs) = builder.qemu_rootfs(target) {
2168             cmd.arg(rootfs);
2169         }
2170         builder.run(&mut cmd);
2171
2172         // Push all our dylibs to the emulator
2173         for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) {
2174             let f = t!(f);
2175             let name = f.file_name().into_string().unwrap();
2176             if util::is_dylib(&name) {
2177                 builder.run(Command::new(&tool).arg("push").arg(f.path()));
2178             }
2179         }
2180     }
2181 }
2182
2183 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2184 pub struct Distcheck;
2185
2186 impl Step for Distcheck {
2187     type Output = ();
2188
2189     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2190         run.path("distcheck")
2191     }
2192
2193     fn make_run(run: RunConfig<'_>) {
2194         run.builder.ensure(Distcheck);
2195     }
2196
2197     /// Runs "distcheck", a 'make check' from a tarball
2198     fn run(self, builder: &Builder<'_>) {
2199         builder.info("Distcheck");
2200         let dir = builder.out.join("tmp").join("distcheck");
2201         let _ = fs::remove_dir_all(&dir);
2202         t!(fs::create_dir_all(&dir));
2203
2204         // Guarantee that these are built before we begin running.
2205         builder.ensure(dist::PlainSourceTarball);
2206         builder.ensure(dist::Src);
2207
2208         let mut cmd = Command::new("tar");
2209         cmd.arg("-xf")
2210             .arg(builder.ensure(dist::PlainSourceTarball).tarball())
2211             .arg("--strip-components=1")
2212             .current_dir(&dir);
2213         builder.run(&mut cmd);
2214         builder.run(
2215             Command::new("./configure")
2216                 .args(&builder.config.configure_args)
2217                 .arg("--enable-vendor")
2218                 .current_dir(&dir),
2219         );
2220         builder.run(
2221             Command::new(build_helper::make(&builder.config.build.triple))
2222                 .arg("check")
2223                 .current_dir(&dir),
2224         );
2225
2226         // Now make sure that rust-src has all of libstd's dependencies
2227         builder.info("Distcheck rust-src");
2228         let dir = builder.out.join("tmp").join("distcheck-src");
2229         let _ = fs::remove_dir_all(&dir);
2230         t!(fs::create_dir_all(&dir));
2231
2232         let mut cmd = Command::new("tar");
2233         cmd.arg("-xf")
2234             .arg(builder.ensure(dist::Src).tarball())
2235             .arg("--strip-components=1")
2236             .current_dir(&dir);
2237         builder.run(&mut cmd);
2238
2239         let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml");
2240         builder.run(
2241             Command::new(&builder.initial_cargo)
2242                 .arg("generate-lockfile")
2243                 .arg("--manifest-path")
2244                 .arg(&toml)
2245                 .current_dir(&dir),
2246         );
2247     }
2248 }
2249
2250 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2251 pub struct Bootstrap;
2252
2253 impl Step for Bootstrap {
2254     type Output = ();
2255     const DEFAULT: bool = true;
2256     const ONLY_HOSTS: bool = true;
2257
2258     /// Tests the build system itself.
2259     fn run(self, builder: &Builder<'_>) {
2260         let mut cmd = Command::new(&builder.initial_cargo);
2261         cmd.arg("test")
2262             .current_dir(builder.src.join("src/bootstrap"))
2263             .env("RUSTFLAGS", "-Cdebuginfo=2")
2264             .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
2265             .env("BOOTSTRAP_OUTPUT_DIRECTORY", &builder.config.out)
2266             .env("BOOTSTRAP_INITIAL_CARGO", &builder.config.initial_cargo)
2267             .env("RUSTC_BOOTSTRAP", "1")
2268             .env("RUSTC", &builder.initial_rustc);
2269         if let Some(flags) = option_env!("RUSTFLAGS") {
2270             // Use the same rustc flags for testing as for "normal" compilation,
2271             // so that Cargo doesn’t recompile the entire dependency graph every time:
2272             // https://github.com/rust-lang/rust/issues/49215
2273             cmd.env("RUSTFLAGS", flags);
2274         }
2275         if !builder.fail_fast {
2276             cmd.arg("--no-fail-fast");
2277         }
2278         cmd.arg("--").args(&builder.config.cmd.test_args());
2279         // rustbuild tests are racy on directory creation so just run them one at a time.
2280         // Since there's not many this shouldn't be a problem.
2281         cmd.arg("--test-threads=1");
2282         try_run(builder, &mut cmd);
2283     }
2284
2285     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2286         run.path("src/bootstrap")
2287     }
2288
2289     fn make_run(run: RunConfig<'_>) {
2290         run.builder.ensure(Bootstrap);
2291     }
2292 }
2293
2294 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2295 pub struct TierCheck {
2296     pub compiler: Compiler,
2297 }
2298
2299 impl Step for TierCheck {
2300     type Output = ();
2301     const DEFAULT: bool = true;
2302     const ONLY_HOSTS: bool = true;
2303
2304     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2305         run.path("src/tools/tier-check")
2306     }
2307
2308     fn make_run(run: RunConfig<'_>) {
2309         let compiler =
2310             run.builder.compiler_for(run.builder.top_stage, run.builder.build.build, run.target);
2311         run.builder.ensure(TierCheck { compiler });
2312     }
2313
2314     /// Tests the Platform Support page in the rustc book.
2315     fn run(self, builder: &Builder<'_>) {
2316         builder.ensure(compile::Std { compiler: self.compiler, target: self.compiler.host });
2317         let mut cargo = tool::prepare_tool_cargo(
2318             builder,
2319             self.compiler,
2320             Mode::ToolStd,
2321             self.compiler.host,
2322             "run",
2323             "src/tools/tier-check",
2324             SourceType::InTree,
2325             &[],
2326         );
2327         cargo.arg(builder.src.join("src/doc/rustc/src/platform-support.md"));
2328         cargo.arg(&builder.rustc(self.compiler));
2329         if builder.is_verbose() {
2330             cargo.arg("--verbose");
2331         }
2332
2333         builder.info("platform support check");
2334         try_run(builder, &mut cargo.into());
2335     }
2336 }
2337
2338 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2339 pub struct LintDocs {
2340     pub compiler: Compiler,
2341     pub target: TargetSelection,
2342 }
2343
2344 impl Step for LintDocs {
2345     type Output = ();
2346     const DEFAULT: bool = true;
2347     const ONLY_HOSTS: bool = true;
2348
2349     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2350         run.path("src/tools/lint-docs")
2351     }
2352
2353     fn make_run(run: RunConfig<'_>) {
2354         run.builder.ensure(LintDocs {
2355             compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
2356             target: run.target,
2357         });
2358     }
2359
2360     /// Tests that the lint examples in the rustc book generate the correct
2361     /// lints and have the expected format.
2362     fn run(self, builder: &Builder<'_>) {
2363         builder.ensure(crate::doc::RustcBook {
2364             compiler: self.compiler,
2365             target: self.target,
2366             validate: true,
2367         });
2368     }
2369 }