1use std::collections::HashSet;
7use std::ffi::{OsStr, OsString};
8use std::path::{Path, PathBuf};
9use std::{env, fs, iter};
10
11#[cfg(feature = "tracing")]
12use tracing::instrument;
13
14use crate::core::build_steps::compile::{Std, run_cargo};
15use crate::core::build_steps::doc::DocumentationFormat;
16use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags};
17use crate::core::build_steps::llvm::get_llvm_version;
18use crate::core::build_steps::run::get_completion_paths;
19use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
20use crate::core::build_steps::tool::{self, COMPILETEST_ALLOW_FEATURES, SourceType, Tool};
21use crate::core::build_steps::toolstate::ToolState;
22use crate::core::build_steps::{compile, dist, llvm};
23use crate::core::builder::{
24 self, Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step, StepMetadata,
25 crate_description,
26};
27use crate::core::config::TargetSelection;
28use crate::core::config::flags::{Subcommand, get_completion};
29use crate::utils::build_stamp::{self, BuildStamp};
30use crate::utils::exec::{BootstrapCommand, command};
31use crate::utils::helpers::{
32 self, LldThreads, add_rustdoc_cargo_linker_args, dylib_path, dylib_path_var, linker_args,
33 linker_flags, t, target_supports_cranelift_backend, up_to_date,
34};
35use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests};
36use crate::{CLang, CodegenBackendKind, DocTests, GitRepo, Mode, PathSet, debug, envify};
37
38const ADB_TEST_DIR: &str = "/data/local/tmp/work";
39
40#[derive(Debug, Clone, PartialEq, Eq, Hash)]
42pub struct CrateBootstrap {
43 path: PathBuf,
44 host: TargetSelection,
45}
46
47impl Step for CrateBootstrap {
48 type Output = ();
49 const ONLY_HOSTS: bool = true;
50 const DEFAULT: bool = true;
51
52 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
53 run.path("src/tools/jsondoclint")
58 .path("src/tools/replace-version-placeholder")
59 .path("src/tools/coverage-dump")
60 .alias("tidyselftest")
63 }
64
65 fn make_run(run: RunConfig<'_>) {
66 for path in run.paths {
69 let path = path.assert_single_path().path.clone();
70 run.builder.ensure(CrateBootstrap { host: run.target, path });
71 }
72 }
73
74 fn run(self, builder: &Builder<'_>) {
75 let bootstrap_host = builder.config.host_target;
76 let compiler = builder.compiler(0, bootstrap_host);
77 let mut path = self.path.to_str().unwrap();
78
79 if path == "tidyselftest" {
81 path = "src/tools/tidy";
82 }
83
84 let cargo = tool::prepare_tool_cargo(
85 builder,
86 compiler,
87 Mode::ToolBootstrap,
88 bootstrap_host,
89 Kind::Test,
90 path,
91 SourceType::InTree,
92 &[],
93 );
94
95 let crate_name = path.rsplit_once('/').unwrap().1;
96 run_cargo_test(cargo, &[], &[], crate_name, bootstrap_host, builder);
97 }
98}
99
100#[derive(Debug, Clone, PartialEq, Eq, Hash)]
101pub struct Linkcheck {
102 host: TargetSelection,
103}
104
105impl Step for Linkcheck {
106 type Output = ();
107 const ONLY_HOSTS: bool = true;
108 const DEFAULT: bool = true;
109
110 fn run(self, builder: &Builder<'_>) {
115 let host = self.host;
116 let hosts = &builder.hosts;
117 let targets = &builder.targets;
118
119 if (hosts != targets) && !hosts.is_empty() && !targets.is_empty() {
124 panic!(
125 "Linkcheck currently does not support builds with different hosts and targets.
126You can skip linkcheck with --skip src/tools/linkchecker"
127 );
128 }
129
130 builder.info(&format!("Linkcheck ({host})"));
131
132 let bootstrap_host = builder.config.host_target;
134 let compiler = builder.compiler(0, bootstrap_host);
135
136 let cargo = tool::prepare_tool_cargo(
137 builder,
138 compiler,
139 Mode::ToolBootstrap,
140 bootstrap_host,
141 Kind::Test,
142 "src/tools/linkchecker",
143 SourceType::InTree,
144 &[],
145 );
146 run_cargo_test(cargo, &[], &[], "linkchecker self tests", bootstrap_host, builder);
147
148 if builder.doc_tests == DocTests::No {
149 return;
150 }
151
152 builder.default_doc(&[]);
154
155 let linkchecker = builder.tool_cmd(Tool::Linkchecker);
157
158 let _guard =
160 builder.msg(Kind::Test, compiler.stage, "Linkcheck", bootstrap_host, bootstrap_host);
161 let _time = helpers::timeit(builder);
162 linkchecker.delay_failure().arg(builder.out.join(host).join("doc")).run(builder);
163 }
164
165 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
166 let builder = run.builder;
167 let run = run.path("src/tools/linkchecker");
168 run.default_condition(builder.config.docs)
169 }
170
171 fn make_run(run: RunConfig<'_>) {
172 run.builder.ensure(Linkcheck { host: run.target });
173 }
174}
175
176fn check_if_tidy_is_installed(builder: &Builder<'_>) -> bool {
177 command("tidy").allow_failure().arg("--version").run_capture_stdout(builder).is_success()
178}
179
180#[derive(Debug, Clone, PartialEq, Eq, Hash)]
181pub struct HtmlCheck {
182 target: TargetSelection,
183}
184
185impl Step for HtmlCheck {
186 type Output = ();
187 const DEFAULT: bool = true;
188 const ONLY_HOSTS: bool = true;
189
190 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
191 let builder = run.builder;
192 let run = run.path("src/tools/html-checker");
193 run.lazy_default_condition(Box::new(|| check_if_tidy_is_installed(builder)))
194 }
195
196 fn make_run(run: RunConfig<'_>) {
197 run.builder.ensure(HtmlCheck { target: run.target });
198 }
199
200 fn run(self, builder: &Builder<'_>) {
201 if !check_if_tidy_is_installed(builder) {
202 eprintln!("not running HTML-check tool because `tidy` is missing");
203 eprintln!(
204 "You need the HTML tidy tool https://www.html-tidy.org/, this tool is *not* part of the rust project and needs to be installed separately, for example via your package manager."
205 );
206 panic!("Cannot run html-check tests");
207 }
208 builder.default_doc(&[]);
210 builder.ensure(crate::core::build_steps::doc::Rustc::new(
211 builder.top_stage,
212 self.target,
213 builder,
214 ));
215
216 builder
217 .tool_cmd(Tool::HtmlChecker)
218 .delay_failure()
219 .arg(builder.doc_out(self.target))
220 .run(builder);
221 }
222}
223
224#[derive(Debug, Clone, PartialEq, Eq, Hash)]
228pub struct Cargotest {
229 stage: u32,
230 host: TargetSelection,
231}
232
233impl Step for Cargotest {
234 type Output = ();
235 const ONLY_HOSTS: bool = true;
236
237 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
238 run.path("src/tools/cargotest")
239 }
240
241 fn make_run(run: RunConfig<'_>) {
242 run.builder.ensure(Cargotest { stage: run.builder.top_stage, host: run.target });
243 }
244
245 fn run(self, builder: &Builder<'_>) {
250 let compiler = builder.compiler(self.stage, self.host);
251 builder.ensure(compile::Rustc::new(compiler, compiler.host));
252 let cargo = builder.ensure(tool::Cargo { compiler, target: compiler.host });
253
254 let out_dir = builder.out.join("ct");
258 t!(fs::create_dir_all(&out_dir));
259
260 let _time = helpers::timeit(builder);
261 let mut cmd = builder.tool_cmd(Tool::CargoTest);
262 cmd.arg(&cargo.tool_path)
263 .arg(&out_dir)
264 .args(builder.config.test_args())
265 .env("RUSTC", builder.rustc(compiler))
266 .env("RUSTDOC", builder.rustdoc(compiler));
267 add_rustdoc_cargo_linker_args(
268 &mut cmd,
269 builder,
270 compiler.host,
271 LldThreads::No,
272 compiler.stage,
273 );
274 cmd.delay_failure().run(builder);
275 }
276}
277
278#[derive(Debug, Clone, PartialEq, Eq, Hash)]
280pub struct Cargo {
281 stage: u32,
282 host: TargetSelection,
283}
284
285impl Cargo {
286 const CRATE_PATH: &str = "src/tools/cargo";
287}
288
289impl Step for Cargo {
290 type Output = ();
291 const ONLY_HOSTS: bool = true;
292
293 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
294 run.path(Self::CRATE_PATH)
295 }
296
297 fn make_run(run: RunConfig<'_>) {
298 let stage = if run.builder.config.is_explicit_stage() || run.builder.top_stage >= 2 {
301 run.builder.top_stage
302 } else {
303 2
304 };
305
306 run.builder.ensure(Cargo { stage, host: run.target });
307 }
308
309 fn run(self, builder: &Builder<'_>) {
311 let stage = self.stage;
312
313 if stage < 2 {
314 eprintln!("WARNING: cargo tests on stage {stage} may not behave well.");
315 eprintln!("HELP: consider using stage 2");
316 }
317
318 let compiler = builder.compiler(stage, self.host);
319
320 let cargo = builder.ensure(tool::Cargo { compiler, target: self.host });
321 let compiler = cargo.build_compiler;
322
323 let cargo = tool::prepare_tool_cargo(
324 builder,
325 compiler,
326 Mode::ToolRustc,
327 self.host,
328 Kind::Test,
329 Self::CRATE_PATH,
330 SourceType::Submodule,
331 &[],
332 );
333
334 let mut cargo = prepare_cargo_test(cargo, &[], &[], self.host, builder);
336
337 cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
340 cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1");
343 cargo.env("PATH", path_for_cargo(builder, compiler));
344 cargo.env("CARGO_RUSTC_CURRENT_DIR", builder.src.display().to_string());
348
349 #[cfg(feature = "build-metrics")]
350 builder.metrics.begin_test_suite(
351 build_helper::metrics::TestSuiteMetadata::CargoPackage {
352 crates: vec!["cargo".into()],
353 target: self.host.triple.to_string(),
354 host: self.host.triple.to_string(),
355 stage,
356 },
357 builder,
358 );
359
360 let _time = helpers::timeit(builder);
361 add_flags_and_try_run_tests(builder, &mut cargo);
362 }
363}
364
365#[derive(Debug, Clone, PartialEq, Eq, Hash)]
366pub struct RustAnalyzer {
367 stage: u32,
368 host: TargetSelection,
369}
370
371impl Step for RustAnalyzer {
372 type Output = ();
373 const ONLY_HOSTS: bool = true;
374 const DEFAULT: bool = true;
375
376 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
377 run.path("src/tools/rust-analyzer")
378 }
379
380 fn make_run(run: RunConfig<'_>) {
381 run.builder.ensure(Self { stage: run.builder.top_stage, host: run.target });
382 }
383
384 fn run(self, builder: &Builder<'_>) {
386 let stage = self.stage;
387 let host = self.host;
388 let compiler = builder.compiler(stage, host);
389 let compiler = tool::get_tool_rustc_compiler(builder, compiler);
390
391 builder.ensure(compile::Rustc::new(compiler, host));
394
395 let workspace_path = "src/tools/rust-analyzer";
396 let crate_path = "src/tools/rust-analyzer/crates/proc-macro-srv";
399 let mut cargo = tool::prepare_tool_cargo(
400 builder,
401 compiler,
402 Mode::ToolRustc,
403 host,
404 Kind::Test,
405 crate_path,
406 SourceType::InTree,
407 &["in-rust-tree".to_owned()],
408 );
409 cargo.allow_features(tool::RustAnalyzer::ALLOW_FEATURES);
410
411 let dir = builder.src.join(workspace_path);
412 cargo.env("CARGO_WORKSPACE_DIR", &dir);
415
416 cargo.env("SKIP_SLOW_TESTS", "1");
419
420 cargo.add_rustc_lib_path(builder);
421 run_cargo_test(cargo, &[], &[], "rust-analyzer", host, builder);
422 }
423}
424
425#[derive(Debug, Clone, PartialEq, Eq, Hash)]
427pub struct Rustfmt {
428 stage: u32,
429 host: TargetSelection,
430}
431
432impl Step for Rustfmt {
433 type Output = ();
434 const ONLY_HOSTS: bool = true;
435
436 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
437 run.path("src/tools/rustfmt")
438 }
439
440 fn make_run(run: RunConfig<'_>) {
441 run.builder.ensure(Rustfmt { stage: run.builder.top_stage, host: run.target });
442 }
443
444 fn run(self, builder: &Builder<'_>) {
446 let stage = self.stage;
447 let host = self.host;
448 let compiler = builder.compiler(stage, host);
449
450 let tool_result = builder.ensure(tool::Rustfmt { compiler, target: self.host });
451 let compiler = tool_result.build_compiler;
452
453 let mut cargo = tool::prepare_tool_cargo(
454 builder,
455 compiler,
456 Mode::ToolRustc,
457 host,
458 Kind::Test,
459 "src/tools/rustfmt",
460 SourceType::InTree,
461 &[],
462 );
463
464 let dir = testdir(builder, compiler.host);
465 t!(fs::create_dir_all(&dir));
466 cargo.env("RUSTFMT_TEST_DIR", dir);
467
468 cargo.add_rustc_lib_path(builder);
469
470 run_cargo_test(cargo, &[], &[], "rustfmt", host, builder);
471 }
472}
473
474#[derive(Debug, Clone, PartialEq, Eq, Hash)]
475pub struct Miri {
476 target: TargetSelection,
477}
478
479impl Miri {
480 pub fn build_miri_sysroot(
482 builder: &Builder<'_>,
483 compiler: Compiler,
484 target: TargetSelection,
485 ) -> PathBuf {
486 let miri_sysroot = builder.out.join(compiler.host).join("miri-sysroot");
487 let mut cargo = builder::Cargo::new(
488 builder,
489 compiler,
490 Mode::Std,
491 SourceType::Submodule,
492 target,
493 Kind::MiriSetup,
494 );
495
496 cargo.env("MIRI_LIB_SRC", builder.src.join("library"));
498 cargo.env("MIRI_SYSROOT", &miri_sysroot);
500
501 let mut cargo = BootstrapCommand::from(cargo);
502 let _guard =
503 builder.msg(Kind::Build, compiler.stage, "miri sysroot", compiler.host, target);
504 cargo.run(builder);
505
506 cargo.arg("--print-sysroot");
512
513 builder.verbose(|| println!("running: {cargo:?}"));
514 let stdout = cargo.run_capture_stdout(builder).stdout();
515 let sysroot = stdout.trim_end();
517 builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
518 PathBuf::from(sysroot)
519 }
520}
521
522impl Step for Miri {
523 type Output = ();
524 const ONLY_HOSTS: bool = false;
525
526 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
527 run.path("src/tools/miri")
528 }
529
530 fn make_run(run: RunConfig<'_>) {
531 run.builder.ensure(Miri { target: run.target });
532 }
533
534 fn run(self, builder: &Builder<'_>) {
536 let host = builder.build.host_target;
537 let target = self.target;
538 let stage = builder.top_stage;
539 if stage == 0 {
540 eprintln!("miri cannot be tested at stage 0");
541 std::process::exit(1);
542 }
543
544 let target_compiler = builder.compiler(stage, host);
546
547 let miri = builder.ensure(tool::Miri { compiler: target_compiler, target: host });
549 builder.ensure(tool::CargoMiri { compiler: target_compiler, target: host });
551
552 let miri_sysroot = Miri::build_miri_sysroot(builder, target_compiler, target);
555 builder.std(target_compiler, host);
556 let host_sysroot = builder.sysroot(target_compiler);
557
558 if !builder.config.dry_run() {
561 let ui_test_dep_dir = builder
564 .stage_out(miri.build_compiler, Mode::ToolStd)
565 .join(host)
566 .join("tmp")
567 .join("miri_ui");
568 build_stamp::clear_if_dirty(builder, &ui_test_dep_dir, &miri_sysroot);
572 }
573
574 let mut cargo = tool::prepare_tool_cargo(
577 builder,
578 miri.build_compiler,
579 Mode::ToolRustc,
580 host,
581 Kind::Test,
582 "src/tools/miri",
583 SourceType::InTree,
584 &[],
585 );
586
587 cargo.add_rustc_lib_path(builder);
588
589 let mut cargo = prepare_cargo_test(cargo, &[], &[], host, builder);
592
593 cargo.env("MIRI_SYSROOT", &miri_sysroot);
595 cargo.env("MIRI_HOST_SYSROOT", &host_sysroot);
596 cargo.env("MIRI", &miri.tool_path);
597
598 cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg());
600
601 {
602 let _guard = builder.msg_sysroot_tool(Kind::Test, stage, "miri", host, target);
603 let _time = helpers::timeit(builder);
604 cargo.run(builder);
605 }
606
607 if builder.config.test_args().is_empty() {
609 cargo.env("MIRIFLAGS", "-O -Zmir-opt-level=4 -Cdebug-assertions=yes");
610 cargo.env("MIRI_SKIP_UI_CHECKS", "1");
612 cargo.env_remove("RUSTC_BLESS");
614 cargo.args(["tests/pass", "tests/panic"]);
616
617 {
618 let _guard = builder.msg_sysroot_tool(
619 Kind::Test,
620 stage,
621 "miri (mir-opt-level 4)",
622 host,
623 target,
624 );
625 let _time = helpers::timeit(builder);
626 cargo.run(builder);
627 }
628 }
629 }
630}
631
632#[derive(Debug, Clone, PartialEq, Eq, Hash)]
635pub struct CargoMiri {
636 target: TargetSelection,
637}
638
639impl Step for CargoMiri {
640 type Output = ();
641 const ONLY_HOSTS: bool = false;
642
643 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
644 run.path("src/tools/miri/cargo-miri")
645 }
646
647 fn make_run(run: RunConfig<'_>) {
648 run.builder.ensure(CargoMiri { target: run.target });
649 }
650
651 fn run(self, builder: &Builder<'_>) {
653 let host = builder.build.host_target;
654 let target = self.target;
655 let stage = builder.top_stage;
656 if stage == 0 {
657 eprintln!("cargo-miri cannot be tested at stage 0");
658 std::process::exit(1);
659 }
660
661 let compiler = builder.compiler(stage, host);
663
664 let mut cargo = tool::prepare_tool_cargo(
669 builder,
670 compiler,
671 Mode::ToolStd, target,
673 Kind::MiriTest,
674 "src/tools/miri/test-cargo-miri",
675 SourceType::Submodule,
676 &[],
677 );
678
679 match builder.doc_tests {
682 DocTests::Yes => {}
683 DocTests::No => {
684 cargo.args(["--lib", "--bins", "--examples", "--tests", "--benches"]);
685 }
686 DocTests::Only => {
687 cargo.arg("--doc");
688 }
689 }
690 cargo.arg("--").args(builder.config.test_args());
691
692 let mut cargo = BootstrapCommand::from(cargo);
694 {
695 let _guard = builder.msg_sysroot_tool(Kind::Test, stage, "cargo-miri", host, target);
696 let _time = helpers::timeit(builder);
697 cargo.run(builder);
698 }
699 }
700}
701
702#[derive(Debug, Clone, PartialEq, Eq, Hash)]
703pub struct CompiletestTest {
704 host: TargetSelection,
705}
706
707impl Step for CompiletestTest {
708 type Output = ();
709
710 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
711 run.path("src/tools/compiletest")
712 }
713
714 fn make_run(run: RunConfig<'_>) {
715 run.builder.ensure(CompiletestTest { host: run.target });
716 }
717
718 #[cfg_attr(
720 feature = "tracing",
721 instrument(level = "debug", name = "CompiletestTest::run", skip_all)
722 )]
723 fn run(self, builder: &Builder<'_>) {
724 let host = self.host;
725
726 if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 {
727 eprintln!("\
728ERROR: `--stage 0` runs compiletest self-tests against the stage0 (precompiled) compiler, not the in-tree compiler, and will almost always cause tests to fail
729NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `--set build.compiletest-allow-stage0=true`."
730 );
731 crate::exit!(1);
732 }
733
734 let compiler = builder.compiler(builder.top_stage, host);
735 debug!(?compiler);
736
737 builder.std(compiler, host);
740 let mut cargo = tool::prepare_tool_cargo(
741 builder,
742 compiler,
743 Mode::ToolStd,
746 host,
747 Kind::Test,
748 "src/tools/compiletest",
749 SourceType::InTree,
750 &[],
751 );
752 cargo.allow_features(COMPILETEST_ALLOW_FEATURES);
753 run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder);
754 }
755}
756
757#[derive(Debug, Clone, PartialEq, Eq, Hash)]
758pub struct Clippy {
759 host: TargetSelection,
760}
761
762impl Step for Clippy {
763 type Output = ();
764 const ONLY_HOSTS: bool = true;
765 const DEFAULT: bool = false;
766
767 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
768 run.suite_path("src/tools/clippy/tests").path("src/tools/clippy")
769 }
770
771 fn make_run(run: RunConfig<'_>) {
772 run.builder.ensure(Clippy { host: run.target });
773 }
774
775 fn run(self, builder: &Builder<'_>) {
777 let stage = builder.top_stage;
778 let host = self.host;
779 let target_compiler = builder.compiler(stage, host);
783
784 let tool_result = builder.ensure(tool::Clippy { compiler: target_compiler, target: host });
785 let tool_compiler = tool_result.build_compiler;
786 let mut cargo = tool::prepare_tool_cargo(
787 builder,
788 tool_compiler,
789 Mode::ToolRustc,
790 host,
791 Kind::Test,
792 "src/tools/clippy",
793 SourceType::InTree,
794 &[],
795 );
796
797 cargo.env("RUSTC_TEST_SUITE", builder.rustc(tool_compiler));
798 cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(tool_compiler));
799 let host_libs = builder.stage_out(tool_compiler, Mode::ToolRustc).join(builder.cargo_dir());
800 cargo.env("HOST_LIBS", host_libs);
801
802 builder.std(target_compiler, host);
804 cargo.env("TEST_SYSROOT", builder.sysroot(target_compiler));
805 cargo.env("TEST_RUSTC", builder.rustc(target_compiler));
806 cargo.env("TEST_RUSTC_LIB", builder.rustc_libdir(target_compiler));
807
808 'partially_test: {
810 let paths = &builder.config.paths[..];
811 let mut test_names = Vec::new();
812 for path in paths {
813 if let Some(path) =
814 helpers::is_valid_test_suite_arg(path, "src/tools/clippy/tests", builder)
815 {
816 test_names.push(path);
817 } else if path.ends_with("src/tools/clippy") {
818 break 'partially_test;
820 }
821 }
822 cargo.env("TESTNAME", test_names.join(","));
823 }
824
825 cargo.add_rustc_lib_path(builder);
826 let cargo = prepare_cargo_test(cargo, &[], &[], host, builder);
827
828 let _guard =
829 builder.msg_sysroot_tool(Kind::Test, tool_compiler.stage, "clippy", host, host);
830
831 if cargo.allow_failure().run(builder) {
833 return;
835 }
836
837 if !builder.config.cmd.bless() {
838 crate::exit!(1);
839 }
840 }
841}
842
843fn path_for_cargo(builder: &Builder<'_>, compiler: Compiler) -> OsString {
844 let path = builder.sysroot(compiler).join("bin");
848 let old_path = env::var_os("PATH").unwrap_or_default();
849 env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("")
850}
851
852#[derive(Debug, Clone, Hash, PartialEq, Eq)]
853pub struct RustdocTheme {
854 pub compiler: Compiler,
855}
856
857impl Step for RustdocTheme {
858 type Output = ();
859 const DEFAULT: bool = true;
860 const ONLY_HOSTS: bool = true;
861
862 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
863 run.path("src/tools/rustdoc-themes")
864 }
865
866 fn make_run(run: RunConfig<'_>) {
867 let compiler = run.builder.compiler(run.builder.top_stage, run.target);
868
869 run.builder.ensure(RustdocTheme { compiler });
870 }
871
872 fn run(self, builder: &Builder<'_>) {
873 let rustdoc = builder.bootstrap_out.join("rustdoc");
874 let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
875 cmd.arg(rustdoc.to_str().unwrap())
876 .arg(builder.src.join("src/librustdoc/html/static/css/rustdoc.css").to_str().unwrap())
877 .env("RUSTC_STAGE", self.compiler.stage.to_string())
878 .env("RUSTC_SYSROOT", builder.sysroot(self.compiler))
879 .env("RUSTDOC_LIBDIR", builder.sysroot_target_libdir(self.compiler, self.compiler.host))
880 .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
881 .env("RUSTDOC_REAL", builder.rustdoc(self.compiler))
882 .env("RUSTC_BOOTSTRAP", "1");
883 cmd.args(linker_args(builder, self.compiler.host, LldThreads::No, self.compiler.stage));
884
885 cmd.delay_failure().run(builder);
886 }
887}
888
889#[derive(Debug, Clone, Hash, PartialEq, Eq)]
890pub struct RustdocJSStd {
891 pub target: TargetSelection,
892}
893
894impl Step for RustdocJSStd {
895 type Output = ();
896 const DEFAULT: bool = true;
897 const ONLY_HOSTS: bool = true;
898
899 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
900 let default = run.builder.config.nodejs.is_some();
901 run.suite_path("tests/rustdoc-js-std").default_condition(default)
902 }
903
904 fn make_run(run: RunConfig<'_>) {
905 run.builder.ensure(RustdocJSStd { target: run.target });
906 }
907
908 fn run(self, builder: &Builder<'_>) {
909 let nodejs =
910 builder.config.nodejs.as_ref().expect("need nodejs to run rustdoc-js-std tests");
911 let mut command = command(nodejs);
912 command
913 .arg(builder.src.join("src/tools/rustdoc-js/tester.js"))
914 .arg("--crate-name")
915 .arg("std")
916 .arg("--resource-suffix")
917 .arg(&builder.version)
918 .arg("--doc-folder")
919 .arg(builder.doc_out(self.target))
920 .arg("--test-folder")
921 .arg(builder.src.join("tests/rustdoc-js-std"));
922 for path in &builder.paths {
923 if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder)
924 {
925 if !p.ends_with(".js") {
926 eprintln!("A non-js file was given: `{}`", path.display());
927 panic!("Cannot run rustdoc-js-std tests");
928 }
929 command.arg("--test-file").arg(path);
930 }
931 }
932 builder.ensure(crate::core::build_steps::doc::Std::new(
933 builder.top_stage,
934 self.target,
935 DocumentationFormat::Html,
936 ));
937 let _guard = builder.msg(
938 Kind::Test,
939 builder.top_stage,
940 "rustdoc-js-std",
941 builder.config.host_target,
942 self.target,
943 );
944 command.run(builder);
945 }
946}
947
948#[derive(Debug, Clone, Hash, PartialEq, Eq)]
949pub struct RustdocJSNotStd {
950 pub target: TargetSelection,
951 pub compiler: Compiler,
952}
953
954impl Step for RustdocJSNotStd {
955 type Output = ();
956 const DEFAULT: bool = true;
957 const ONLY_HOSTS: bool = true;
958
959 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
960 let default = run.builder.config.nodejs.is_some();
961 run.suite_path("tests/rustdoc-js").default_condition(default)
962 }
963
964 fn make_run(run: RunConfig<'_>) {
965 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
966 run.builder.ensure(RustdocJSNotStd { target: run.target, compiler });
967 }
968
969 fn run(self, builder: &Builder<'_>) {
970 builder.ensure(Compiletest {
971 compiler: self.compiler,
972 target: self.target,
973 mode: "rustdoc-js",
974 suite: "rustdoc-js",
975 path: "tests/rustdoc-js",
976 compare_mode: None,
977 });
978 }
979}
980
981fn get_browser_ui_test_version_inner(
982 builder: &Builder<'_>,
983 npm: &Path,
984 global: bool,
985) -> Option<String> {
986 let mut command = command(npm);
987 command.arg("list").arg("--parseable").arg("--long").arg("--depth=0");
988 if global {
989 command.arg("--global");
990 }
991 let lines = command.allow_failure().run_capture(builder).stdout();
992 lines
993 .lines()
994 .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@"))
995 .map(|v| v.to_owned())
996}
997
998fn get_browser_ui_test_version(builder: &Builder<'_>, npm: &Path) -> Option<String> {
999 get_browser_ui_test_version_inner(builder, npm, false)
1000 .or_else(|| get_browser_ui_test_version_inner(builder, npm, true))
1001}
1002
1003#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1004pub struct RustdocGUI {
1005 pub target: TargetSelection,
1006 pub compiler: Compiler,
1007}
1008
1009impl Step for RustdocGUI {
1010 type Output = ();
1011 const DEFAULT: bool = true;
1012 const ONLY_HOSTS: bool = true;
1013
1014 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1015 let builder = run.builder;
1016 let run = run.suite_path("tests/rustdoc-gui");
1017 run.lazy_default_condition(Box::new(move || {
1018 builder.config.nodejs.is_some()
1019 && builder.doc_tests != DocTests::Only
1020 && builder
1021 .config
1022 .npm
1023 .as_ref()
1024 .map(|p| get_browser_ui_test_version(builder, p).is_some())
1025 .unwrap_or(false)
1026 }))
1027 }
1028
1029 fn make_run(run: RunConfig<'_>) {
1030 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1031 run.builder.ensure(RustdocGUI { target: run.target, compiler });
1032 }
1033
1034 fn run(self, builder: &Builder<'_>) {
1035 builder.std(self.compiler, self.target);
1036
1037 let mut cmd = builder.tool_cmd(Tool::RustdocGUITest);
1038
1039 let out_dir = builder.test_out(self.target).join("rustdoc-gui");
1040 build_stamp::clear_if_dirty(builder, &out_dir, &builder.rustdoc(self.compiler));
1041
1042 if let Some(src) = builder.config.src.to_str() {
1043 cmd.arg("--rust-src").arg(src);
1044 }
1045
1046 if let Some(out_dir) = out_dir.to_str() {
1047 cmd.arg("--out-dir").arg(out_dir);
1048 }
1049
1050 if let Some(initial_cargo) = builder.config.initial_cargo.to_str() {
1051 cmd.arg("--initial-cargo").arg(initial_cargo);
1052 }
1053
1054 cmd.arg("--jobs").arg(builder.jobs().to_string());
1055
1056 cmd.env("RUSTDOC", builder.rustdoc(self.compiler))
1057 .env("RUSTC", builder.rustc(self.compiler));
1058
1059 add_rustdoc_cargo_linker_args(
1060 &mut cmd,
1061 builder,
1062 self.compiler.host,
1063 LldThreads::No,
1064 self.compiler.stage,
1065 );
1066
1067 for path in &builder.paths {
1068 if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) {
1069 if !p.ends_with(".goml") {
1070 eprintln!("A non-goml file was given: `{}`", path.display());
1071 panic!("Cannot run rustdoc-gui tests");
1072 }
1073 if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
1074 cmd.arg("--goml-file").arg(name);
1075 }
1076 }
1077 }
1078
1079 for test_arg in builder.config.test_args() {
1080 cmd.arg("--test-arg").arg(test_arg);
1081 }
1082
1083 if let Some(ref nodejs) = builder.config.nodejs {
1084 cmd.arg("--nodejs").arg(nodejs);
1085 }
1086
1087 if let Some(ref npm) = builder.config.npm {
1088 cmd.arg("--npm").arg(npm);
1089 }
1090
1091 let _time = helpers::timeit(builder);
1092 let _guard = builder.msg_sysroot_tool(
1093 Kind::Test,
1094 self.compiler.stage,
1095 "rustdoc-gui",
1096 self.compiler.host,
1097 self.target,
1098 );
1099 try_run_tests(builder, &mut cmd, true);
1100 }
1101}
1102
1103#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1108pub struct Tidy;
1109
1110impl Step for Tidy {
1111 type Output = ();
1112 const DEFAULT: bool = true;
1113 const ONLY_HOSTS: bool = true;
1114
1115 fn run(self, builder: &Builder<'_>) {
1124 let mut cmd = builder.tool_cmd(Tool::Tidy);
1125 cmd.arg(&builder.src);
1126 cmd.arg(&builder.initial_cargo);
1127 cmd.arg(&builder.out);
1128 let jobs = builder.config.jobs.unwrap_or_else(|| {
1130 8 * std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32
1131 });
1132 cmd.arg(jobs.to_string());
1133 if let Some(npm) = &builder.config.npm {
1135 cmd.arg(npm);
1136 } else {
1137 cmd.arg("npm");
1138 }
1139 if builder.is_verbose() {
1140 cmd.arg("--verbose");
1141 }
1142 if builder.config.cmd.bless() {
1143 cmd.arg("--bless");
1144 }
1145 if let Some(s) =
1146 builder.config.cmd.extra_checks().or(builder.config.tidy_extra_checks.as_deref())
1147 {
1148 cmd.arg(format!("--extra-checks={s}"));
1149 }
1150 let mut args = std::env::args_os();
1151 if args.any(|arg| arg == OsStr::new("--")) {
1152 cmd.arg("--");
1153 cmd.args(args);
1154 }
1155
1156 if builder.config.channel == "dev" || builder.config.channel == "nightly" {
1157 if !builder.config.json_output {
1158 builder.info("fmt check");
1159 if builder.config.initial_rustfmt.is_none() {
1160 let inferred_rustfmt_dir = builder.initial_sysroot.join("bin");
1161 eprintln!(
1162 "\
1163ERROR: no `rustfmt` binary found in {PATH}
1164INFO: `rust.channel` is currently set to \"{CHAN}\"
1165HELP: if you are testing a beta branch, set `rust.channel` to \"beta\" in the `bootstrap.toml` file
1166HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to `x.py test`",
1167 PATH = inferred_rustfmt_dir.display(),
1168 CHAN = builder.config.channel,
1169 );
1170 crate::exit!(1);
1171 }
1172 let all = false;
1173 crate::core::build_steps::format::format(
1174 builder,
1175 !builder.config.cmd.bless(),
1176 all,
1177 &[],
1178 );
1179 } else {
1180 eprintln!(
1181 "WARNING: `--json-output` is not supported on rustfmt, formatting will be skipped"
1182 );
1183 }
1184 }
1185
1186 builder.info("tidy check");
1187 cmd.delay_failure().run(builder);
1188
1189 builder.info("x.py completions check");
1190 let completion_paths = get_completion_paths(builder);
1191 if builder.config.cmd.bless() {
1192 builder.ensure(crate::core::build_steps::run::GenerateCompletions);
1193 } else if completion_paths
1194 .into_iter()
1195 .any(|(shell, path)| get_completion(shell, &path).is_some())
1196 {
1197 eprintln!(
1198 "x.py completions were changed; run `x.py run generate-completions` to update them"
1199 );
1200 crate::exit!(1);
1201 }
1202 }
1203
1204 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1205 let default = run.builder.doc_tests != DocTests::Only;
1206 run.path("src/tools/tidy").default_condition(default)
1207 }
1208
1209 fn make_run(run: RunConfig<'_>) {
1210 run.builder.ensure(Tidy);
1211 }
1212
1213 fn metadata(&self) -> Option<StepMetadata> {
1214 Some(StepMetadata::test("tidy", TargetSelection::default()))
1215 }
1216}
1217
1218fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf {
1219 builder.out.join(host).join("test")
1220}
1221
1222macro_rules! test {
1224 (
1225 $( #[$attr:meta] )* $name:ident {
1227 path: $path:expr,
1228 mode: $mode:expr,
1229 suite: $suite:expr,
1230 default: $default:expr
1231 $( , only_hosts: $only_hosts:expr )? $( , compare_mode: $compare_mode:expr )? $( , )? }
1235 ) => {
1236 $( #[$attr] )*
1237 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
1238 pub struct $name {
1239 pub compiler: Compiler,
1240 pub target: TargetSelection,
1241 }
1242
1243 impl Step for $name {
1244 type Output = ();
1245 const DEFAULT: bool = $default;
1246 const ONLY_HOSTS: bool = (const {
1247 #[allow(unused_assignments, unused_mut)]
1248 let mut value = false;
1249 $( value = $only_hosts; )?
1250 value
1251 });
1252
1253 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1254 run.suite_path($path)
1255 }
1256
1257 fn make_run(run: RunConfig<'_>) {
1258 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1259
1260 run.builder.ensure($name { compiler, target: run.target });
1261 }
1262
1263 fn run(self, builder: &Builder<'_>) {
1264 builder.ensure(Compiletest {
1265 compiler: self.compiler,
1266 target: self.target,
1267 mode: $mode,
1268 suite: $suite,
1269 path: $path,
1270 compare_mode: (const {
1271 #[allow(unused_assignments, unused_mut)]
1272 let mut value = None;
1273 $( value = $compare_mode; )?
1274 value
1275 }),
1276 })
1277 }
1278
1279 fn metadata(&self) -> Option<StepMetadata> {
1280 Some(
1281 StepMetadata::test(stringify!($name), self.target)
1282 )
1283 }
1284 }
1285 };
1286}
1287
1288#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1291pub struct CrateRunMakeSupport {
1292 host: TargetSelection,
1293}
1294
1295impl Step for CrateRunMakeSupport {
1296 type Output = ();
1297 const ONLY_HOSTS: bool = true;
1298
1299 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1300 run.path("src/tools/run-make-support")
1301 }
1302
1303 fn make_run(run: RunConfig<'_>) {
1304 run.builder.ensure(CrateRunMakeSupport { host: run.target });
1305 }
1306
1307 fn run(self, builder: &Builder<'_>) {
1309 let host = self.host;
1310 let compiler = builder.compiler(0, host);
1311
1312 let mut cargo = tool::prepare_tool_cargo(
1313 builder,
1314 compiler,
1315 Mode::ToolBootstrap,
1316 host,
1317 Kind::Test,
1318 "src/tools/run-make-support",
1319 SourceType::InTree,
1320 &[],
1321 );
1322 cargo.allow_features("test");
1323 run_cargo_test(cargo, &[], &[], "run-make-support self test", host, builder);
1324 }
1325}
1326
1327#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1328pub struct CrateBuildHelper {
1329 host: TargetSelection,
1330}
1331
1332impl Step for CrateBuildHelper {
1333 type Output = ();
1334 const ONLY_HOSTS: bool = true;
1335
1336 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1337 run.path("src/build_helper")
1338 }
1339
1340 fn make_run(run: RunConfig<'_>) {
1341 run.builder.ensure(CrateBuildHelper { host: run.target });
1342 }
1343
1344 fn run(self, builder: &Builder<'_>) {
1346 let host = self.host;
1347 let compiler = builder.compiler(0, host);
1348
1349 let mut cargo = tool::prepare_tool_cargo(
1350 builder,
1351 compiler,
1352 Mode::ToolBootstrap,
1353 host,
1354 Kind::Test,
1355 "src/build_helper",
1356 SourceType::InTree,
1357 &[],
1358 );
1359 cargo.allow_features("test");
1360 run_cargo_test(cargo, &[], &[], "build_helper self test", host, builder);
1361 }
1362}
1363
1364test!(Ui { path: "tests/ui", mode: "ui", suite: "ui", default: true });
1365
1366test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes", default: true });
1367
1368test!(CodegenLlvm {
1369 path: "tests/codegen-llvm",
1370 mode: "codegen",
1371 suite: "codegen-llvm",
1372 default: true
1373});
1374
1375test!(CodegenUnits {
1376 path: "tests/codegen-units",
1377 mode: "codegen-units",
1378 suite: "codegen-units",
1379 default: true,
1380});
1381
1382test!(Incremental {
1383 path: "tests/incremental",
1384 mode: "incremental",
1385 suite: "incremental",
1386 default: true,
1387});
1388
1389test!(Debuginfo {
1390 path: "tests/debuginfo",
1391 mode: "debuginfo",
1392 suite: "debuginfo",
1393 default: true,
1394 compare_mode: Some("split-dwarf"),
1395});
1396
1397test!(UiFullDeps {
1398 path: "tests/ui-fulldeps",
1399 mode: "ui",
1400 suite: "ui-fulldeps",
1401 default: true,
1402 only_hosts: true,
1403});
1404
1405test!(Rustdoc {
1406 path: "tests/rustdoc",
1407 mode: "rustdoc",
1408 suite: "rustdoc",
1409 default: true,
1410 only_hosts: true,
1411});
1412test!(RustdocUi {
1413 path: "tests/rustdoc-ui",
1414 mode: "ui",
1415 suite: "rustdoc-ui",
1416 default: true,
1417 only_hosts: true,
1418});
1419
1420test!(RustdocJson {
1421 path: "tests/rustdoc-json",
1422 mode: "rustdoc-json",
1423 suite: "rustdoc-json",
1424 default: true,
1425 only_hosts: true,
1426});
1427
1428test!(Pretty {
1429 path: "tests/pretty",
1430 mode: "pretty",
1431 suite: "pretty",
1432 default: true,
1433 only_hosts: true,
1434});
1435
1436test!(RunMake { path: "tests/run-make", mode: "run-make", suite: "run-make", default: true });
1437
1438test!(AssemblyLlvm {
1439 path: "tests/assembly-llvm",
1440 mode: "assembly",
1441 suite: "assembly-llvm",
1442 default: true
1443});
1444
1445#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1448pub struct Coverage {
1449 pub compiler: Compiler,
1450 pub target: TargetSelection,
1451 pub mode: &'static str,
1452}
1453
1454impl Coverage {
1455 const PATH: &'static str = "tests/coverage";
1456 const SUITE: &'static str = "coverage";
1457 const ALL_MODES: &[&str] = &["coverage-map", "coverage-run"];
1458}
1459
1460impl Step for Coverage {
1461 type Output = ();
1462 const DEFAULT: bool = true;
1463 const ONLY_HOSTS: bool = false;
1465
1466 fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {
1467 run = run.suite_path(Self::PATH);
1473 for mode in Self::ALL_MODES {
1474 run = run.alias(mode);
1475 }
1476 run
1477 }
1478
1479 fn make_run(run: RunConfig<'_>) {
1480 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1481 let target = run.target;
1482
1483 let mut modes = vec![];
1487
1488 for path in &run.paths {
1491 match path {
1492 PathSet::Set(_) => {
1493 for mode in Self::ALL_MODES {
1494 if path.assert_single_path().path == Path::new(mode) {
1495 modes.push(mode);
1496 break;
1497 }
1498 }
1499 }
1500 PathSet::Suite(_) => {
1501 modes.extend(Self::ALL_MODES);
1502 break;
1503 }
1504 }
1505 }
1506
1507 modes.retain(|mode| !run.builder.config.skip.iter().any(|skip| skip == Path::new(mode)));
1510
1511 for mode in modes {
1519 run.builder.ensure(Coverage { compiler, target, mode });
1520 }
1521 }
1522
1523 fn run(self, builder: &Builder<'_>) {
1524 let Self { compiler, target, mode } = self;
1525 builder.ensure(Compiletest {
1528 compiler,
1529 target,
1530 mode,
1531 suite: Self::SUITE,
1532 path: Self::PATH,
1533 compare_mode: None,
1534 });
1535 }
1536}
1537
1538test!(CoverageRunRustdoc {
1539 path: "tests/coverage-run-rustdoc",
1540 mode: "coverage-run",
1541 suite: "coverage-run-rustdoc",
1542 default: true,
1543 only_hosts: true,
1544});
1545
1546#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1548pub struct MirOpt {
1549 pub compiler: Compiler,
1550 pub target: TargetSelection,
1551}
1552
1553impl Step for MirOpt {
1554 type Output = ();
1555 const DEFAULT: bool = true;
1556 const ONLY_HOSTS: bool = false;
1557
1558 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1559 run.suite_path("tests/mir-opt")
1560 }
1561
1562 fn make_run(run: RunConfig<'_>) {
1563 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1564 run.builder.ensure(MirOpt { compiler, target: run.target });
1565 }
1566
1567 fn run(self, builder: &Builder<'_>) {
1568 let run = |target| {
1569 builder.ensure(Compiletest {
1570 compiler: self.compiler,
1571 target,
1572 mode: "mir-opt",
1573 suite: "mir-opt",
1574 path: "tests/mir-opt",
1575 compare_mode: None,
1576 })
1577 };
1578
1579 run(self.target);
1580
1581 if builder.config.cmd.bless() {
1584 for target in ["aarch64-unknown-linux-gnu", "i686-pc-windows-msvc"] {
1590 run(TargetSelection::from_user(target));
1591 }
1592
1593 for target in ["x86_64-apple-darwin", "i686-unknown-linux-musl"] {
1594 let target = TargetSelection::from_user(target);
1595 let panic_abort_target = builder.ensure(MirOptPanicAbortSyntheticTarget {
1596 compiler: self.compiler,
1597 base: target,
1598 });
1599 run(panic_abort_target);
1600 }
1601 }
1602 }
1603}
1604
1605#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1606struct Compiletest {
1607 compiler: Compiler,
1608 target: TargetSelection,
1609 mode: &'static str,
1610 suite: &'static str,
1611 path: &'static str,
1612 compare_mode: Option<&'static str>,
1613}
1614
1615impl Step for Compiletest {
1616 type Output = ();
1617
1618 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1619 run.never()
1620 }
1621
1622 fn run(self, builder: &Builder<'_>) {
1628 if builder.doc_tests == DocTests::Only {
1629 return;
1630 }
1631
1632 if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 {
1633 eprintln!("\
1634ERROR: `--stage 0` runs compiletest on the stage0 (precompiled) compiler, not your local changes, and will almost always cause tests to fail
1635HELP: to test the compiler or standard library, omit the stage or explicitly use `--stage 1` instead
1636NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `--set build.compiletest-allow-stage0=true`."
1637 );
1638 crate::exit!(1);
1639 }
1640
1641 let mut compiler = self.compiler;
1642 let target = self.target;
1643 let mode = self.mode;
1644 let suite = self.suite;
1645
1646 let suite_path = self.path;
1648
1649 if !builder.config.codegen_tests && mode == "codegen" {
1651 return;
1652 }
1653
1654 let (stage, stage_id) = if suite == "ui-fulldeps" && compiler.stage == 1 {
1661 let build = builder.build.host_target;
1665 compiler = builder.compiler(compiler.stage - 1, build);
1666 let test_stage = compiler.stage + 1;
1667 (test_stage, format!("stage{test_stage}-{build}"))
1668 } else {
1669 let stage = compiler.stage;
1670 (stage, format!("stage{stage}-{target}"))
1671 };
1672
1673 if suite.ends_with("fulldeps") {
1674 builder.ensure(compile::Rustc::new(compiler, target));
1675 }
1676
1677 if suite == "debuginfo" {
1678 builder.ensure(dist::DebuggerScripts {
1679 sysroot: builder.sysroot(compiler).to_path_buf(),
1680 host: target,
1681 });
1682 }
1683 if suite == "run-make" {
1684 builder.tool_exe(Tool::RunMakeSupport);
1685 }
1686
1687 if suite == "mir-opt" {
1689 builder.ensure(compile::Std::new(compiler, compiler.host).is_for_mir_opt_tests(true));
1690 } else {
1691 builder.std(compiler, compiler.host);
1692 }
1693
1694 let mut cmd = builder.tool_cmd(Tool::Compiletest);
1695
1696 if suite == "mir-opt" {
1697 builder.ensure(compile::Std::new(compiler, target).is_for_mir_opt_tests(true));
1698 } else {
1699 builder.std(compiler, target);
1700 }
1701
1702 builder.ensure(RemoteCopyLibs { compiler, target });
1703
1704 cmd.arg("--stage").arg(stage.to_string());
1708 cmd.arg("--stage-id").arg(stage_id);
1709
1710 cmd.arg("--compile-lib-path").arg(builder.rustc_libdir(compiler));
1711 cmd.arg("--run-lib-path").arg(builder.sysroot_target_libdir(compiler, target));
1712 cmd.arg("--rustc-path").arg(builder.rustc(compiler));
1713
1714 cmd.arg("--minicore-path")
1717 .arg(builder.src.join("tests").join("auxiliary").join("minicore.rs"));
1718
1719 let is_rustdoc = suite == "rustdoc-ui" || suite == "rustdoc-js";
1720
1721 if mode == "run-make" {
1722 let cargo_path = if builder.top_stage == 0 {
1723 builder.initial_cargo.clone()
1725 } else {
1726 builder.ensure(tool::Cargo { compiler, target: compiler.host }).tool_path
1727 };
1728
1729 cmd.arg("--cargo-path").arg(cargo_path);
1730
1731 let stage0_rustc_path = builder.compiler(0, compiler.host);
1734 cmd.arg("--stage0-rustc-path").arg(builder.rustc(stage0_rustc_path));
1735 }
1736
1737 if mode == "rustdoc"
1739 || mode == "run-make"
1740 || (mode == "ui" && is_rustdoc)
1741 || mode == "rustdoc-js"
1742 || mode == "rustdoc-json"
1743 || suite == "coverage-run-rustdoc"
1744 {
1745 cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler));
1746 }
1747
1748 if mode == "rustdoc-json" {
1749 let json_compiler = compiler.with_stage(0);
1751 cmd.arg("--jsondocck-path")
1752 .arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target }).tool_path);
1753 cmd.arg("--jsondoclint-path").arg(
1754 builder.ensure(tool::JsonDocLint { compiler: json_compiler, target }).tool_path,
1755 );
1756 }
1757
1758 if matches!(mode, "coverage-map" | "coverage-run") {
1759 let coverage_dump = builder.tool_exe(Tool::CoverageDump);
1760 cmd.arg("--coverage-dump-path").arg(coverage_dump);
1761 }
1762
1763 cmd.arg("--src-root").arg(&builder.src);
1764 cmd.arg("--src-test-suite-root").arg(builder.src.join("tests").join(suite));
1765
1766 cmd.arg("--build-root").arg(&builder.out);
1770 cmd.arg("--build-test-suite-root").arg(testdir(builder, compiler.host).join(suite));
1771
1772 let sysroot = if builder.top_stage == 0 {
1775 builder.initial_sysroot.clone()
1776 } else {
1777 builder.sysroot(compiler)
1778 };
1779
1780 cmd.arg("--sysroot-base").arg(sysroot);
1781
1782 cmd.arg("--suite").arg(suite);
1783 cmd.arg("--mode").arg(mode);
1784 cmd.arg("--target").arg(target.rustc_target_arg());
1785 cmd.arg("--host").arg(&*compiler.host.triple);
1786 cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.host_target));
1787
1788 if let Some(codegen_backend) = builder.config.default_codegen_backend(compiler.host) {
1789 cmd.arg("--codegen-backend").arg(codegen_backend.name());
1792 }
1793
1794 if builder.build.config.llvm_enzyme {
1795 cmd.arg("--has-enzyme");
1796 }
1797
1798 if builder.config.cmd.bless() {
1799 cmd.arg("--bless");
1800 }
1801
1802 if builder.config.cmd.force_rerun() {
1803 cmd.arg("--force-rerun");
1804 }
1805
1806 if builder.config.cmd.no_capture() {
1807 cmd.arg("--no-capture");
1808 }
1809
1810 let compare_mode =
1811 builder.config.cmd.compare_mode().or_else(|| {
1812 if builder.config.test_compare_mode { self.compare_mode } else { None }
1813 });
1814
1815 if let Some(ref pass) = builder.config.cmd.pass() {
1816 cmd.arg("--pass");
1817 cmd.arg(pass);
1818 }
1819
1820 if let Some(ref run) = builder.config.cmd.run() {
1821 cmd.arg("--run");
1822 cmd.arg(run);
1823 }
1824
1825 if let Some(ref nodejs) = builder.config.nodejs {
1826 cmd.arg("--nodejs").arg(nodejs);
1827 } else if mode == "rustdoc-js" {
1828 panic!("need nodejs to run rustdoc-js suite");
1829 }
1830 if let Some(ref npm) = builder.config.npm {
1831 cmd.arg("--npm").arg(npm);
1832 }
1833 if builder.config.rust_optimize_tests {
1834 cmd.arg("--optimize-tests");
1835 }
1836 if builder.config.rust_randomize_layout {
1837 cmd.arg("--rust-randomized-layout");
1838 }
1839 if builder.config.cmd.only_modified() {
1840 cmd.arg("--only-modified");
1841 }
1842 if let Some(compiletest_diff_tool) = &builder.config.compiletest_diff_tool {
1843 cmd.arg("--compiletest-diff-tool").arg(compiletest_diff_tool);
1844 }
1845
1846 let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
1847 flags.push(format!(
1848 "-Cdebuginfo={}",
1849 if mode == "codegen" {
1850 if builder.config.rust_debuginfo_level_tests
1853 != crate::core::config::DebuginfoLevel::None
1854 {
1855 println!(
1856 "NOTE: ignoring `rust.debuginfo-level-tests={}` for codegen tests",
1857 builder.config.rust_debuginfo_level_tests
1858 );
1859 }
1860 crate::core::config::DebuginfoLevel::None
1861 } else {
1862 builder.config.rust_debuginfo_level_tests
1863 }
1864 ));
1865 flags.extend(builder.config.cmd.compiletest_rustc_args().iter().map(|s| s.to_string()));
1866
1867 if suite != "mir-opt" {
1868 if let Some(linker) = builder.linker(target) {
1869 cmd.arg("--target-linker").arg(linker);
1870 }
1871 if let Some(linker) = builder.linker(compiler.host) {
1872 cmd.arg("--host-linker").arg(linker);
1873 }
1874 }
1875
1876 if suite == "ui-fulldeps" && target.ends_with("darwin") {
1878 flags.push("-Alinker_messages".into());
1879 }
1880
1881 let mut hostflags = flags.clone();
1882 hostflags.extend(linker_flags(builder, compiler.host, LldThreads::No, compiler.stage));
1883
1884 let mut targetflags = flags;
1885
1886 if suite == "ui" || suite == "incremental" {
1888 builder.ensure(TestHelpers { target: compiler.host });
1889 builder.ensure(TestHelpers { target });
1890 hostflags
1891 .push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display()));
1892 targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
1893 }
1894
1895 for flag in hostflags {
1896 cmd.arg("--host-rustcflags").arg(flag);
1897 }
1898 for flag in targetflags {
1899 cmd.arg("--target-rustcflags").arg(flag);
1900 }
1901
1902 cmd.arg("--python").arg(builder.python());
1903
1904 if let Some(ref gdb) = builder.config.gdb {
1905 cmd.arg("--gdb").arg(gdb);
1906 }
1907
1908 let lldb_exe = builder.config.lldb.clone().unwrap_or_else(|| PathBuf::from("lldb"));
1909 let lldb_version = command(&lldb_exe)
1910 .allow_failure()
1911 .arg("--version")
1912 .run_capture(builder)
1913 .stdout_if_ok()
1914 .and_then(|v| if v.trim().is_empty() { None } else { Some(v) });
1915 if let Some(ref vers) = lldb_version {
1916 cmd.arg("--lldb-version").arg(vers);
1917 let lldb_python_dir = command(&lldb_exe)
1918 .allow_failure()
1919 .arg("-P")
1920 .run_capture_stdout(builder)
1921 .stdout_if_ok()
1922 .map(|p| p.lines().next().expect("lldb Python dir not found").to_string());
1923 if let Some(ref dir) = lldb_python_dir {
1924 cmd.arg("--lldb-python-dir").arg(dir);
1925 }
1926 }
1927
1928 if helpers::forcing_clang_based_tests() {
1929 let clang_exe = builder.llvm_out(target).join("bin").join("clang");
1930 cmd.arg("--run-clang-based-tests-with").arg(clang_exe);
1931 }
1932
1933 for exclude in &builder.config.skip {
1934 cmd.arg("--skip");
1935 cmd.arg(exclude);
1936 }
1937
1938 let paths = match &builder.config.cmd {
1940 Subcommand::Test { .. } => &builder.config.paths[..],
1941 _ => &[],
1942 };
1943
1944 let mut test_args: Vec<&str> = paths
1946 .iter()
1947 .filter_map(|p| helpers::is_valid_test_suite_arg(p, suite_path, builder))
1948 .collect();
1949
1950 test_args.append(&mut builder.config.test_args());
1951
1952 if cfg!(windows) {
1955 let test_args_win: Vec<String> =
1956 test_args.iter().map(|s| s.replace('/', "\\")).collect();
1957 cmd.args(&test_args_win);
1958 } else {
1959 cmd.args(&test_args);
1960 }
1961
1962 if builder.is_verbose() {
1963 cmd.arg("--verbose");
1964 }
1965
1966 cmd.arg("--json");
1967
1968 if builder.config.rustc_debug_assertions {
1969 cmd.arg("--with-rustc-debug-assertions");
1970 }
1971
1972 if builder.config.std_debug_assertions {
1973 cmd.arg("--with-std-debug-assertions");
1974 }
1975
1976 let mut llvm_components_passed = false;
1977 let mut copts_passed = false;
1978 if builder.config.llvm_enabled(compiler.host) {
1979 let llvm::LlvmResult { host_llvm_config, .. } =
1980 builder.ensure(llvm::Llvm { target: builder.config.host_target });
1981 if !builder.config.dry_run() {
1982 let llvm_version = get_llvm_version(builder, &host_llvm_config);
1983 let llvm_components = command(&host_llvm_config)
1984 .arg("--components")
1985 .run_capture_stdout(builder)
1986 .stdout();
1987 cmd.arg("--llvm-version")
1989 .arg(llvm_version.trim())
1990 .arg("--llvm-components")
1991 .arg(llvm_components.trim());
1992 llvm_components_passed = true;
1993 }
1994 if !builder.config.is_rust_llvm(target) {
1995 cmd.arg("--system-llvm");
1996 }
1997
1998 if !builder.config.dry_run() && suite.ends_with("fulldeps") {
2003 let llvm_libdir =
2004 command(&host_llvm_config).arg("--libdir").run_capture_stdout(builder).stdout();
2005 let link_llvm = if target.is_msvc() {
2006 format!("-Clink-arg=-LIBPATH:{llvm_libdir}")
2007 } else {
2008 format!("-Clink-arg=-L{llvm_libdir}")
2009 };
2010 cmd.arg("--host-rustcflags").arg(link_llvm);
2011 }
2012
2013 if !builder.config.dry_run() && matches!(mode, "run-make" | "coverage-run") {
2014 let llvm_bin_path = host_llvm_config
2019 .parent()
2020 .expect("Expected llvm-config to be contained in directory");
2021 assert!(llvm_bin_path.is_dir());
2022 cmd.arg("--llvm-bin-dir").arg(llvm_bin_path);
2023 }
2024
2025 if !builder.config.dry_run() && mode == "run-make" {
2026 if builder.config.lld_enabled {
2028 let lld_install_root =
2029 builder.ensure(llvm::Lld { target: builder.config.host_target });
2030
2031 let lld_bin_path = lld_install_root.join("bin");
2032
2033 let old_path = env::var_os("PATH").unwrap_or_default();
2034 let new_path = env::join_paths(
2035 std::iter::once(lld_bin_path).chain(env::split_paths(&old_path)),
2036 )
2037 .expect("Could not add LLD bin path to PATH");
2038 cmd.env("PATH", new_path);
2039 }
2040 }
2041 }
2042
2043 if !builder.config.dry_run() && mode == "run-make" {
2046 let mut cflags = builder.cc_handled_clags(target, CLang::C);
2047 cflags.extend(builder.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::C));
2048 let mut cxxflags = builder.cc_handled_clags(target, CLang::Cxx);
2049 cxxflags.extend(builder.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::Cxx));
2050 cmd.arg("--cc")
2051 .arg(builder.cc(target))
2052 .arg("--cxx")
2053 .arg(builder.cxx(target).unwrap())
2054 .arg("--cflags")
2055 .arg(cflags.join(" "))
2056 .arg("--cxxflags")
2057 .arg(cxxflags.join(" "));
2058 copts_passed = true;
2059 if let Some(ar) = builder.ar(target) {
2060 cmd.arg("--ar").arg(ar);
2061 }
2062 }
2063
2064 if !llvm_components_passed {
2065 cmd.arg("--llvm-components").arg("");
2066 }
2067 if !copts_passed {
2068 cmd.arg("--cc")
2069 .arg("")
2070 .arg("--cxx")
2071 .arg("")
2072 .arg("--cflags")
2073 .arg("")
2074 .arg("--cxxflags")
2075 .arg("");
2076 }
2077
2078 if builder.remote_tested(target) {
2079 cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient));
2080 } else if let Some(tool) = builder.runner(target) {
2081 cmd.arg("--runner").arg(tool);
2082 }
2083
2084 if suite != "mir-opt" {
2085 if !builder.config.dry_run() && target.is_msvc() {
2091 for (k, v) in builder.cc[&target].env() {
2092 if k != "PATH" {
2093 cmd.env(k, v);
2094 }
2095 }
2096 }
2097 }
2098
2099 if !builder.config.dry_run()
2101 && target.contains("msvc")
2102 && builder.config.sanitizers_enabled(target)
2103 {
2104 cmd.env("ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE", "1");
2107 let asan_runtime_path = builder.cc[&target].path().parent().unwrap().to_path_buf();
2109 let old_path = cmd
2110 .get_envs()
2111 .find_map(|(k, v)| (k == "PATH").then_some(v))
2112 .flatten()
2113 .map_or_else(|| env::var_os("PATH").unwrap_or_default(), |v| v.to_owned());
2114 let new_path = env::join_paths(
2115 env::split_paths(&old_path).chain(std::iter::once(asan_runtime_path)),
2116 )
2117 .expect("Could not add ASAN runtime path to PATH");
2118 cmd.env("PATH", new_path);
2119 }
2120
2121 cmd.env_remove("CARGO");
2124
2125 cmd.env("RUSTC_BOOTSTRAP", "1");
2126 cmd.env("RUSTC_FORCE_RUSTC_VERSION", "compiletest");
2129 cmd.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
2130 builder.add_rust_test_threads(&mut cmd);
2131
2132 if builder.config.sanitizers_enabled(target) {
2133 cmd.env("RUSTC_SANITIZER_SUPPORT", "1");
2134 }
2135
2136 if builder.config.profiler_enabled(target) {
2137 cmd.arg("--profiler-runtime");
2138 }
2139
2140 cmd.env("RUST_TEST_TMPDIR", builder.tempdir());
2141
2142 cmd.arg("--adb-path").arg("adb");
2143 cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
2144 if target.contains("android") && !builder.config.dry_run() {
2145 cmd.arg("--android-cross-path")
2147 .arg(builder.cc(target).parent().unwrap().parent().unwrap());
2148 } else {
2149 cmd.arg("--android-cross-path").arg("");
2150 }
2151
2152 if builder.config.cmd.rustfix_coverage() {
2153 cmd.arg("--rustfix-coverage");
2154 }
2155
2156 cmd.arg("--channel").arg(&builder.config.channel);
2157
2158 if !builder.config.omit_git_hash {
2159 cmd.arg("--git-hash");
2160 }
2161
2162 let git_config = builder.config.git_config();
2163 cmd.arg("--nightly-branch").arg(git_config.nightly_branch);
2164 cmd.arg("--git-merge-commit-email").arg(git_config.git_merge_commit_email);
2165 cmd.force_coloring_in_ci();
2166
2167 #[cfg(feature = "build-metrics")]
2168 builder.metrics.begin_test_suite(
2169 build_helper::metrics::TestSuiteMetadata::Compiletest {
2170 suite: suite.into(),
2171 mode: mode.into(),
2172 compare_mode: None,
2173 target: self.target.triple.to_string(),
2174 host: self.compiler.host.triple.to_string(),
2175 stage: self.compiler.stage,
2176 },
2177 builder,
2178 );
2179
2180 let _group = builder.msg(
2181 Kind::Test,
2182 compiler.stage,
2183 format!("compiletest suite={suite} mode={mode}"),
2184 compiler.host,
2185 target,
2186 );
2187 try_run_tests(builder, &mut cmd, false);
2188
2189 if let Some(compare_mode) = compare_mode {
2190 cmd.arg("--compare-mode").arg(compare_mode);
2191
2192 #[cfg(feature = "build-metrics")]
2193 builder.metrics.begin_test_suite(
2194 build_helper::metrics::TestSuiteMetadata::Compiletest {
2195 suite: suite.into(),
2196 mode: mode.into(),
2197 compare_mode: Some(compare_mode.into()),
2198 target: self.target.triple.to_string(),
2199 host: self.compiler.host.triple.to_string(),
2200 stage: self.compiler.stage,
2201 },
2202 builder,
2203 );
2204
2205 builder.info(&format!(
2206 "Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
2207 suite, mode, compare_mode, &compiler.host, target
2208 ));
2209 let _time = helpers::timeit(builder);
2210 try_run_tests(builder, &mut cmd, false);
2211 }
2212 }
2213}
2214
2215#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2216struct BookTest {
2217 compiler: Compiler,
2218 path: PathBuf,
2219 name: &'static str,
2220 is_ext_doc: bool,
2221 dependencies: Vec<&'static str>,
2222}
2223
2224impl Step for BookTest {
2225 type Output = ();
2226 const ONLY_HOSTS: bool = true;
2227
2228 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2229 run.never()
2230 }
2231
2232 fn run(self, builder: &Builder<'_>) {
2236 if self.is_ext_doc {
2246 self.run_ext_doc(builder);
2247 } else {
2248 self.run_local_doc(builder);
2249 }
2250 }
2251}
2252
2253impl BookTest {
2254 fn run_ext_doc(self, builder: &Builder<'_>) {
2257 let compiler = self.compiler;
2258
2259 builder.std(compiler, compiler.host);
2260
2261 let mut rustdoc_path = builder.rustdoc(compiler);
2264 rustdoc_path.pop();
2265 let old_path = env::var_os("PATH").unwrap_or_default();
2266 let new_path = env::join_paths(iter::once(rustdoc_path).chain(env::split_paths(&old_path)))
2267 .expect("could not add rustdoc to PATH");
2268
2269 let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
2270 let path = builder.src.join(&self.path);
2271 rustbook_cmd.env("RUSTC_BOOTSTRAP", "1");
2273 rustbook_cmd.env("PATH", new_path).arg("test").arg(path);
2274
2275 let libs = if !self.dependencies.is_empty() {
2280 let mut lib_paths = vec![];
2281 for dep in self.dependencies {
2282 let mode = Mode::ToolRustc;
2283 let target = builder.config.host_target;
2284 let cargo = tool::prepare_tool_cargo(
2285 builder,
2286 compiler,
2287 mode,
2288 target,
2289 Kind::Build,
2290 dep,
2291 SourceType::Submodule,
2292 &[],
2293 );
2294
2295 let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, target))
2296 .with_prefix(PathBuf::from(dep).file_name().and_then(|v| v.to_str()).unwrap());
2297
2298 let output_paths = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false);
2299 let directories = output_paths
2300 .into_iter()
2301 .filter_map(|p| p.parent().map(ToOwned::to_owned))
2302 .fold(HashSet::new(), |mut set, dir| {
2303 set.insert(dir);
2304 set
2305 });
2306
2307 lib_paths.extend(directories);
2308 }
2309 lib_paths
2310 } else {
2311 vec![]
2312 };
2313
2314 if !libs.is_empty() {
2315 let paths = libs
2316 .into_iter()
2317 .map(|path| path.into_os_string())
2318 .collect::<Vec<OsString>>()
2319 .join(OsStr::new(","));
2320 rustbook_cmd.args([OsString::from("--library-path"), paths]);
2321 }
2322
2323 builder.add_rust_test_threads(&mut rustbook_cmd);
2324 let _guard = builder.msg(
2325 Kind::Test,
2326 compiler.stage,
2327 format_args!("mdbook {}", self.path.display()),
2328 compiler.host,
2329 compiler.host,
2330 );
2331 let _time = helpers::timeit(builder);
2332 let toolstate = if rustbook_cmd.delay_failure().run(builder) {
2333 ToolState::TestPass
2334 } else {
2335 ToolState::TestFail
2336 };
2337 builder.save_toolstate(self.name, toolstate);
2338 }
2339
2340 fn run_local_doc(self, builder: &Builder<'_>) {
2342 let compiler = self.compiler;
2343 let host = self.compiler.host;
2344
2345 builder.std(compiler, host);
2346
2347 let _guard =
2348 builder.msg(Kind::Test, compiler.stage, format!("book {}", self.name), host, host);
2349
2350 let mut stack = vec![builder.src.join(self.path)];
2353 let _time = helpers::timeit(builder);
2354 let mut files = Vec::new();
2355 while let Some(p) = stack.pop() {
2356 if p.is_dir() {
2357 stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
2358 continue;
2359 }
2360
2361 if p.extension().and_then(|s| s.to_str()) != Some("md") {
2362 continue;
2363 }
2364
2365 files.push(p);
2366 }
2367
2368 files.sort();
2369
2370 for file in files {
2371 markdown_test(builder, compiler, &file);
2372 }
2373 }
2374}
2375
2376macro_rules! test_book {
2377 ($(
2378 $name:ident, $path:expr, $book_name:expr,
2379 default=$default:expr
2380 $(,submodules = $submodules:expr)?
2381 $(,dependencies=$dependencies:expr)?
2382 ;
2383 )+) => {
2384 $(
2385 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
2386 pub struct $name {
2387 compiler: Compiler,
2388 }
2389
2390 impl Step for $name {
2391 type Output = ();
2392 const DEFAULT: bool = $default;
2393 const ONLY_HOSTS: bool = true;
2394
2395 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2396 run.path($path)
2397 }
2398
2399 fn make_run(run: RunConfig<'_>) {
2400 run.builder.ensure($name {
2401 compiler: run.builder.compiler(run.builder.top_stage, run.target),
2402 });
2403 }
2404
2405 fn run(self, builder: &Builder<'_>) {
2406 $(
2407 for submodule in $submodules {
2408 builder.require_submodule(submodule, None);
2409 }
2410 )*
2411
2412 let dependencies = vec![];
2413 $(
2414 let mut dependencies = dependencies;
2415 for dep in $dependencies {
2416 dependencies.push(dep);
2417 }
2418 )?
2419
2420 builder.ensure(BookTest {
2421 compiler: self.compiler,
2422 path: PathBuf::from($path),
2423 name: $book_name,
2424 is_ext_doc: !$default,
2425 dependencies,
2426 });
2427 }
2428 }
2429 )+
2430 }
2431}
2432
2433test_book!(
2434 Nomicon, "src/doc/nomicon", "nomicon", default=false, submodules=["src/doc/nomicon"];
2435 Reference, "src/doc/reference", "reference", default=false, submodules=["src/doc/reference"];
2436 RustdocBook, "src/doc/rustdoc", "rustdoc", default=true;
2437 RustcBook, "src/doc/rustc", "rustc", default=true;
2438 RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false, submodules=["src/doc/rust-by-example"];
2439 EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false, submodules=["src/doc/embedded-book"];
2440 TheBook, "src/doc/book", "book", default=false, submodules=["src/doc/book"], dependencies=["src/doc/book/packages/trpl"];
2441 UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
2442 EditionGuide, "src/doc/edition-guide", "edition-guide", default=false, submodules=["src/doc/edition-guide"];
2443);
2444
2445#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2446pub struct ErrorIndex {
2447 compiler: Compiler,
2448}
2449
2450impl Step for ErrorIndex {
2451 type Output = ();
2452 const DEFAULT: bool = true;
2453 const ONLY_HOSTS: bool = true;
2454
2455 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2456 run.path("src/tools/error_index_generator").alias("error-index")
2459 }
2460
2461 fn make_run(run: RunConfig<'_>) {
2462 let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.host_target);
2466 run.builder.ensure(ErrorIndex { compiler });
2467 }
2468
2469 fn run(self, builder: &Builder<'_>) {
2476 let compiler = self.compiler;
2477
2478 let dir = testdir(builder, compiler.host);
2479 t!(fs::create_dir_all(&dir));
2480 let output = dir.join("error-index.md");
2481
2482 let mut tool = tool::ErrorIndex::command(builder);
2483 tool.arg("markdown").arg(&output);
2484
2485 let guard =
2486 builder.msg(Kind::Test, compiler.stage, "error-index", compiler.host, compiler.host);
2487 let _time = helpers::timeit(builder);
2488 tool.run_capture(builder);
2489 drop(guard);
2490 builder.std(compiler, compiler.host);
2493 markdown_test(builder, compiler, &output);
2494 }
2495}
2496
2497fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool {
2498 if let Ok(contents) = fs::read_to_string(markdown)
2499 && !contents.contains("```")
2500 {
2501 return true;
2502 }
2503
2504 builder.verbose(|| println!("doc tests for: {}", markdown.display()));
2505 let mut cmd = builder.rustdoc_cmd(compiler);
2506 builder.add_rust_test_threads(&mut cmd);
2507 cmd.arg("-Z");
2509 cmd.arg("unstable-options");
2510 cmd.arg("--test");
2511 cmd.arg(markdown);
2512 cmd.env("RUSTC_BOOTSTRAP", "1");
2513
2514 let test_args = builder.config.test_args().join(" ");
2515 cmd.arg("--test-args").arg(test_args);
2516
2517 cmd = cmd.delay_failure();
2518 if !builder.config.verbose_tests {
2519 cmd.run_capture(builder).is_success()
2520 } else {
2521 cmd.run(builder)
2522 }
2523}
2524
2525#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2530pub struct CrateLibrustc {
2531 compiler: Compiler,
2532 target: TargetSelection,
2533 crates: Vec<String>,
2534}
2535
2536impl Step for CrateLibrustc {
2537 type Output = ();
2538 const DEFAULT: bool = true;
2539 const ONLY_HOSTS: bool = true;
2540
2541 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2542 run.crate_or_deps("rustc-main").path("compiler")
2543 }
2544
2545 fn make_run(run: RunConfig<'_>) {
2546 let builder = run.builder;
2547 let host = run.build_triple();
2548 let compiler = builder.compiler_for(builder.top_stage, host, host);
2549 let crates = run.make_run_crates(Alias::Compiler);
2550
2551 builder.ensure(CrateLibrustc { compiler, target: run.target, crates });
2552 }
2553
2554 fn run(self, builder: &Builder<'_>) {
2555 builder.std(self.compiler, self.target);
2556
2557 builder.ensure(Crate {
2559 compiler: self.compiler,
2560 target: self.target,
2561 mode: Mode::Rustc,
2562 crates: self.crates,
2563 });
2564 }
2565
2566 fn metadata(&self) -> Option<StepMetadata> {
2567 Some(StepMetadata::test("CrateLibrustc", self.target))
2568 }
2569}
2570
2571fn run_cargo_test<'a>(
2575 cargo: builder::Cargo,
2576 libtest_args: &[&str],
2577 crates: &[String],
2578 description: impl Into<Option<&'a str>>,
2579 target: TargetSelection,
2580 builder: &Builder<'_>,
2581) -> bool {
2582 let compiler = cargo.compiler();
2583 let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, target, builder);
2584 let _time = helpers::timeit(builder);
2585 let _group = description.into().and_then(|what| {
2586 builder.msg_sysroot_tool(Kind::Test, compiler.stage, what, compiler.host, target)
2587 });
2588
2589 #[cfg(feature = "build-metrics")]
2590 builder.metrics.begin_test_suite(
2591 build_helper::metrics::TestSuiteMetadata::CargoPackage {
2592 crates: crates.iter().map(|c| c.to_string()).collect(),
2593 target: target.triple.to_string(),
2594 host: compiler.host.triple.to_string(),
2595 stage: compiler.stage,
2596 },
2597 builder,
2598 );
2599 add_flags_and_try_run_tests(builder, &mut cargo)
2600}
2601
2602fn prepare_cargo_test(
2604 cargo: builder::Cargo,
2605 libtest_args: &[&str],
2606 crates: &[String],
2607 target: TargetSelection,
2608 builder: &Builder<'_>,
2609) -> BootstrapCommand {
2610 let compiler = cargo.compiler();
2611 let mut cargo: BootstrapCommand = cargo.into();
2612
2613 if builder.config.cmd.bless() && !cargo.get_envs().any(|v| v.0 == "RUSTC_BLESS") {
2617 cargo.env("RUSTC_BLESS", "Gesundheit");
2618 }
2619
2620 if builder.kind == Kind::Test && !builder.fail_fast {
2624 cargo.arg("--no-fail-fast");
2625 }
2626
2627 if builder.config.json_output {
2628 cargo.arg("--message-format=json");
2629 }
2630
2631 match builder.doc_tests {
2632 DocTests::Only => {
2633 cargo.arg("--doc");
2634 }
2635 DocTests::No => {
2636 cargo.args(["--bins", "--examples", "--tests", "--benches"]);
2637 }
2638 DocTests::Yes => {}
2639 }
2640
2641 for krate in crates {
2642 cargo.arg("-p").arg(krate);
2643 }
2644
2645 cargo.arg("--").args(builder.config.test_args()).args(libtest_args);
2646 if !builder.config.verbose_tests {
2647 cargo.arg("--quiet");
2648 }
2649
2650 if builder.kind != Kind::Miri {
2659 let mut dylib_paths = builder.rustc_lib_paths(compiler);
2660 dylib_paths.push(builder.sysroot_target_libdir(compiler, target));
2661 helpers::add_dylib_path(dylib_paths, &mut cargo);
2662 }
2663
2664 if builder.remote_tested(target) {
2665 cargo.env(
2666 format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
2667 format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
2668 );
2669 } else if let Some(tool) = builder.runner(target) {
2670 cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), tool);
2671 }
2672
2673 cargo
2674}
2675
2676#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2684pub struct Crate {
2685 pub compiler: Compiler,
2686 pub target: TargetSelection,
2687 pub mode: Mode,
2688 pub crates: Vec<String>,
2689}
2690
2691impl Step for Crate {
2692 type Output = ();
2693 const DEFAULT: bool = true;
2694
2695 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2696 run.crate_or_deps("sysroot").crate_or_deps("coretests").crate_or_deps("alloctests")
2697 }
2698
2699 fn make_run(run: RunConfig<'_>) {
2700 let builder = run.builder;
2701 let host = run.build_triple();
2702 let compiler = builder.compiler_for(builder.top_stage, host, host);
2703 let crates = run
2704 .paths
2705 .iter()
2706 .map(|p| builder.crate_paths[&p.assert_single_path().path].clone())
2707 .collect();
2708
2709 builder.ensure(Crate { compiler, target: run.target, mode: Mode::Std, crates });
2710 }
2711
2712 fn run(self, builder: &Builder<'_>) {
2721 let compiler = self.compiler;
2722 let target = self.target;
2723 let mode = self.mode;
2724
2725 builder.ensure(Std::new(compiler, compiler.host).force_recompile(true));
2728
2729 let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
2734
2735 let mut cargo = if builder.kind == Kind::Miri {
2736 if builder.top_stage == 0 {
2737 eprintln!("ERROR: `x.py miri` requires stage 1 or higher");
2738 std::process::exit(1);
2739 }
2740
2741 let mut cargo = builder::Cargo::new(
2744 builder,
2745 compiler,
2746 mode,
2747 SourceType::InTree,
2748 target,
2749 Kind::MiriTest,
2750 );
2751 cargo.env("MIRI_REPLACE_LIBRS_IF_NOT_TEST", "1");
2763 cargo.rustflag("-Zforce-unstable-if-unmarked");
2767 cargo
2768 } else {
2769 if !builder.config.is_host_target(target) {
2771 builder.ensure(compile::Std::new(compiler, target).force_recompile(true));
2772 builder.ensure(RemoteCopyLibs { compiler, target });
2773 }
2774
2775 builder::Cargo::new(builder, compiler, mode, SourceType::InTree, target, builder.kind)
2777 };
2778
2779 match mode {
2780 Mode::Std => {
2781 if builder.kind == Kind::Miri {
2782 cargo
2788 .arg("--manifest-path")
2789 .arg(builder.src.join("library/sysroot/Cargo.toml"));
2790 } else {
2791 compile::std_cargo(builder, target, compiler.stage, &mut cargo);
2792 }
2793 }
2794 Mode::Rustc => {
2795 compile::rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates);
2796 }
2797 _ => panic!("can only test libraries"),
2798 };
2799
2800 let mut crates = self.crates.clone();
2801 if crates.iter().any(|crate_| crate_ == "core") {
2806 crates.push("coretests".to_owned());
2807 }
2808 if crates.iter().any(|crate_| crate_ == "alloc") {
2809 crates.push("alloctests".to_owned());
2810 }
2811
2812 run_cargo_test(cargo, &[], &crates, &*crate_description(&self.crates), target, builder);
2813 }
2814}
2815
2816#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2818pub struct CrateRustdoc {
2819 host: TargetSelection,
2820}
2821
2822impl Step for CrateRustdoc {
2823 type Output = ();
2824 const DEFAULT: bool = true;
2825 const ONLY_HOSTS: bool = true;
2826
2827 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2828 run.paths(&["src/librustdoc", "src/tools/rustdoc"])
2829 }
2830
2831 fn make_run(run: RunConfig<'_>) {
2832 let builder = run.builder;
2833
2834 builder.ensure(CrateRustdoc { host: run.target });
2835 }
2836
2837 fn run(self, builder: &Builder<'_>) {
2838 let target = self.host;
2839
2840 let compiler = if builder.download_rustc() {
2841 builder.compiler(builder.top_stage, target)
2842 } else {
2843 builder.compiler_for(builder.top_stage, target, target)
2848 };
2849 builder.std(compiler, target);
2854 builder.ensure(compile::Rustc::new(compiler, target));
2855
2856 let mut cargo = tool::prepare_tool_cargo(
2857 builder,
2858 compiler,
2859 Mode::ToolRustc,
2860 target,
2861 builder.kind,
2862 "src/tools/rustdoc",
2863 SourceType::InTree,
2864 &[],
2865 );
2866 if self.host.contains("musl") {
2867 cargo.arg("'-Ctarget-feature=-crt-static'");
2868 }
2869
2870 let libdir = if builder.download_rustc() {
2897 builder.rustc_libdir(compiler)
2898 } else {
2899 builder.sysroot_target_libdir(compiler, target).to_path_buf()
2900 };
2901 let mut dylib_path = dylib_path();
2902 dylib_path.insert(0, PathBuf::from(&*libdir));
2903 cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
2904
2905 run_cargo_test(cargo, &[], &["rustdoc:0.0.0".to_string()], "rustdoc", target, builder);
2906 }
2907}
2908
2909#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2910pub struct CrateRustdocJsonTypes {
2911 host: TargetSelection,
2912}
2913
2914impl Step for CrateRustdocJsonTypes {
2915 type Output = ();
2916 const DEFAULT: bool = true;
2917 const ONLY_HOSTS: bool = true;
2918
2919 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2920 run.path("src/rustdoc-json-types")
2921 }
2922
2923 fn make_run(run: RunConfig<'_>) {
2924 let builder = run.builder;
2925
2926 builder.ensure(CrateRustdocJsonTypes { host: run.target });
2927 }
2928
2929 fn run(self, builder: &Builder<'_>) {
2930 let target = self.host;
2931
2932 let compiler = builder.compiler_for(builder.top_stage, target, target);
2937 builder.ensure(compile::Rustc::new(compiler, target));
2938
2939 let cargo = tool::prepare_tool_cargo(
2940 builder,
2941 compiler,
2942 Mode::ToolRustc,
2943 target,
2944 builder.kind,
2945 "src/rustdoc-json-types",
2946 SourceType::InTree,
2947 &[],
2948 );
2949
2950 let libtest_args = if self.host.contains("musl") {
2952 ["'-Ctarget-feature=-crt-static'"].as_slice()
2953 } else {
2954 &[]
2955 };
2956
2957 run_cargo_test(
2958 cargo,
2959 libtest_args,
2960 &["rustdoc-json-types".to_string()],
2961 "rustdoc-json-types",
2962 target,
2963 builder,
2964 );
2965 }
2966}
2967
2968#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2978pub struct RemoteCopyLibs {
2979 compiler: Compiler,
2980 target: TargetSelection,
2981}
2982
2983impl Step for RemoteCopyLibs {
2984 type Output = ();
2985
2986 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2987 run.never()
2988 }
2989
2990 fn run(self, builder: &Builder<'_>) {
2991 let compiler = self.compiler;
2992 let target = self.target;
2993 if !builder.remote_tested(target) {
2994 return;
2995 }
2996
2997 builder.std(compiler, target);
2998
2999 builder.info(&format!("REMOTE copy libs to emulator ({target})"));
3000
3001 let remote_test_server =
3002 builder.ensure(tool::RemoteTestServer { build_compiler: compiler, target });
3003
3004 let tool = builder.tool_exe(Tool::RemoteTestClient);
3006 let mut cmd = command(&tool);
3007 cmd.arg("spawn-emulator")
3008 .arg(target.triple)
3009 .arg(&remote_test_server.tool_path)
3010 .arg(builder.tempdir());
3011 if let Some(rootfs) = builder.qemu_rootfs(target) {
3012 cmd.arg(rootfs);
3013 }
3014 cmd.run(builder);
3015
3016 for f in t!(builder.sysroot_target_libdir(compiler, target).read_dir()) {
3018 let f = t!(f);
3019 if helpers::is_dylib(&f.path()) {
3020 command(&tool).arg("push").arg(f.path()).run(builder);
3021 }
3022 }
3023 }
3024}
3025
3026#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3027pub struct Distcheck;
3028
3029impl Step for Distcheck {
3030 type Output = ();
3031
3032 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3033 run.alias("distcheck")
3034 }
3035
3036 fn make_run(run: RunConfig<'_>) {
3037 run.builder.ensure(Distcheck);
3038 }
3039
3040 fn run(self, builder: &Builder<'_>) {
3049 builder.info("Distcheck");
3050 let dir = builder.tempdir().join("distcheck");
3051 let _ = fs::remove_dir_all(&dir);
3052 t!(fs::create_dir_all(&dir));
3053
3054 builder.ensure(dist::PlainSourceTarball);
3056 builder.ensure(dist::Src);
3057
3058 command("tar")
3059 .arg("-xf")
3060 .arg(builder.ensure(dist::PlainSourceTarball).tarball())
3061 .arg("--strip-components=1")
3062 .current_dir(&dir)
3063 .run(builder);
3064 command("./configure")
3065 .args(&builder.config.configure_args)
3066 .arg("--enable-vendor")
3067 .current_dir(&dir)
3068 .run(builder);
3069 command(helpers::make(&builder.config.host_target.triple))
3070 .arg("check")
3071 .current_dir(&dir)
3072 .run(builder);
3073
3074 builder.info("Distcheck rust-src");
3076 let dir = builder.tempdir().join("distcheck-src");
3077 let _ = fs::remove_dir_all(&dir);
3078 t!(fs::create_dir_all(&dir));
3079
3080 command("tar")
3081 .arg("-xf")
3082 .arg(builder.ensure(dist::Src).tarball())
3083 .arg("--strip-components=1")
3084 .current_dir(&dir)
3085 .run(builder);
3086
3087 let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml");
3088 command(&builder.initial_cargo)
3089 .env("RUSTC_BOOTSTRAP", "1")
3092 .arg("generate-lockfile")
3093 .arg("--manifest-path")
3094 .arg(&toml)
3095 .current_dir(&dir)
3096 .run(builder);
3097 }
3098}
3099
3100#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3101pub struct Bootstrap;
3102
3103impl Step for Bootstrap {
3104 type Output = ();
3105 const DEFAULT: bool = true;
3106 const ONLY_HOSTS: bool = true;
3107
3108 fn run(self, builder: &Builder<'_>) {
3110 let host = builder.config.host_target;
3111 let compiler = builder.compiler(0, host);
3112 let _guard = builder.msg(Kind::Test, 0, "bootstrap", host, host);
3113
3114 builder.build.require_submodule("src/tools/cargo", None);
3116
3117 let mut check_bootstrap = command(builder.python());
3118 check_bootstrap
3119 .args(["-m", "unittest", "bootstrap_test.py"])
3120 .env("BUILD_DIR", &builder.out)
3121 .env("BUILD_PLATFORM", builder.build.host_target.triple)
3122 .env("BOOTSTRAP_TEST_RUSTC_BIN", &builder.initial_rustc)
3123 .env("BOOTSTRAP_TEST_CARGO_BIN", &builder.initial_cargo)
3124 .current_dir(builder.src.join("src/bootstrap/"));
3125 check_bootstrap.delay_failure().run(builder);
3128
3129 let mut cargo = tool::prepare_tool_cargo(
3130 builder,
3131 compiler,
3132 Mode::ToolBootstrap,
3133 host,
3134 Kind::Test,
3135 "src/bootstrap",
3136 SourceType::InTree,
3137 &[],
3138 );
3139
3140 cargo.release_build(false);
3141
3142 cargo
3143 .rustflag("-Cdebuginfo=2")
3144 .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
3145 .env("INSTA_WORKSPACE_ROOT", &builder.src)
3147 .env("RUSTC_BOOTSTRAP", "1");
3148
3149 run_cargo_test(cargo, &["--test-threads=1"], &[], None, host, builder);
3152 }
3153
3154 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3155 let runs_on_ci = run.builder.config.is_running_on_ci;
3159 run.path("src/bootstrap").default_condition(runs_on_ci)
3160 }
3161
3162 fn make_run(run: RunConfig<'_>) {
3163 run.builder.ensure(Bootstrap);
3164 }
3165}
3166
3167#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3168pub struct TierCheck {
3169 pub compiler: Compiler,
3170}
3171
3172impl Step for TierCheck {
3173 type Output = ();
3174 const DEFAULT: bool = true;
3175 const ONLY_HOSTS: bool = true;
3176
3177 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3178 run.path("src/tools/tier-check")
3179 }
3180
3181 fn make_run(run: RunConfig<'_>) {
3182 let compiler = run.builder.compiler_for(
3183 run.builder.top_stage,
3184 run.builder.build.host_target,
3185 run.target,
3186 );
3187 run.builder.ensure(TierCheck { compiler });
3188 }
3189
3190 fn run(self, builder: &Builder<'_>) {
3192 builder.std(self.compiler, self.compiler.host);
3193 let mut cargo = tool::prepare_tool_cargo(
3194 builder,
3195 self.compiler,
3196 Mode::ToolStd,
3197 self.compiler.host,
3198 Kind::Run,
3199 "src/tools/tier-check",
3200 SourceType::InTree,
3201 &[],
3202 );
3203 cargo.arg(builder.src.join("src/doc/rustc/src/platform-support.md"));
3204 cargo.arg(builder.rustc(self.compiler));
3205 if builder.is_verbose() {
3206 cargo.arg("--verbose");
3207 }
3208
3209 let _guard = builder.msg(
3210 Kind::Test,
3211 self.compiler.stage,
3212 "platform support check",
3213 self.compiler.host,
3214 self.compiler.host,
3215 );
3216 BootstrapCommand::from(cargo).delay_failure().run(builder);
3217 }
3218}
3219
3220#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3221pub struct LintDocs {
3222 pub compiler: Compiler,
3223 pub target: TargetSelection,
3224}
3225
3226impl Step for LintDocs {
3227 type Output = ();
3228 const DEFAULT: bool = true;
3229 const ONLY_HOSTS: bool = true;
3230
3231 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3232 run.path("src/tools/lint-docs")
3233 }
3234
3235 fn make_run(run: RunConfig<'_>) {
3236 run.builder.ensure(LintDocs {
3237 compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
3238 target: run.target,
3239 });
3240 }
3241
3242 fn run(self, builder: &Builder<'_>) {
3245 builder.ensure(crate::core::build_steps::doc::RustcBook {
3246 compiler: self.compiler,
3247 target: self.target,
3248 validate: true,
3249 });
3250 }
3251}
3252
3253#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3254pub struct RustInstaller;
3255
3256impl Step for RustInstaller {
3257 type Output = ();
3258 const ONLY_HOSTS: bool = true;
3259 const DEFAULT: bool = true;
3260
3261 fn run(self, builder: &Builder<'_>) {
3263 let bootstrap_host = builder.config.host_target;
3264 let compiler = builder.compiler(0, bootstrap_host);
3265 let cargo = tool::prepare_tool_cargo(
3266 builder,
3267 compiler,
3268 Mode::ToolBootstrap,
3269 bootstrap_host,
3270 Kind::Test,
3271 "src/tools/rust-installer",
3272 SourceType::InTree,
3273 &[],
3274 );
3275
3276 let _guard = builder.msg(
3277 Kind::Test,
3278 compiler.stage,
3279 "rust-installer",
3280 bootstrap_host,
3281 bootstrap_host,
3282 );
3283 run_cargo_test(cargo, &[], &[], None, bootstrap_host, builder);
3284
3285 if bootstrap_host != "x86_64-unknown-linux-gnu" {
3289 return;
3290 }
3291
3292 let mut cmd = command(builder.src.join("src/tools/rust-installer/test.sh"));
3293 let tmpdir = testdir(builder, compiler.host).join("rust-installer");
3294 let _ = std::fs::remove_dir_all(&tmpdir);
3295 let _ = std::fs::create_dir_all(&tmpdir);
3296 cmd.current_dir(&tmpdir);
3297 cmd.env("CARGO_TARGET_DIR", tmpdir.join("cargo-target"));
3298 cmd.env("CARGO", &builder.initial_cargo);
3299 cmd.env("RUSTC", &builder.initial_rustc);
3300 cmd.env("TMP_DIR", &tmpdir);
3301 cmd.delay_failure().run(builder);
3302 }
3303
3304 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3305 run.path("src/tools/rust-installer")
3306 }
3307
3308 fn make_run(run: RunConfig<'_>) {
3309 run.builder.ensure(Self);
3310 }
3311}
3312
3313#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3314pub struct TestHelpers {
3315 pub target: TargetSelection,
3316}
3317
3318impl Step for TestHelpers {
3319 type Output = ();
3320
3321 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3322 run.path("tests/auxiliary/rust_test_helpers.c")
3323 }
3324
3325 fn make_run(run: RunConfig<'_>) {
3326 run.builder.ensure(TestHelpers { target: run.target })
3327 }
3328
3329 fn run(self, builder: &Builder<'_>) {
3332 if builder.config.dry_run() {
3333 return;
3334 }
3335 let target = if self.target == "x86_64-fortanix-unknown-sgx" {
3339 TargetSelection::from_user("x86_64-unknown-linux-gnu")
3340 } else {
3341 self.target
3342 };
3343 let dst = builder.test_helpers_out(target);
3344 let src = builder.src.join("tests/auxiliary/rust_test_helpers.c");
3345 if up_to_date(&src, &dst.join("librust_test_helpers.a")) {
3346 return;
3347 }
3348
3349 let _guard = builder.msg_unstaged(Kind::Build, "test helpers", target);
3350 t!(fs::create_dir_all(&dst));
3351 let mut cfg = cc::Build::new();
3352
3353 if !target.is_msvc() {
3357 if let Some(ar) = builder.ar(target) {
3358 cfg.archiver(ar);
3359 }
3360 cfg.compiler(builder.cc(target));
3361 }
3362 cfg.cargo_metadata(false)
3363 .out_dir(&dst)
3364 .target(&target.triple)
3365 .host(&builder.config.host_target.triple)
3366 .opt_level(0)
3367 .warnings(false)
3368 .debug(false)
3369 .file(builder.src.join("tests/auxiliary/rust_test_helpers.c"))
3370 .compile("rust_test_helpers");
3371 }
3372}
3373
3374#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3375pub struct CodegenCranelift {
3376 compiler: Compiler,
3377 target: TargetSelection,
3378}
3379
3380impl Step for CodegenCranelift {
3381 type Output = ();
3382 const DEFAULT: bool = true;
3383 const ONLY_HOSTS: bool = true;
3384
3385 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3386 run.paths(&["compiler/rustc_codegen_cranelift"])
3387 }
3388
3389 fn make_run(run: RunConfig<'_>) {
3390 let builder = run.builder;
3391 let host = run.build_triple();
3392 let compiler = run.builder.compiler_for(run.builder.top_stage, host, host);
3393
3394 if builder.doc_tests == DocTests::Only {
3395 return;
3396 }
3397
3398 if builder.download_rustc() {
3399 builder.info("CI rustc uses the default codegen backend. skipping");
3400 return;
3401 }
3402
3403 if !target_supports_cranelift_backend(run.target) {
3404 builder.info("target not supported by rustc_codegen_cranelift. skipping");
3405 return;
3406 }
3407
3408 if builder.remote_tested(run.target) {
3409 builder.info("remote testing is not supported by rustc_codegen_cranelift. skipping");
3410 return;
3411 }
3412
3413 if !builder.config.codegen_backends(run.target).contains(&CodegenBackendKind::Cranelift) {
3414 builder.info("cranelift not in rust.codegen-backends. skipping");
3415 return;
3416 }
3417
3418 builder.ensure(CodegenCranelift { compiler, target: run.target });
3419 }
3420
3421 fn run(self, builder: &Builder<'_>) {
3422 let compiler = self.compiler;
3423 let target = self.target;
3424
3425 builder.std(compiler, target);
3426
3427 let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
3432
3433 let build_cargo = || {
3434 let mut cargo = builder::Cargo::new(
3435 builder,
3436 compiler,
3437 Mode::Codegen, SourceType::InTree,
3439 target,
3440 Kind::Run,
3441 );
3442
3443 cargo.current_dir(&builder.src.join("compiler/rustc_codegen_cranelift"));
3444 cargo
3445 .arg("--manifest-path")
3446 .arg(builder.src.join("compiler/rustc_codegen_cranelift/build_system/Cargo.toml"));
3447 compile::rustc_cargo_env(builder, &mut cargo, target);
3448
3449 cargo.env("CARGO_BUILD_INCREMENTAL", "false");
3451
3452 cargo
3453 };
3454
3455 builder.info(&format!(
3456 "{} cranelift stage{} ({} -> {})",
3457 Kind::Test.description(),
3458 compiler.stage,
3459 &compiler.host,
3460 target
3461 ));
3462 let _time = helpers::timeit(builder);
3463
3464 let download_dir = builder.out.join("cg_clif_download");
3466
3467 let mut cargo = build_cargo();
3476 cargo
3477 .arg("--")
3478 .arg("test")
3479 .arg("--download-dir")
3480 .arg(&download_dir)
3481 .arg("--out-dir")
3482 .arg(builder.stage_out(compiler, Mode::ToolRustc).join("cg_clif"))
3483 .arg("--no-unstable-features")
3484 .arg("--use-backend")
3485 .arg("cranelift")
3486 .arg("--sysroot")
3488 .arg("llvm")
3489 .arg("--skip-test")
3492 .arg("testsuite.extended_sysroot");
3493
3494 cargo.into_cmd().run(builder);
3495 }
3496}
3497
3498#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3499pub struct CodegenGCC {
3500 compiler: Compiler,
3501 target: TargetSelection,
3502}
3503
3504impl Step for CodegenGCC {
3505 type Output = ();
3506 const DEFAULT: bool = true;
3507 const ONLY_HOSTS: bool = true;
3508
3509 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3510 run.paths(&["compiler/rustc_codegen_gcc"])
3511 }
3512
3513 fn make_run(run: RunConfig<'_>) {
3514 let builder = run.builder;
3515 let host = run.build_triple();
3516 let compiler = run.builder.compiler_for(run.builder.top_stage, host, host);
3517
3518 if builder.doc_tests == DocTests::Only {
3519 return;
3520 }
3521
3522 if builder.download_rustc() {
3523 builder.info("CI rustc uses the default codegen backend. skipping");
3524 return;
3525 }
3526
3527 let triple = run.target.triple;
3528 let target_supported =
3529 if triple.contains("linux") { triple.contains("x86_64") } else { false };
3530 if !target_supported {
3531 builder.info("target not supported by rustc_codegen_gcc. skipping");
3532 return;
3533 }
3534
3535 if builder.remote_tested(run.target) {
3536 builder.info("remote testing is not supported by rustc_codegen_gcc. skipping");
3537 return;
3538 }
3539
3540 if !builder.config.codegen_backends(run.target).contains(&CodegenBackendKind::Gcc) {
3541 builder.info("gcc not in rust.codegen-backends. skipping");
3542 return;
3543 }
3544
3545 builder.ensure(CodegenGCC { compiler, target: run.target });
3546 }
3547
3548 fn run(self, builder: &Builder<'_>) {
3549 let compiler = self.compiler;
3550 let target = self.target;
3551
3552 let gcc = builder.ensure(Gcc { target });
3553
3554 builder.ensure(
3555 compile::Std::new(compiler, target)
3556 .extra_rust_args(&["-Csymbol-mangling-version=v0", "-Cpanic=abort"]),
3557 );
3558
3559 let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
3564
3565 let build_cargo = || {
3566 let mut cargo = builder::Cargo::new(
3567 builder,
3568 compiler,
3569 Mode::Codegen, SourceType::InTree,
3571 target,
3572 Kind::Run,
3573 );
3574
3575 cargo.current_dir(&builder.src.join("compiler/rustc_codegen_gcc"));
3576 cargo
3577 .arg("--manifest-path")
3578 .arg(builder.src.join("compiler/rustc_codegen_gcc/build_system/Cargo.toml"));
3579 compile::rustc_cargo_env(builder, &mut cargo, target);
3580 add_cg_gcc_cargo_flags(&mut cargo, &gcc);
3581
3582 cargo.env("CARGO_BUILD_INCREMENTAL", "false");
3584 cargo.rustflag("-Cpanic=abort");
3585
3586 cargo
3587 };
3588
3589 builder.info(&format!(
3590 "{} GCC stage{} ({} -> {})",
3591 Kind::Test.description(),
3592 compiler.stage,
3593 &compiler.host,
3594 target
3595 ));
3596 let _time = helpers::timeit(builder);
3597
3598 let mut cargo = build_cargo();
3607
3608 cargo
3609 .env("CG_RUSTFLAGS", "-Alinker-messages")
3611 .arg("--")
3612 .arg("test")
3613 .arg("--use-backend")
3614 .arg("gcc")
3615 .arg("--gcc-path")
3616 .arg(gcc.libgccjit.parent().unwrap())
3617 .arg("--out-dir")
3618 .arg(builder.stage_out(compiler, Mode::ToolRustc).join("cg_gcc"))
3619 .arg("--release")
3620 .arg("--mini-tests")
3621 .arg("--std-tests");
3622 cargo.args(builder.config.test_args());
3623
3624 cargo.into_cmd().run(builder);
3625 }
3626}
3627
3628#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3633pub struct TestFloatParse {
3634 path: PathBuf,
3635 host: TargetSelection,
3636}
3637
3638impl Step for TestFloatParse {
3639 type Output = ();
3640 const ONLY_HOSTS: bool = true;
3641 const DEFAULT: bool = true;
3642
3643 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3644 run.path("src/tools/test-float-parse")
3645 }
3646
3647 fn make_run(run: RunConfig<'_>) {
3648 for path in run.paths {
3649 let path = path.assert_single_path().path.clone();
3650 run.builder.ensure(Self { path, host: run.target });
3651 }
3652 }
3653
3654 fn run(self, builder: &Builder<'_>) {
3655 let bootstrap_host = builder.config.host_target;
3656 let compiler = builder.compiler(builder.top_stage, bootstrap_host);
3657 let path = self.path.to_str().unwrap();
3658 let crate_name = self.path.iter().next_back().unwrap().to_str().unwrap();
3659
3660 builder.ensure(tool::TestFloatParse { host: self.host });
3661
3662 let mut cargo_test = tool::prepare_tool_cargo(
3664 builder,
3665 compiler,
3666 Mode::ToolStd,
3667 bootstrap_host,
3668 Kind::Test,
3669 path,
3670 SourceType::InTree,
3671 &[],
3672 );
3673 cargo_test.allow_features(tool::TestFloatParse::ALLOW_FEATURES);
3674
3675 run_cargo_test(cargo_test, &[], &[], crate_name, bootstrap_host, builder);
3676
3677 let mut cargo_run = tool::prepare_tool_cargo(
3679 builder,
3680 compiler,
3681 Mode::ToolStd,
3682 bootstrap_host,
3683 Kind::Run,
3684 path,
3685 SourceType::InTree,
3686 &[],
3687 );
3688 cargo_run.allow_features(tool::TestFloatParse::ALLOW_FEATURES);
3689
3690 if !matches!(env::var("FLOAT_PARSE_TESTS_NO_SKIP_HUGE").as_deref(), Ok("1") | Ok("true")) {
3691 cargo_run.args(["--", "--skip-huge"]);
3692 }
3693
3694 cargo_run.into_cmd().run(builder);
3695 }
3696}
3697
3698#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
3702pub struct CollectLicenseMetadata;
3703
3704impl Step for CollectLicenseMetadata {
3705 type Output = PathBuf;
3706 const ONLY_HOSTS: bool = true;
3707
3708 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3709 run.path("src/tools/collect-license-metadata")
3710 }
3711
3712 fn make_run(run: RunConfig<'_>) {
3713 run.builder.ensure(CollectLicenseMetadata);
3714 }
3715
3716 fn run(self, builder: &Builder<'_>) -> Self::Output {
3717 let Some(reuse) = &builder.config.reuse else {
3718 panic!("REUSE is required to collect the license metadata");
3719 };
3720
3721 let dest = builder.src.join("license-metadata.json");
3722
3723 let mut cmd = builder.tool_cmd(Tool::CollectLicenseMetadata);
3724 cmd.env("REUSE_EXE", reuse);
3725 cmd.env("DEST", &dest);
3726 cmd.env("ONLY_CHECK", "1");
3727 cmd.run(builder);
3728
3729 dest
3730 }
3731}