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