1use std::collections::HashSet;
10use std::env::split_paths;
11use std::ffi::{OsStr, OsString};
12use std::path::{Path, PathBuf};
13use std::process::Command;
14use std::{env, fs, iter};
15
16use build_helper::git::get_closest_upstream_commit;
17
18use crate::core::backend::CodegenBackendKind;
19use crate::core::build_steps::compile::{ArtifactKeepMode, Std, run_cargo};
20use crate::core::build_steps::doc::{DocumentationFormat, prepare_doc_compiler};
21use crate::core::build_steps::format::InternalRustfmt;
22use crate::core::build_steps::gcc::{Gcc, GccTargetPair, add_cg_gcc_cargo_flags};
23use crate::core::build_steps::llvm::get_llvm_version;
24use crate::core::build_steps::run::{get_completion_paths, get_help_path};
25use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
26use crate::core::build_steps::test::compiletest::CompiletestMode;
27use crate::core::build_steps::test::failed_tests::{RecordFailedTests, SetupFailedTestsFile};
28use crate::core::build_steps::tool::{
29 self, RustcPrivateCompilers, SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, Tool,
30 ToolTargetBuildMode, get_tool_target_compiler,
31};
32use crate::core::build_steps::toolstate::ToolState;
33use crate::core::build_steps::{compile, dist, llvm};
34use crate::core::builder::{
35 self, Alias, Builder, CommandLineStep, Kind, RunConfig, ShouldRun, Step, StepMetadata,
36 crate_description,
37};
38use crate::core::compiler::Compiler;
39use crate::core::config::TargetSelection;
40use crate::core::config::flags::{Subcommand, get_completion, top_level_help};
41use crate::core::{android, debuggers};
42use crate::utils::build_stamp::{self, BuildStamp};
43use crate::utils::exec::{BootstrapCommand, command};
44use crate::utils::helpers::{
45 self, LldThreads, TestFilterCategory, add_dylib_path, add_rustdoc_cargo_linker_args,
46 dylib_path, dylib_path_var, envify, linker_args, linker_flags, t,
47 target_supports_cranelift_backend, up_to_date,
48};
49use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests};
50use crate::{CLang, GitRepo, Mode};
51
52mod compiletest;
53pub mod failed_tests;
54
55#[derive(PartialEq, Eq, Copy, Clone, Debug)]
56pub enum TestTarget {
57 Default,
59 AllTargets,
61 DocOnly,
63 Tests,
65}
66
67impl TestTarget {
68 pub(crate) fn runs_doctests(&self) -> bool {
69 matches!(self, TestTarget::DocOnly | TestTarget::Default)
70 }
71}
72
73#[derive(Debug, Clone, PartialEq, Eq, Hash)]
75pub struct CrateBootstrap {
76 path: PathBuf,
77 host: TargetSelection,
78}
79
80impl CommandLineStep for CrateBootstrap {
81 type Output = ();
82 const IS_HOST: bool = true;
83
84 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
85 run.path("src/tools/jsondoclint")
90 .path("src/tools/replace-version-placeholder")
91 .path("src/tools/coverage-dump")
92 .alias("tidyselftest")
95 }
96
97 fn is_default_step(_builder: &Builder<'_>) -> bool {
98 true
99 }
100
101 fn make_run(run: RunConfig<'_>) {
102 for path in run.paths {
105 let path = path.assert_single_path().path.clone();
106 run.builder.ensure(CrateBootstrap { host: run.target, path });
107 }
108 }
109
110 fn run(self, builder: &Builder<'_>) {
111 let bootstrap_host = builder.config.host_target;
112 let compiler = builder.compiler(0, bootstrap_host);
113 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
114 let mut path = self.path.to_str().unwrap();
115
116 if path == "tidyselftest" {
118 path = "src/tools/tidy";
119 }
120
121 let cargo = tool::prepare_tool_cargo(
122 builder,
123 compiler,
124 Mode::ToolBootstrap,
125 bootstrap_host,
126 Kind::Test,
127 path,
128 SourceType::InTree,
129 &[],
130 );
131
132 let crate_name = path.rsplit_once('/').unwrap().1;
133 run_cargo_test(cargo, &[], &[], crate_name, bootstrap_host, builder, record_failed_tests);
134 }
135
136 fn metadata(&self) -> Option<StepMetadata> {
137 Some(
138 StepMetadata::test("crate-bootstrap", self.host)
139 .with_metadata(self.path.as_path().to_string_lossy().to_string()),
140 )
141 }
142}
143
144#[derive(Debug, Clone, PartialEq, Eq, Hash)]
145pub struct Linkcheck {
146 host: TargetSelection,
147}
148
149impl CommandLineStep for Linkcheck {
150 type Output = ();
151 const IS_HOST: bool = true;
152
153 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
154 run.path("src/tools/linkchecker")
155 }
156
157 fn is_default_step(builder: &Builder<'_>) -> bool {
158 builder.config.docs
159 }
160
161 fn make_run(run: RunConfig<'_>) {
162 run.builder.ensure(Linkcheck { host: run.target });
163 }
164
165 fn run(self, builder: &Builder<'_>) {
170 let host = self.host;
171 let hosts = &builder.hosts;
172 let targets = &builder.targets;
173
174 if (hosts != targets) && !hosts.is_empty() && !targets.is_empty() {
179 panic!(
180 "Linkcheck currently does not support builds with different hosts and targets.
181You can skip linkcheck with --skip src/tools/linkchecker"
182 );
183 }
184
185 builder.info(&format!("Linkcheck ({host})"));
186
187 let bootstrap_host = builder.config.host_target;
189 let compiler = builder.compiler(0, bootstrap_host);
190 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
191
192 let cargo = tool::prepare_tool_cargo(
193 builder,
194 compiler,
195 Mode::ToolBootstrap,
196 bootstrap_host,
197 Kind::Test,
198 "src/tools/linkchecker",
199 SourceType::InTree,
200 &[],
201 );
202 run_cargo_test(
203 cargo,
204 &[],
205 &[],
206 "linkchecker self tests",
207 bootstrap_host,
208 builder,
209 record_failed_tests,
210 );
211
212 if !builder.test_target.runs_doctests() {
213 return;
214 }
215
216 builder.run_default_doc_steps();
218
219 let linkchecker = builder.tool_cmd(Tool::Linkchecker);
221
222 let _guard = builder.msg_test("Linkcheck", bootstrap_host, 1);
224 let _time = helpers::timeit(builder);
225 linkchecker.delay_failure().arg(builder.out.join(host).join("doc")).run(builder);
226 }
227
228 fn metadata(&self) -> Option<StepMetadata> {
229 Some(StepMetadata::test("link-check", self.host))
230 }
231}
232
233fn check_if_tidy_is_installed(builder: &Builder<'_>) -> bool {
234 command("tidy")
235 .allow_failure()
236 .arg("--version")
237 .cached()
239 .run_capture_stdout(builder)
240 .is_success()
241}
242
243#[derive(Debug, Clone, PartialEq, Eq, Hash)]
244pub struct HtmlCheck {
245 target: TargetSelection,
246}
247
248impl CommandLineStep for HtmlCheck {
249 type Output = ();
250 const IS_HOST: bool = true;
251
252 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
253 run.path("src/tools/html-checker")
254 }
255
256 fn is_default_step(builder: &Builder<'_>) -> bool {
257 check_if_tidy_is_installed(builder)
258 }
259
260 fn make_run(run: RunConfig<'_>) {
261 run.builder.ensure(HtmlCheck { target: run.target });
262 }
263
264 fn run(self, builder: &Builder<'_>) {
265 if !check_if_tidy_is_installed(builder) {
266 eprintln!("not running HTML-check tool because `tidy` is missing");
267 eprintln!(
268 "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."
269 );
270 panic!("Cannot run html-check tests");
271 }
272 builder.run_default_doc_steps();
274 builder.ensure(crate::core::build_steps::doc::Rustc::for_stage(
275 builder,
276 builder.top_stage,
277 self.target,
278 ));
279
280 builder
281 .tool_cmd(Tool::HtmlChecker)
282 .delay_failure()
283 .arg(builder.doc_out(self.target))
284 .run(builder);
285 }
286
287 fn metadata(&self) -> Option<StepMetadata> {
288 Some(StepMetadata::test("html-check", self.target))
289 }
290}
291
292#[derive(Debug, Clone, PartialEq, Eq, Hash)]
296pub struct Cargotest {
297 build_compiler: Compiler,
298 host: TargetSelection,
299}
300
301impl CommandLineStep for Cargotest {
302 type Output = ();
303 const IS_HOST: bool = true;
304
305 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
306 run.path("src/tools/cargotest")
307 }
308
309 fn make_run(run: RunConfig<'_>) {
310 if run.builder.top_stage == 0 {
311 eprintln!(
312 "ERROR: running cargotest with stage 0 is currently unsupported. Use at least stage 1."
313 );
314 helpers::exit_process(1);
315 }
316 run.builder.ensure(Cargotest {
320 build_compiler: run.builder.compiler(run.builder.top_stage - 1, run.target),
321 host: run.target,
322 });
323 }
324
325 fn run(self, builder: &Builder<'_>) {
330 let cargo =
340 builder.ensure(tool::Cargo::from_build_compiler(self.build_compiler, self.host));
341 let tested_compiler = builder.compiler(self.build_compiler.stage + 1, self.host);
342 builder.std(tested_compiler, self.host);
343
344 let out_dir = builder.out.join("ct");
348 t!(fs::create_dir_all(&out_dir));
349
350 let _time = helpers::timeit(builder);
351 let mut cmd = builder.tool_cmd(Tool::CargoTest);
352 cmd.arg(&cargo.tool_path)
353 .arg(&out_dir)
354 .args(builder.config.test_args())
355 .env("RUSTC", builder.rustc(tested_compiler))
356 .env("RUSTDOC", builder.rustdoc_for_compiler(tested_compiler));
357 add_rustdoc_cargo_linker_args(&mut cmd, builder, tested_compiler.host, LldThreads::No);
358 cmd.delay_failure().run(builder);
359 }
360
361 fn metadata(&self) -> Option<StepMetadata> {
362 Some(StepMetadata::test("cargotest", self.host).stage(self.build_compiler.stage + 1))
363 }
364}
365
366#[derive(Debug, Clone, PartialEq, Eq, Hash)]
369pub struct Cargo {
370 build_compiler: Compiler,
371 host: TargetSelection,
372}
373
374impl Cargo {
375 const CRATE_PATH: &str = "src/tools/cargo";
376}
377
378impl CommandLineStep for Cargo {
379 type Output = ();
380 const IS_HOST: bool = true;
381
382 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
383 run.path(Self::CRATE_PATH)
384 }
385
386 fn make_run(run: RunConfig<'_>) {
387 run.builder.ensure(Cargo {
388 build_compiler: get_tool_target_compiler(
389 run.builder,
390 ToolTargetBuildMode::Build(run.target),
391 ),
392 host: run.target,
393 });
394 }
395
396 fn run(self, builder: &Builder<'_>) {
398 builder.ensure(tool::Cargo::from_build_compiler(self.build_compiler, self.host));
402 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
403
404 let tested_compiler = builder.compiler(self.build_compiler.stage + 1, self.host);
405 builder.std(tested_compiler, self.host);
406 builder.rustdoc_for_compiler(tested_compiler);
410
411 let cargo = tool::prepare_tool_cargo(
412 builder,
413 self.build_compiler,
414 Mode::ToolTarget,
415 self.host,
416 Kind::Test,
417 Self::CRATE_PATH,
418 SourceType::Submodule,
419 &[],
420 );
421
422 let mut cargo = prepare_cargo_test(cargo, &[], &[], self.host, builder);
424
425 cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
428 cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1");
431
432 cargo.env("PATH", bin_path_for_cargo(builder, tested_compiler));
436
437 let mut existing_dylib_paths = cargo
442 .get_envs()
443 .find(|(k, _)| *k == OsStr::new(dylib_path_var()))
444 .and_then(|(_, v)| v)
445 .map(|value| split_paths(value).collect::<Vec<PathBuf>>())
446 .unwrap_or_default();
447 existing_dylib_paths.insert(0, builder.rustc_libdir(tested_compiler));
448 add_dylib_path(existing_dylib_paths, &mut cargo);
449
450 cargo.env("CARGO_RUSTC_CURRENT_DIR", builder.src.display().to_string());
454
455 #[cfg(feature = "build-metrics")]
456 builder.metrics.begin_test_suite(
457 build_helper::metrics::TestSuiteMetadata::CargoPackage {
458 crates: vec!["cargo".into()],
459 target: self.host.triple.to_string(),
460 host: self.host.triple.to_string(),
461 stage: self.build_compiler.stage + 1,
462 },
463 builder,
464 );
465
466 let _time = helpers::timeit(builder);
467 add_flags_and_try_run_tests(builder, &mut cargo, record_failed_tests);
468 }
469
470 fn metadata(&self) -> Option<StepMetadata> {
471 Some(StepMetadata::test("cargo", self.host).built_by(self.build_compiler))
472 }
473}
474
475#[derive(Debug, Clone, PartialEq, Eq, Hash)]
476pub struct RustAnalyzer {
477 compilers: RustcPrivateCompilers,
478}
479
480impl CommandLineStep for RustAnalyzer {
481 type Output = ();
482 const IS_HOST: bool = true;
483
484 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
485 run.path("src/tools/rust-analyzer")
486 }
487
488 fn is_default_step(_builder: &Builder<'_>) -> bool {
489 true
490 }
491
492 fn make_run(run: RunConfig<'_>) {
493 run.builder.ensure(Self {
494 compilers: RustcPrivateCompilers::new(
495 run.builder,
496 run.builder.top_stage,
497 run.builder.host_target,
498 ),
499 });
500 }
501
502 fn run(self, builder: &Builder<'_>) {
504 let build_compiler = self.compilers.build_compiler();
505 let target = self.compilers.target();
506 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
507
508 if target.starts_with("i686") {
518 return;
519 }
520
521 let suite = "src/tools/rust-analyzer";
522 let mut cargo = tool::prepare_tool_cargo(
523 builder,
524 build_compiler,
525 Mode::ToolRustcPrivate,
526 target,
527 Kind::Test,
528 suite,
529 SourceType::InTree,
530 &["in-rust-tree".to_owned()],
531 );
532 cargo.allow_features(tool::RustAnalyzer::ALLOW_FEATURES);
533
534 cargo.env("SKIP_SLOW_TESTS", "1");
541
542 cargo.arg("--workspace");
548 cargo.arg("--exclude=xtask");
549
550 if build_compiler.stage == 0 {
551 cargo.arg("--exclude=proc-macro-srv");
554 cargo.arg("--exclude=proc-macro-srv-cli");
555 }
556
557 let mut skip_tests = vec![];
558
559 skip_tests.extend_from_slice(&[
567 "tests::smoke_test_real_sysroot_cargo",
570 "check_code_formatting",
573 ]);
574
575 let skip_tests = skip_tests.iter().map(|name| format!("--skip={name}")).collect::<Vec<_>>();
576 let skip_tests = skip_tests.iter().map(|s| s.as_str()).collect::<Vec<_>>();
577
578 cargo.add_rustc_lib_path(builder);
579 run_cargo_test(
580 cargo,
581 skip_tests.as_slice(),
582 &[],
583 "rust-analyzer",
584 target,
585 builder,
586 record_failed_tests,
587 );
588 }
589
590 fn metadata(&self) -> Option<StepMetadata> {
591 Some(
592 StepMetadata::test("rust-analyzer", self.compilers.target())
593 .built_by(self.compilers.build_compiler()),
594 )
595 }
596}
597
598#[derive(Debug, Clone, PartialEq, Eq, Hash)]
600pub struct Rustfmt {
601 compilers: RustcPrivateCompilers,
602}
603
604impl CommandLineStep for Rustfmt {
605 type Output = ();
606 const IS_HOST: bool = true;
607
608 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
609 run.path("src/tools/rustfmt")
610 }
611
612 fn make_run(run: RunConfig<'_>) {
613 run.builder.ensure(Rustfmt {
614 compilers: RustcPrivateCompilers::new(
615 run.builder,
616 run.builder.top_stage,
617 run.builder.host_target,
618 ),
619 });
620 }
621
622 fn run(self, builder: &Builder<'_>) {
624 let build_compiler = self.compilers.build_compiler();
625 let target = self.compilers.target();
626 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
627
628 builder.ensure(compile::Rustc::new(build_compiler, target));
632
633 let mut cargo = tool::prepare_tool_cargo(
634 builder,
635 build_compiler,
636 Mode::ToolRustcPrivate,
637 target,
638 Kind::Test,
639 "src/tools/rustfmt",
640 SourceType::InTree,
641 &[],
642 );
643
644 let dir = testdir(builder, target);
645 t!(fs::create_dir_all(&dir));
646 cargo.env("RUSTFMT_TEST_DIR", dir);
647
648 cargo.add_rustc_lib_path(builder);
649
650 run_cargo_test(cargo, &[], &[], "rustfmt", target, builder, record_failed_tests);
651 }
652
653 fn metadata(&self) -> Option<StepMetadata> {
654 Some(
655 StepMetadata::test("rustfmt", self.compilers.target())
656 .built_by(self.compilers.build_compiler()),
657 )
658 }
659}
660
661#[derive(Debug, Clone, PartialEq, Eq, Hash)]
662pub struct Miri {
663 target: TargetSelection,
664}
665
666impl Miri {
667 pub fn build_miri_sysroot(
669 builder: &Builder<'_>,
670 compiler: Compiler,
671 target: TargetSelection,
672 ) -> PathBuf {
673 let miri_sysroot = builder.out.join(compiler.host).join("miri-sysroot");
674 let mut cargo = builder::Cargo::new(
675 builder,
676 compiler,
677 Mode::Std,
678 SourceType::Submodule,
679 target,
680 Kind::MiriSetup,
681 );
682
683 cargo.env("MIRI_LIB_SRC", builder.src.join("library"));
685 cargo.env("MIRI_SYSROOT", &miri_sysroot);
687
688 let mut cargo = BootstrapCommand::from(cargo);
689 let _guard =
690 builder.msg(Kind::Build, "miri sysroot", Mode::ToolRustcPrivate, compiler, target);
691 cargo.run(builder);
692
693 cargo.arg("--print-sysroot");
699
700 builder.do_if_verbose(|| println!("running: {cargo:?}"));
701 let stdout = cargo.run_capture_stdout(builder).stdout();
702 let sysroot = stdout.trim_end();
704 builder.do_if_verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
705 PathBuf::from(sysroot)
706 }
707}
708
709impl CommandLineStep for Miri {
710 type Output = ();
711
712 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
713 run.path("src/tools/miri")
714 }
715
716 fn make_run(run: RunConfig<'_>) {
717 run.builder.ensure(Miri { target: run.target });
718 }
719
720 fn run(self, builder: &Builder<'_>) {
722 let host = builder.build.host_target;
723 let target = self.target;
724 let stage = builder.top_stage;
725 if stage == 0 {
726 eprintln!("miri cannot be tested at stage 0");
727 std::process::exit(1);
728 }
729
730 let compilers = RustcPrivateCompilers::new(builder, stage, host);
732
733 let miri = builder.ensure(tool::Miri::from_compilers(compilers));
735 builder.ensure(tool::CargoMiri::from_compilers(compilers));
737
738 let target_compiler = compilers.target_compiler();
739
740 let miri_sysroot = Miri::build_miri_sysroot(builder, target_compiler, target);
743 builder.std(target_compiler, host);
744 let host_sysroot = builder.sysroot(target_compiler);
745
746 if !builder.config.dry_run() {
749 let ui_test_dep_dir = builder
752 .stage_out(miri.build_compiler, Mode::ToolStd)
753 .join(host)
754 .join("tmp")
755 .join("miri_ui");
756 build_stamp::clear_if_dirty(builder, &ui_test_dep_dir, &miri_sysroot);
760 }
761
762 let mut cargo = tool::prepare_tool_cargo(
765 builder,
766 miri.build_compiler,
767 Mode::ToolRustcPrivate,
768 host,
769 Kind::Test,
770 "src/tools/miri",
771 SourceType::InTree,
772 &[],
773 );
774
775 cargo.add_rustc_lib_path(builder);
776
777 let mut cargo = prepare_cargo_test(cargo, &[], &[], host, builder);
780
781 cargo.env("MIRI_SYSROOT", &miri_sysroot);
783 cargo.env("MIRI_HOST_SYSROOT", &host_sysroot);
784
785 cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg());
787
788 {
789 let _guard = builder.msg_test("miri", target, target_compiler.stage);
790 let _time = helpers::timeit(builder);
791 cargo.run(builder);
792 }
793 }
794}
795
796#[derive(Debug, Clone, PartialEq, Eq, Hash)]
799pub struct CargoMiri {
800 target: TargetSelection,
801}
802
803impl CommandLineStep for CargoMiri {
804 type Output = ();
805
806 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
807 run.path("src/tools/miri/cargo-miri")
808 }
809
810 fn make_run(run: RunConfig<'_>) {
811 run.builder.ensure(CargoMiri { target: run.target });
812 }
813
814 fn run(self, builder: &Builder<'_>) {
816 let host = builder.build.host_target;
817 let target = self.target;
818 let stage = builder.top_stage;
819 if stage == 0 {
820 eprintln!("cargo-miri cannot be tested at stage 0");
821 std::process::exit(1);
822 }
823
824 let build_compiler = builder.compiler(stage, host);
826
827 let mut cargo = tool::prepare_tool_cargo(
832 builder,
833 build_compiler,
834 Mode::ToolStd, target,
836 Kind::MiriTest,
837 "src/tools/miri/test-cargo-miri",
838 SourceType::Submodule,
839 &[],
840 );
841 cargo.arg("--workspace");
843 cargo.env("MIRIFLAGS", "-Zmiri-disable-isolation");
845
846 if stage >= 2 {
849 let built_cargo = builder
850 .ensure(tool::Cargo::from_build_compiler(
851 builder.compiler(0, builder.host_target),
854 builder.host_target,
855 ))
856 .tool_path;
857 cargo.env("CARGO", built_cargo);
858 }
859
860 match builder.test_target {
863 TestTarget::AllTargets => {
864 cargo.args(["--lib", "--bins", "--examples", "--tests", "--benches"])
865 }
866 TestTarget::Default => &mut cargo,
867 TestTarget::DocOnly => cargo.arg("--doc"),
868 TestTarget::Tests => cargo.arg("--tests"),
869 };
870 cargo.arg("--").args(builder.config.test_args());
871
872 let mut cargo = BootstrapCommand::from(cargo);
874 {
875 let _guard = builder.msg_test("cargo-miri", target, stage);
876 let _time = helpers::timeit(builder);
877 cargo.run(builder);
878 }
879 }
880}
881
882#[derive(Debug, Clone, PartialEq, Eq, Hash)]
883pub struct Priroda {
884 target: TargetSelection,
885}
886
887impl CommandLineStep for Priroda {
888 type Output = ();
889
890 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
891 run.path("src/tools/miri/priroda")
892 }
893
894 fn make_run(run: RunConfig<'_>) {
895 run.builder.ensure(Priroda { target: run.target });
896 }
897
898 fn run(self, builder: &Builder<'_>) {
900 let host = builder.build.host_target;
901 let target = self.target;
902 let stage = builder.top_stage;
903
904 let compilers = RustcPrivateCompilers::new(builder, stage, host);
906 let miri = builder.ensure(tool::Miri::from_compilers(compilers));
907 let target_compiler = compilers.target_compiler();
908
909 let miri_sysroot = Miri::build_miri_sysroot(builder, target_compiler, target);
910 builder.std(target_compiler, host);
911 let host_sysroot = builder.sysroot(target_compiler);
912
913 let mut cargo = tool::prepare_tool_cargo(
914 builder,
915 miri.build_compiler,
916 Mode::ToolRustcPrivate,
917 host,
918 Kind::Test,
919 "src/tools/miri/priroda",
920 SourceType::InTree,
921 &[],
922 );
923
924 cargo.add_rustc_lib_path(builder);
925
926 let mut cargo = prepare_cargo_test(cargo, &[], &[], host, builder);
927
928 cargo.env("MIRI_SYSROOT", &miri_sysroot);
929 cargo.env("MIRI_HOST_SYSROOT", &host_sysroot);
930 cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg());
931
932 {
933 let _guard = builder.msg_test("priroda", target, target_compiler.stage);
934 let _time = helpers::timeit(builder);
935 cargo.run(builder);
936 }
937 }
938}
939
940#[derive(Debug, Clone, PartialEq, Eq, Hash)]
941pub struct CompiletestTest {
942 host: TargetSelection,
943}
944
945impl CommandLineStep for CompiletestTest {
946 type Output = ();
947
948 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
949 run.path("src/tools/compiletest")
950 }
951
952 fn make_run(run: RunConfig<'_>) {
953 run.builder.ensure(CompiletestTest { host: run.target });
954 }
955
956 fn run(self, builder: &Builder<'_>) {
958 let host = self.host;
959 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
960
961 if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 {
967 eprintln!("\
968ERROR: `--stage 0` causes compiletest to query information from the stage0 (precompiled) compiler, instead of the in-tree compiler, which can cause some tests to fail inappropriately
969NOTE: 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`."
970 );
971 helpers::exit_process(1);
972 }
973
974 let bootstrap_compiler = builder.compiler(0, host);
975 let staged_compiler = builder.compiler(builder.top_stage, host);
976
977 let mut cargo = tool::prepare_tool_cargo(
978 builder,
979 bootstrap_compiler,
980 Mode::ToolBootstrap,
981 host,
982 Kind::Test,
983 "src/tools/compiletest",
984 SourceType::InTree,
985 &[],
986 );
987
988 cargo.env("TEST_RUSTC", builder.rustc(staged_compiler));
992
993 run_cargo_test(
994 cargo,
995 &[],
996 &[],
997 "compiletest self test",
998 host,
999 builder,
1000 record_failed_tests,
1001 );
1002 }
1003}
1004
1005#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1009pub struct StdarchVerify;
1010
1011impl CommandLineStep for StdarchVerify {
1012 type Output = ();
1013 const IS_HOST: bool = true;
1014
1015 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1016 run.path("library/stdarch/crates/stdarch-verify")
1017 }
1018
1019 fn is_default_step(_builder: &Builder<'_>) -> bool {
1020 true
1021 }
1022
1023 fn make_run(run: RunConfig<'_>) {
1024 run.builder.ensure(StdarchVerify);
1025 }
1026
1027 fn run(self, builder: &Builder<'_>) {
1028 let host = builder.config.host_target;
1029 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
1030 let build_compiler = builder.compiler(0, host);
1031
1032 let cargo = tool::prepare_tool_cargo(
1033 builder,
1034 build_compiler,
1035 Mode::ToolBootstrap,
1036 host,
1037 Kind::Test,
1038 "library/stdarch/crates/stdarch-verify",
1039 SourceType::InTree,
1040 &[],
1041 );
1042
1043 run_cargo_test(
1044 cargo,
1045 &[],
1046 &["stdarch-verify".to_string()],
1047 Some("stdarch-verify"),
1048 host,
1049 builder,
1050 record_failed_tests,
1051 );
1052 }
1053}
1054
1055#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1065pub struct IntrinsicTest {
1066 host: TargetSelection,
1067}
1068
1069impl CommandLineStep for IntrinsicTest {
1070 type Output = ();
1071 const IS_HOST: bool = true;
1072
1073 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1074 run.alias("intrinsic-test")
1075 }
1076
1077 fn is_default_step(_builder: &Builder<'_>) -> bool {
1078 true
1079 }
1080
1081 fn make_run(run: RunConfig<'_>) {
1082 let target = run.target;
1083 let builder = run.builder;
1084
1085 let is_explicit =
1086 builder.config.paths.iter().any(|p| p.to_string_lossy() == "intrinsic-test");
1087
1088 if target.contains("x86_64-unknown-linux") && builder.config.sde.is_none() && is_explicit {
1089 panic!(
1090 "SDE is required to run intrinsic-test. Please configure `build.sde` in config.toml."
1091 );
1092 }
1093
1094 builder.ensure(IntrinsicTest { host: target });
1095 }
1096
1097 fn run(self, builder: &Builder<'_>) {
1098 let host = self.host;
1099 if cfg!(test)
1100 || (!host.contains("aarch64-unknown-linux") && !host.contains("x86_64-unknown-linux"))
1101 {
1102 builder.info(&format!("Skipping intrinsic-test, as it is not available for {host}"));
1103 return;
1104 }
1105
1106 let (input_file, skip_file, cflags, sde_runner) = if host.contains("x86_64-unknown-linux") {
1107 let Some(sde) = &builder.config.sde else {
1108 builder.info("Skipping intrinsic-test because `build.sde` is not configured");
1109 return;
1110 };
1111
1112 let cpuid_def =
1113 builder.src.join("library/stdarch/ci/docker/x86_64-unknown-linux-gnu/cpuid.def");
1114 let sde_runner = format!(
1115 "{} -cpuid-in {} -rtm-mode full -tsx --",
1116 sde.display(),
1117 cpuid_def.display()
1118 );
1119
1120 (
1121 builder.src.join("library/stdarch/intrinsics_data/x86-intel.xml"),
1122 [
1123 builder
1124 .src
1125 .join("library/stdarch/crates/intrinsic-test/missing_x86_common.txt"),
1126 builder.src.join("library/stdarch/crates/intrinsic-test/missing_x86_gcc.txt"),
1127 ],
1128 "-I/usr/include/x86_64-linux-gnu/",
1129 Some(sde_runner),
1130 )
1131 } else if host.contains("aarch64-unknown-linux") {
1132 (
1133 builder.src.join("library/stdarch/intrinsics_data/arm_intrinsics.json"),
1134 [
1135 builder
1136 .src
1137 .join("library/stdarch/crates/intrinsic-test/missing_aarch64_common.txt"),
1138 builder
1139 .src
1140 .join("library/stdarch/crates/intrinsic-test/missing_aarch64_gcc.txt"),
1141 ],
1142 "-I/usr/aarch64-linux-gnu/include/",
1143 None,
1144 )
1145 } else {
1146 panic!("intrinsic-test only supports aarch64/x86_64 Linux, got {host}");
1147 };
1148
1149 let out_dir = builder.out.join(host).join("intrinsic-test");
1150 t!(fs::create_dir_all(&out_dir));
1151
1152 let crates_link = out_dir.join("crates");
1153 if !crates_link.exists() {
1154 t!(
1155 helpers::symlink_dir(
1156 &builder.config,
1157 &builder.src.join("library/stdarch/crates"),
1158 &crates_link
1159 ),
1160 format!("failed to symlink stdarch crates into {}", crates_link.display())
1161 );
1162 }
1163
1164 let mut cmd = builder.tool_cmd(Tool::IntrinsicTest);
1165 cmd.current_dir(&out_dir);
1166 cmd.arg(&input_file);
1167 cmd.arg("--target").arg(&*host.triple);
1168 for skip in &skip_file {
1169 cmd.arg("--skip").arg(skip);
1170 }
1171 cmd.arg("--sample-percentage").arg("100");
1172 cmd.arg("--cc-arg-style").arg("gcc");
1173 cmd.env("CC", builder.cc(host));
1174 cmd.env("CFLAGS", cflags);
1175 let Some(rustfmt_path) = builder.ensure(InternalRustfmt) else {
1178 eprintln!(
1179 "WARNING: intrinsic-test skipped because rustfmt is required but not available on this channel"
1180 );
1181 return;
1182 };
1183
1184 let mut path_dirs: Vec<PathBuf> = Vec::new();
1185 if let Some(cargo_dir) = builder.initial_cargo.parent() {
1186 path_dirs.push(cargo_dir.to_path_buf());
1187 }
1188 if let Some(rustfmt_dir) = rustfmt_path.parent() {
1189 path_dirs.push(rustfmt_dir.to_path_buf());
1190 }
1191 let old_path = env::var_os("PATH").unwrap_or_default();
1192 let new_path = env::join_paths(path_dirs.into_iter().chain(env::split_paths(&old_path)))
1193 .expect("could not build PATH for intrinsic-test");
1194 cmd.env("PATH", new_path);
1195 cmd.run(builder);
1196
1197 let tested_compiler = builder.compiler(builder.top_stage, host);
1198 builder.std(tested_compiler, host);
1199 let rustc = builder.rustc(tested_compiler);
1200
1201 let manifest = out_dir.join("rust_programs/Cargo.toml");
1202 let mut cargo = command(&builder.initial_cargo);
1203 cargo.arg("test");
1204 cargo.arg("--tests");
1205 cargo.arg("--manifest-path").arg(&manifest);
1206 cargo.arg("--target").arg(&*host.triple);
1207 cargo.arg("--profile").arg("release");
1208 cargo.env("CC", builder.cc(host));
1209 cargo.env("CFLAGS", cflags);
1210 cargo.env("RUSTC", rustc);
1211 cargo.env("RUSTC_BOOTSTRAP", "1");
1212 if let Some(runner) = sde_runner {
1213 cargo.env("CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER", runner);
1214 }
1215 cargo.run(builder);
1216 }
1217
1218 fn metadata(&self) -> Option<StepMetadata> {
1219 Some(StepMetadata::test("intrinsic-test", self.host))
1220 }
1221}
1222
1223#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1224pub struct Clippy {
1225 compilers: RustcPrivateCompilers,
1226}
1227
1228impl CommandLineStep for Clippy {
1229 type Output = ();
1230 const IS_HOST: bool = true;
1231
1232 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1233 run.suite_path("src/tools/clippy/tests").path("src/tools/clippy")
1234 }
1235
1236 fn is_default_step(_builder: &Builder<'_>) -> bool {
1237 false
1238 }
1239
1240 fn make_run(run: RunConfig<'_>) {
1241 run.builder.ensure(Clippy {
1242 compilers: RustcPrivateCompilers::new(
1243 run.builder,
1244 run.builder.top_stage,
1245 run.builder.host_target,
1246 ),
1247 });
1248 }
1249
1250 fn run(self, builder: &Builder<'_>) {
1252 let target = self.compilers.target();
1253
1254 let target_compiler = self.compilers.target_compiler();
1258 let build_compiler = self.compilers.build_compiler();
1259
1260 builder.ensure(compile::Rustc::new(build_compiler, target));
1264
1265 let mut cargo = tool::prepare_tool_cargo(
1266 builder,
1267 build_compiler,
1268 Mode::ToolRustcPrivate,
1269 target,
1270 Kind::Test,
1271 "src/tools/clippy",
1272 SourceType::InTree,
1273 &[],
1274 );
1275
1276 cargo.env("RUSTC_TEST_SUITE", builder.rustc(build_compiler));
1277 cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(build_compiler));
1278 let host_libs = builder
1279 .stage_out(build_compiler, Mode::ToolRustcPrivate)
1280 .join(builder.cargo_dir(Mode::ToolRustcPrivate));
1281 cargo.env("HOST_LIBS", host_libs);
1282
1283 builder.std(target_compiler, target);
1285 cargo.env("TEST_SYSROOT", builder.sysroot(target_compiler));
1286 cargo.env("TEST_RUSTC", builder.rustc(target_compiler));
1287 cargo.env("TEST_RUSTC_LIB", builder.rustc_libdir(target_compiler));
1288
1289 'partially_test: {
1291 let paths = &builder.config.paths[..];
1292 let mut test_names = Vec::new();
1293 for path in paths {
1294 match helpers::is_valid_test_suite_arg(path, "src/tools/clippy/tests", builder) {
1295 TestFilterCategory::Arg(path) => {
1296 test_names.push(path);
1297 }
1298 TestFilterCategory::Fullsuite => {
1299 break 'partially_test;
1301 }
1302 TestFilterCategory::Uninteresting => {}
1303 }
1304 }
1305 cargo.env("TESTNAME", test_names.join(","));
1306 }
1307
1308 cargo.add_rustc_lib_path(builder);
1309 let cargo = prepare_cargo_test(cargo, &[], &[], target, builder);
1310
1311 let _guard = builder.msg_test("clippy", target, target_compiler.stage);
1312
1313 if cargo.allow_failure().run(builder) {
1315 return;
1317 }
1318
1319 if !builder.config.cmd.bless() {
1320 helpers::exit_process(1);
1321 }
1322 }
1323
1324 fn metadata(&self) -> Option<StepMetadata> {
1325 Some(
1326 StepMetadata::test("clippy", self.compilers.target())
1327 .built_by(self.compilers.build_compiler()),
1328 )
1329 }
1330}
1331
1332fn bin_path_for_cargo(builder: &Builder<'_>, compiler: Compiler) -> OsString {
1333 let path = builder.sysroot(compiler).join("bin");
1334 let old_path = env::var_os("PATH").unwrap_or_default();
1335 env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("")
1336}
1337
1338#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1340pub struct RustdocTheme {
1341 test_compiler: Compiler,
1343}
1344
1345impl CommandLineStep for RustdocTheme {
1346 type Output = ();
1347 const IS_HOST: bool = true;
1348
1349 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1350 run.path("src/tools/rustdoc-themes")
1351 }
1352
1353 fn is_default_step(_builder: &Builder<'_>) -> bool {
1354 true
1355 }
1356
1357 fn make_run(run: RunConfig<'_>) {
1358 let test_compiler = run.builder.compiler(run.builder.top_stage, run.target);
1359
1360 run.builder.ensure(RustdocTheme { test_compiler });
1361 }
1362
1363 fn run(self, builder: &Builder<'_>) {
1364 let rustdoc = builder.bootstrap_out.join("rustdoc");
1365 let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
1366 cmd.arg(rustdoc.to_str().unwrap())
1367 .arg(builder.src.join("src/librustdoc/html/static/css/rustdoc.css").to_str().unwrap())
1368 .env("RUSTC_STAGE", self.test_compiler.stage.to_string())
1369 .env("RUSTC_SYSROOT", builder.sysroot(self.test_compiler))
1370 .env(
1371 "RUSTDOC_LIBDIR",
1372 builder.sysroot_target_libdir(self.test_compiler, self.test_compiler.host),
1373 )
1374 .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
1375 .env("RUSTDOC_REAL", builder.rustdoc_for_compiler(self.test_compiler))
1376 .env("RUSTC_BOOTSTRAP", "1");
1377 cmd.args(linker_args(builder, self.test_compiler.host, LldThreads::No));
1378
1379 cmd.delay_failure().run(builder);
1380 }
1381
1382 fn metadata(&self) -> Option<StepMetadata> {
1383 Some(
1384 StepMetadata::test("rustdoc-theme", self.test_compiler.host)
1385 .stage(self.test_compiler.stage),
1386 )
1387 }
1388}
1389
1390#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1392pub struct RustdocJSStd {
1393 build_compiler: Compiler,
1395 target: TargetSelection,
1396}
1397
1398impl CommandLineStep for RustdocJSStd {
1399 type Output = ();
1400 const IS_HOST: bool = true;
1401
1402 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1403 run.suite_path("tests/rustdoc-js-std")
1404 }
1405
1406 fn is_default_step(builder: &Builder<'_>) -> bool {
1407 builder.config.nodejs.is_some()
1408 }
1409
1410 fn make_run(run: RunConfig<'_>) {
1411 run.builder.ensure(RustdocJSStd {
1412 build_compiler: run.builder.compiler(run.builder.top_stage, run.builder.host_target),
1413 target: run.target,
1414 });
1415 }
1416
1417 fn run(self, builder: &Builder<'_>) {
1418 let nodejs =
1419 builder.config.nodejs.as_ref().expect("need nodejs to run rustdoc-js-std tests");
1420 let mut command = command(nodejs);
1421 command
1422 .arg(builder.src.join("src/tools/rustdoc-js/tester.js"))
1423 .arg("--crate-name")
1424 .arg("std")
1425 .arg("--resource-suffix")
1426 .arg(&builder.version)
1427 .arg("--doc-folder")
1428 .arg(builder.doc_out(self.target))
1429 .arg("--test-folder")
1430 .arg(builder.src.join("tests/rustdoc-js-std"));
1431
1432 let full_suite = builder.paths.iter().any(|path| {
1433 matches!(
1434 helpers::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder),
1435 TestFilterCategory::Fullsuite
1436 )
1437 });
1438
1439 if !full_suite {
1442 for path in &builder.paths {
1443 if let TestFilterCategory::Arg(p) =
1444 helpers::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder)
1445 {
1446 if !p.ends_with(".js") {
1447 eprintln!("A non-js file was given: `{}`", path.display());
1448 panic!("Cannot run rustdoc-js-std tests");
1449 }
1450 command.arg("--test-file").arg(path);
1451 }
1452 }
1453 }
1454
1455 builder.ensure(crate::core::build_steps::doc::Std::from_build_compiler(
1456 self.build_compiler,
1457 self.target,
1458 DocumentationFormat::Html,
1459 ));
1460 let _guard = builder.msg_test("rustdoc-js-std", self.target, self.build_compiler.stage);
1461 command.run(builder);
1462 }
1463
1464 fn metadata(&self) -> Option<StepMetadata> {
1465 Some(StepMetadata::test("rustdoc-js-std", self.target).stage(self.build_compiler.stage))
1466 }
1467}
1468
1469#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1470pub struct RustdocJSNotStd {
1471 pub target: TargetSelection,
1472 pub compiler: Compiler,
1473}
1474
1475impl CommandLineStep for RustdocJSNotStd {
1476 type Output = ();
1477 const IS_HOST: bool = true;
1478
1479 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1480 run.suite_path("tests/rustdoc-js")
1481 }
1482
1483 fn is_default_step(builder: &Builder<'_>) -> bool {
1484 builder.config.nodejs.is_some()
1485 }
1486
1487 fn make_run(run: RunConfig<'_>) {
1488 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1489 run.builder.ensure(RustdocJSNotStd { target: run.target, compiler });
1490 }
1491
1492 fn run(self, builder: &Builder<'_>) {
1493 builder.ensure(Compiletest {
1494 test_compiler: self.compiler,
1495 target: self.target,
1496 mode: CompiletestMode::RustdocJs,
1497 suite: "rustdoc-js",
1498 path: "tests/rustdoc-js",
1499 compare_mode: None,
1500 });
1501 }
1502}
1503
1504fn get_browser_ui_test_version_inner(
1505 builder: &Builder<'_>,
1506 yarn: &Path,
1507 global: bool,
1508) -> Option<String> {
1509 let mut command = command(yarn);
1510 command
1511 .arg("--cwd")
1512 .arg(&builder.build.out)
1513 .arg("list")
1514 .arg("--parseable")
1515 .arg("--long")
1516 .arg("--depth=0");
1517 if global {
1518 command.arg("--global");
1519 }
1520 let lines = command.allow_failure().cached().run_capture(builder).stdout();
1523 lines
1524 .lines()
1525 .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@"))
1526 .map(|v| v.to_owned())
1527}
1528
1529fn get_browser_ui_test_version(builder: &Builder<'_>) -> Option<String> {
1530 let yarn = builder.config.yarn.as_deref()?;
1531 get_browser_ui_test_version_inner(builder, yarn, false)
1532 .or_else(|| get_browser_ui_test_version_inner(builder, yarn, true))
1533}
1534
1535#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1537pub struct RustdocGUI {
1538 test_compiler: Compiler,
1540 target: TargetSelection,
1541}
1542
1543impl CommandLineStep for RustdocGUI {
1544 type Output = ();
1545 const IS_HOST: bool = true;
1546
1547 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1548 run.suite_path("tests/rustdoc-gui")
1549 }
1550
1551 fn is_default_step(builder: &Builder<'_>) -> bool {
1552 builder.config.nodejs.is_some()
1553 && builder.test_target != TestTarget::DocOnly
1554 && get_browser_ui_test_version(builder).is_some()
1555 }
1556
1557 fn make_run(run: RunConfig<'_>) {
1558 let test_compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1559 run.builder.ensure(RustdocGUI { test_compiler, target: run.target });
1560 }
1561
1562 fn run(self, builder: &Builder<'_>) {
1563 builder.std(self.test_compiler, self.target);
1564 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
1565
1566 let mut cmd = builder.tool_cmd(Tool::RustdocGUITest);
1567
1568 let out_dir = builder.test_out(self.target).join("rustdoc-gui");
1569 build_stamp::clear_if_dirty(
1570 builder,
1571 &out_dir,
1572 &builder.rustdoc_for_compiler(self.test_compiler),
1573 );
1574
1575 if let Some(src) = builder.config.src.to_str() {
1576 cmd.arg("--rust-src").arg(src);
1577 }
1578
1579 if let Some(out_dir) = out_dir.to_str() {
1580 cmd.arg("--out-dir").arg(out_dir);
1581 }
1582
1583 if let Some(initial_cargo) = builder.config.initial_cargo.to_str() {
1584 cmd.arg("--initial-cargo").arg(initial_cargo);
1585 }
1586
1587 cmd.arg("--jobs").arg(builder.jobs().to_string());
1588
1589 cmd.env("RUSTDOC", builder.rustdoc_for_compiler(self.test_compiler))
1590 .env("RUSTC", builder.rustc(self.test_compiler));
1591
1592 add_rustdoc_cargo_linker_args(&mut cmd, builder, self.test_compiler.host, LldThreads::No);
1593
1594 let full_suite = builder.paths.iter().any(|path| {
1595 matches!(
1596 helpers::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder),
1597 TestFilterCategory::Fullsuite
1598 )
1599 });
1600
1601 if !full_suite {
1604 for path in &builder.paths {
1605 if let TestFilterCategory::Arg(p) =
1606 helpers::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder)
1607 {
1608 if !p.ends_with(".goml") {
1609 eprintln!("A non-goml file was given: `{}`", path.display());
1610 panic!("Cannot run rustdoc-gui tests");
1611 }
1612 if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
1613 cmd.arg("--goml-file").arg(name);
1614 }
1615 }
1616 }
1617 }
1618
1619 for test_arg in builder.config.test_args() {
1620 cmd.arg("--test-arg").arg(test_arg);
1621 }
1622
1623 if let Some(ref nodejs) = builder.config.nodejs {
1624 cmd.arg("--nodejs").arg(nodejs);
1625 }
1626
1627 if let Some(ref yarn) = builder.config.yarn {
1628 cmd.arg("--yarn").arg(yarn);
1629 }
1630
1631 let _time = helpers::timeit(builder);
1632 let _guard = builder.msg_test("rustdoc-gui", self.target, self.test_compiler.stage);
1633 try_run_tests(builder, &mut cmd, true, record_failed_tests);
1634 }
1635
1636 fn metadata(&self) -> Option<StepMetadata> {
1637 Some(StepMetadata::test("rustdoc-gui", self.target).stage(self.test_compiler.stage))
1638 }
1639}
1640
1641#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1646pub struct Tidy;
1647
1648impl CommandLineStep for Tidy {
1649 type Output = ();
1650 const IS_HOST: bool = true;
1651
1652 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1653 run.path("src/tools/tidy")
1654 }
1655
1656 fn is_default_step(builder: &Builder<'_>) -> bool {
1657 builder.test_target != TestTarget::DocOnly
1658 }
1659
1660 fn make_run(run: RunConfig<'_>) {
1661 run.builder.ensure(Tidy);
1662 }
1663
1664 fn run(self, builder: &Builder<'_>) {
1673 let mut cmd = builder.tool_cmd(Tool::Tidy);
1674 cmd.arg(format!("--root-path={}", builder.src.display()));
1675 cmd.arg(format!("--cargo-path={}", builder.initial_cargo.display()));
1676 cmd.arg(format!("--output-dir={}", builder.out.display()));
1677 let jobs = builder.config.jobs.unwrap_or_else(|| {
1679 8 * std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32
1680 });
1681 cmd.arg(format!("--concurrency={jobs}"));
1682 if let Some(yarn) = &builder.config.yarn {
1684 cmd.arg(format!("--npm-path={}", yarn.display()));
1685 } else {
1686 cmd.arg("--npm-path=yarn");
1687 }
1688 if builder.is_verbose() {
1689 cmd.arg("--verbose");
1690 }
1691 if builder.config.cmd.bless() {
1692 cmd.arg("--bless");
1693 }
1694 if builder.config.is_running_on_ci() {
1695 cmd.arg("--ci=true");
1696 }
1697 if let Some(s) =
1698 builder.config.cmd.extra_checks().or(builder.config.tidy_extra_checks.as_deref())
1699 {
1700 cmd.arg(format!("--extra-checks={s}"));
1701 }
1702 let mut args = std::env::args_os();
1703 if args.any(|arg| arg == OsStr::new("--")) {
1704 cmd.arg("--");
1705 cmd.args(args);
1706 }
1707
1708 if builder.config.channel == "dev" || builder.config.channel == "nightly" {
1709 if !builder.config.json_output {
1710 builder.info("fmt check");
1711
1712 let Some(rustfmt) = builder.ensure(InternalRustfmt) else {
1715 let inferred_rustfmt_dir = builder.initial_sysroot.join("bin");
1716 eprintln!(
1717 "\
1718ERROR: no `rustfmt` binary found in {PATH}
1719INFO: `rust.channel` is currently set to \"{CHAN}\"
1720HELP: if you are testing a beta branch, set `rust.channel` to \"beta\" in the `bootstrap.toml` file
1721HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to `x.py test`",
1722 PATH = inferred_rustfmt_dir.display(),
1723 CHAN = builder.config.channel,
1724 );
1725 helpers::exit_process(1);
1726 };
1727 let all = false;
1728 crate::core::build_steps::format::format(
1729 builder,
1730 rustfmt,
1731 !builder.config.cmd.bless(),
1732 all,
1733 &[],
1734 );
1735 } else {
1736 eprintln!(
1737 "WARNING: `--json-output` is not supported on rustfmt, formatting will be skipped"
1738 );
1739 }
1740 }
1741
1742 builder.info("tidy check");
1743 cmd.delay_failure().run(builder);
1744
1745 builder.info("x.py completions check");
1746 let completion_paths = get_completion_paths(builder);
1747 if builder.config.cmd.bless() {
1748 builder.ensure(crate::core::build_steps::run::GenerateCompletions);
1749 } else if completion_paths
1750 .into_iter()
1751 .any(|(shell, path)| get_completion(shell, &path).is_some())
1752 {
1753 eprintln!(
1754 "x.py completions were changed; run `x.py run generate-completions` to update them"
1755 );
1756 helpers::exit_process(1);
1757 }
1758
1759 builder.info("x.py help check");
1760 if builder.config.cmd.bless() {
1761 builder.ensure(crate::core::build_steps::run::GenerateHelp);
1762 } else {
1763 let help_path = get_help_path(builder);
1764 let cur_help = std::fs::read_to_string(&help_path).unwrap_or_else(|err| {
1765 eprintln!("couldn't read {}: {}", help_path.display(), err);
1766 helpers::exit_process(1);
1767 });
1768 let new_help = top_level_help();
1769
1770 if new_help != cur_help {
1771 eprintln!("x.py help was changed; run `x.py run generate-help` to update it");
1772 helpers::exit_process(1);
1773 }
1774 }
1775 }
1776
1777 fn metadata(&self) -> Option<StepMetadata> {
1778 Some(StepMetadata::test("tidy", TargetSelection::default()))
1779 }
1780}
1781
1782#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1785pub struct CrateRunMakeSupport {
1786 host: TargetSelection,
1787}
1788
1789impl CommandLineStep for CrateRunMakeSupport {
1790 type Output = ();
1791 const IS_HOST: bool = true;
1792
1793 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1794 run.path("src/tools/run-make-support")
1795 }
1796
1797 fn make_run(run: RunConfig<'_>) {
1798 run.builder.ensure(CrateRunMakeSupport { host: run.target });
1799 }
1800
1801 fn run(self, builder: &Builder<'_>) {
1803 let host = self.host;
1804 let compiler = builder.compiler(0, host);
1805 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
1806
1807 let mut cargo = tool::prepare_tool_cargo(
1808 builder,
1809 compiler,
1810 Mode::ToolBootstrap,
1811 host,
1812 Kind::Test,
1813 "src/tools/run-make-support",
1814 SourceType::InTree,
1815 &[],
1816 );
1817 cargo.allow_features("test");
1818 run_cargo_test(
1819 cargo,
1820 &[],
1821 &[],
1822 "run-make-support self test",
1823 host,
1824 builder,
1825 record_failed_tests,
1826 );
1827 }
1828}
1829
1830#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1831pub struct CrateBuildHelper {
1832 host: TargetSelection,
1833}
1834
1835impl CommandLineStep for CrateBuildHelper {
1836 type Output = ();
1837 const IS_HOST: bool = true;
1838
1839 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1840 run.path("src/build_helper")
1841 }
1842
1843 fn make_run(run: RunConfig<'_>) {
1844 run.builder.ensure(CrateBuildHelper { host: run.target });
1845 }
1846
1847 fn run(self, builder: &Builder<'_>) {
1849 let host = self.host;
1850 let compiler = builder.compiler(0, host);
1851 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
1852
1853 let mut cargo = tool::prepare_tool_cargo(
1854 builder,
1855 compiler,
1856 Mode::ToolBootstrap,
1857 host,
1858 Kind::Test,
1859 "src/build_helper",
1860 SourceType::InTree,
1861 &[],
1862 );
1863 cargo.allow_features("test");
1864 run_cargo_test(
1865 cargo,
1866 &[],
1867 &[],
1868 "build_helper self test",
1869 host,
1870 builder,
1871 record_failed_tests,
1872 );
1873 }
1874}
1875
1876fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf {
1877 builder.out.join(host).join("test")
1878}
1879
1880macro_rules! test {
1882 (
1883 $( #[$attr:meta] )* $name:ident {
1885 path: $path:expr,
1886 mode: $mode:expr,
1887 suite: $suite:expr,
1888 default: $default:expr
1889 $( , IS_HOST: $IS_HOST:expr )? $( , compare_mode: $compare_mode:expr )? $( , )? }
1893 ) => {
1894 $( #[$attr] )*
1895 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
1896 pub struct $name {
1897 test_compiler: Compiler,
1898 target: TargetSelection,
1899 }
1900
1901 impl CommandLineStep for $name {
1902 type Output = ();
1903 const IS_HOST: bool = (const {
1904 #[allow(unused_assignments, unused_mut)]
1905 let mut value = false;
1906 $( value = $IS_HOST; )?
1907 value
1908 });
1909
1910 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1911 run.suite_path($path)
1912 }
1913
1914 fn is_default_step(_builder: &Builder<'_>) -> bool {
1915 const { $default }
1916 }
1917
1918 fn make_run(run: RunConfig<'_>) {
1919 let test_compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1920
1921 run.builder.ensure($name { test_compiler, target: run.target });
1922 }
1923
1924 fn run(self, builder: &Builder<'_>) {
1925 builder.ensure(Compiletest {
1926 test_compiler: self.test_compiler,
1927 target: self.target,
1928 mode: const { $mode },
1929 suite: $suite,
1930 path: $path,
1931 compare_mode: (const {
1932 #[allow(unused_assignments, unused_mut)]
1933 let mut value = None;
1934 $( value = $compare_mode; )?
1935 value
1936 }),
1937 })
1938 }
1939 }
1940 };
1941}
1942
1943test!(Ui { path: "tests/ui", mode: CompiletestMode::Ui, suite: "ui", default: true });
1944
1945test!(Crashes {
1946 path: "tests/crashes",
1947 mode: CompiletestMode::Crashes,
1948 suite: "crashes",
1949 default: true,
1950});
1951
1952test!(CodegenLlvm {
1953 path: "tests/codegen-llvm",
1954 mode: CompiletestMode::Codegen,
1955 suite: "codegen-llvm",
1956 default: true
1957});
1958
1959test!(CodegenUnits {
1960 path: "tests/codegen-units",
1961 mode: CompiletestMode::CodegenUnits,
1962 suite: "codegen-units",
1963 default: true,
1964});
1965
1966test!(Incremental {
1967 path: "tests/incremental",
1968 mode: CompiletestMode::Incremental,
1969 suite: "incremental",
1970 default: true,
1971});
1972
1973test!(Debuginfo {
1974 path: "tests/debuginfo",
1975 mode: CompiletestMode::Debuginfo,
1976 suite: "debuginfo",
1977 default: true,
1978 compare_mode: Some("split-dwarf"),
1979});
1980
1981test!(UiFullDeps {
1982 path: "tests/ui-fulldeps",
1983 mode: CompiletestMode::Ui,
1984 suite: "ui-fulldeps",
1985 default: true,
1986 IS_HOST: true,
1987});
1988
1989test!(RustdocHtml {
1990 path: "tests/rustdoc-html",
1991 mode: CompiletestMode::RustdocHtml,
1992 suite: "rustdoc-html",
1993 default: true,
1994 IS_HOST: true,
1995});
1996test!(RustdocUi {
1997 path: "tests/rustdoc-ui",
1998 mode: CompiletestMode::Ui,
1999 suite: "rustdoc-ui",
2000 default: true,
2001 IS_HOST: true,
2002});
2003
2004test!(RustdocJson {
2005 path: "tests/rustdoc-json",
2006 mode: CompiletestMode::RustdocJson,
2007 suite: "rustdoc-json",
2008 default: true,
2009 IS_HOST: true,
2010});
2011
2012test!(Pretty {
2013 path: "tests/pretty",
2014 mode: CompiletestMode::Pretty,
2015 suite: "pretty",
2016 default: true,
2017 IS_HOST: true,
2018});
2019
2020test!(RunMake {
2021 path: "tests/run-make",
2022 mode: CompiletestMode::RunMake,
2023 suite: "run-make",
2024 default: true,
2025});
2026test!(RunMakeCargo {
2027 path: "tests/run-make-cargo",
2028 mode: CompiletestMode::RunMake,
2029 suite: "run-make-cargo",
2030 default: true
2031});
2032test!(BuildStd {
2033 path: "tests/build-std",
2034 mode: CompiletestMode::RunMake,
2035 suite: "build-std",
2036 default: false
2037});
2038
2039test!(AssemblyLlvm {
2040 path: "tests/assembly-llvm",
2041 mode: CompiletestMode::Assembly,
2042 suite: "assembly-llvm",
2043 default: true
2044});
2045
2046#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2049pub struct Coverage {
2050 pub compiler: Compiler,
2051 pub target: TargetSelection,
2052 pub(crate) mode: CompiletestMode,
2053}
2054
2055impl Coverage {
2056 const PATH: &'static str = "tests/coverage";
2057 const SUITE: &'static str = "coverage";
2058 const ALL_MODES: &[CompiletestMode] =
2059 &[CompiletestMode::CoverageMap, CompiletestMode::CoverageRun];
2060
2061 fn new(run: &RunConfig<'_>, mode: CompiletestMode) -> Self {
2062 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
2063 let target = run.target;
2064 Coverage { compiler, target, mode }
2065 }
2066}
2067
2068impl CommandLineStep for Coverage {
2069 type Output = ();
2070 const IS_HOST: bool = false;
2072
2073 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2074 run.suite_path(Coverage::PATH)
2081 }
2082
2083 fn is_default_step(_builder: &Builder<'_>) -> bool {
2084 true
2085 }
2086
2087 fn make_run(run: RunConfig<'_>) {
2088 for &mode in Coverage::ALL_MODES {
2092 if !run.builder.config.skip.iter().any(|skip| skip == Path::new(mode.as_str())) {
2093 run.builder.ensure(Coverage::new(&run, mode));
2094 }
2095 }
2096 }
2097
2098 fn run(self, builder: &Builder<'_>) {
2099 let Self { compiler, target, mode } = self;
2100 builder.ensure(Compiletest {
2103 test_compiler: compiler,
2104 target,
2105 mode,
2106 suite: Self::SUITE,
2107 path: Self::PATH,
2108 compare_mode: None,
2109 });
2110 }
2111}
2112
2113#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2121pub enum CoverageModeAlias {}
2122
2123impl CommandLineStep for CoverageModeAlias {
2124 type Output = ();
2125
2126 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2127 Coverage::ALL_MODES.iter().fold(run, |run, mode| run.alias(mode.as_str()))
2132 }
2133
2134 fn is_default_step(_builder: &Builder<'_>) -> bool {
2135 false
2136 }
2137
2138 fn make_run(run: RunConfig<'_>) {
2139 for path in &run.paths {
2140 let single_path = &path.assert_single_path().path;
2141 for &mode in Coverage::ALL_MODES {
2142 if single_path == Path::new(mode.as_str()) {
2143 run.builder.ensure(Coverage::new(&run, mode));
2146 }
2147 }
2148 }
2149 }
2150
2151 fn run(self, _builder: &Builder<'_>) {
2152 unreachable!("never instantiated; `make_run` creates a Coverage step instead");
2153 }
2154}
2155
2156test!(CoverageRunRustdoc {
2157 path: "tests/coverage-run-rustdoc",
2158 mode: CompiletestMode::CoverageRun,
2159 suite: "coverage-run-rustdoc",
2160 default: true,
2161 IS_HOST: true,
2162});
2163
2164#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2166pub struct MirOpt {
2167 pub compiler: Compiler,
2168 pub target: TargetSelection,
2169}
2170
2171impl CommandLineStep for MirOpt {
2172 type Output = ();
2173
2174 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2175 run.suite_path("tests/mir-opt")
2176 }
2177
2178 fn is_default_step(_builder: &Builder<'_>) -> bool {
2179 true
2180 }
2181
2182 fn make_run(run: RunConfig<'_>) {
2183 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
2184 run.builder.ensure(MirOpt { compiler, target: run.target });
2185 }
2186
2187 fn run(self, builder: &Builder<'_>) {
2188 let run = |target| {
2189 builder.ensure(Compiletest {
2190 test_compiler: self.compiler,
2191 target,
2192 mode: CompiletestMode::MirOpt,
2193 suite: "mir-opt",
2194 path: "tests/mir-opt",
2195 compare_mode: None,
2196 })
2197 };
2198
2199 run(self.target);
2200
2201 if builder.config.cmd.bless() {
2204 for target in ["aarch64-unknown-linux-gnu", "i686-pc-windows-msvc"] {
2210 run(TargetSelection::from_user(target));
2211 }
2212
2213 for target in ["x86_64-apple-darwin", "i686-unknown-linux-musl"] {
2214 let target = TargetSelection::from_user(target);
2215 let panic_abort_target = builder.ensure(MirOptPanicAbortSyntheticTarget {
2216 compiler: self.compiler,
2217 base: target,
2218 });
2219 run(panic_abort_target);
2220 }
2221 }
2222 }
2223}
2224
2225#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2231struct Compiletest {
2232 test_compiler: Compiler,
2234 target: TargetSelection,
2235 mode: CompiletestMode,
2236 suite: &'static str,
2237 path: &'static str,
2238 compare_mode: Option<&'static str>,
2239}
2240
2241impl Step for Compiletest {
2242 type Output = ();
2243
2244 fn run(self, builder: &Builder<'_>) {
2245 if builder.test_target == TestTarget::DocOnly {
2246 return;
2247 }
2248
2249 if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 {
2250 eprintln!("\
2251ERROR: `--stage 0` runs compiletest on the stage0 (precompiled) compiler, not your local changes, and will almost always cause tests to fail
2252HELP: to test the compiler or standard library, omit the stage or explicitly use `--stage 1` instead
2253NOTE: 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`."
2254 );
2255 helpers::exit_process(1);
2256 }
2257
2258 let mut test_compiler = self.test_compiler;
2259 let target = self.target;
2260 let mode = self.mode;
2261 let suite = self.suite;
2262 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
2263
2264 let suite_path = self.path;
2266
2267 if !builder.config.codegen_tests && mode == CompiletestMode::Codegen {
2269 return;
2270 }
2271
2272 let query_compiler;
2279 let (stage, stage_id) = if suite == "ui-fulldeps" && test_compiler.stage == 1 {
2280 query_compiler = Some(test_compiler);
2283 let build = builder.build.host_target;
2287 test_compiler = builder.compiler(test_compiler.stage - 1, build);
2288 let test_stage = test_compiler.stage + 1;
2289 (test_stage, format!("stage{test_stage}-{build}"))
2290 } else {
2291 query_compiler = None;
2292 let stage = test_compiler.stage;
2293 (stage, format!("stage{stage}-{target}"))
2294 };
2295
2296 if suite.ends_with("fulldeps") {
2297 builder.ensure(compile::Rustc::new(test_compiler, target));
2298 }
2299
2300 if builder.config.wasm_proc_macros {
2302 builder.ensure(compile::Std::new(
2303 test_compiler,
2304 TargetSelection::from_user("wasm32-wasip2"),
2305 ));
2306 }
2307
2308 if suite == "debuginfo" {
2309 builder.ensure(dist::DebuggerScripts {
2310 sysroot: builder.sysroot(test_compiler).to_path_buf(),
2311 target,
2312 });
2313 }
2314
2315 if suite == "mir-opt" {
2317 builder.ensure(
2318 compile::Std::new(test_compiler, test_compiler.host).is_for_mir_opt_tests(true),
2319 );
2320 } else {
2321 builder.std(test_compiler, test_compiler.host);
2322 }
2323
2324 let mut cmd = builder.tool_cmd(Tool::Compiletest);
2325
2326 if mode == CompiletestMode::RunMake {
2327 let output = builder.tool(Tool::RunMakeSupport);
2330 let find = |extension: &str| -> Option<&PathBuf> {
2331 output.artifacts.iter().find_map(|p| {
2332 let filename = p.file_name()?.to_str()?;
2337 if !filename.starts_with("librun_make_support") {
2338 return None;
2339 }
2340
2341 if extension == p.extension()? { Some(p) } else { None }
2342 })
2343 };
2344 if !builder.config.dry_run() {
2345 let rlib =
2346 find("rlib").expect(".rlib not found when compiling librun_make_support");
2347 cmd.arg("--run-make-support-rlib").arg(rlib);
2348
2349 if let Some(rmeta) = find("rmeta") {
2351 cmd.arg("--run-make-support-rmeta").arg(rmeta);
2352 }
2353 }
2354 }
2355
2356 if suite == "mir-opt" {
2357 builder.ensure(compile::Std::new(test_compiler, target).is_for_mir_opt_tests(true));
2358 } else {
2359 builder.std(test_compiler, target);
2360 }
2361
2362 builder.ensure(RemoteCopyLibs { build_compiler: test_compiler, target });
2363
2364 cmd.arg("--stage").arg(stage.to_string());
2368 cmd.arg("--stage-id").arg(stage_id);
2369
2370 cmd.arg("--compile-lib-path").arg(builder.rustc_libdir(test_compiler));
2371 cmd.arg("--run-lib-path").arg(builder.sysroot_target_libdir(test_compiler, target));
2372 cmd.arg("--rustc-path").arg(builder.rustc(test_compiler));
2373 if let Some(query_compiler) = query_compiler {
2374 cmd.arg("--query-rustc-path").arg(builder.rustc(query_compiler));
2375 }
2376
2377 cmd.arg("--minicore-path")
2380 .arg(builder.src.join("tests").join("auxiliary").join("minicore.rs"));
2381
2382 let is_rustdoc = suite == "rustdoc-ui" || suite == "rustdoc-js";
2383
2384 if builder.config.wasm_proc_macros {
2385 cmd.arg("--wasm-proc-macros");
2386 }
2387
2388 if mode == CompiletestMode::RunMake {
2403 let stage0_rustc_path = builder.compiler(0, test_compiler.host);
2406 cmd.arg("--stage0-rustc-path").arg(builder.rustc(stage0_rustc_path));
2407
2408 if matches!(suite, "run-make-cargo" | "build-std") {
2409 let cargo_path = if test_compiler.stage == 0 {
2410 builder.initial_cargo.clone()
2412 } else {
2413 builder
2414 .ensure(tool::Cargo::from_build_compiler(
2415 builder.compiler(test_compiler.stage - 1, test_compiler.host),
2416 test_compiler.host,
2417 ))
2418 .tool_path
2419 };
2420
2421 cmd.arg("--cargo-path").arg(cargo_path);
2422 }
2423 }
2424
2425 if matches!(
2427 mode,
2428 CompiletestMode::RunMake
2429 | CompiletestMode::RustdocHtml
2430 | CompiletestMode::RustdocJs
2431 | CompiletestMode::RustdocJson
2432 ) || matches!(suite, "rustdoc-ui" | "coverage-run-rustdoc")
2433 {
2434 cmd.arg("--rustdoc-path").arg(builder.rustdoc_for_compiler(test_compiler));
2435 }
2436
2437 if mode == CompiletestMode::RustdocJson {
2438 let json_compiler = builder.compiler(0, builder.host_target);
2440 cmd.arg("--jsondocck-path")
2441 .arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target }).tool_path);
2442 cmd.arg("--jsondoclint-path").arg(
2443 builder.ensure(tool::JsonDocLint { compiler: json_compiler, target }).tool_path,
2444 );
2445 }
2446
2447 if matches!(mode, CompiletestMode::CoverageMap | CompiletestMode::CoverageRun) {
2448 let coverage_dump = builder.tool_exe(Tool::CoverageDump);
2449 cmd.arg("--coverage-dump-path").arg(coverage_dump);
2450 }
2451
2452 cmd.arg("--src-root").arg(&builder.src);
2453 cmd.arg("--src-test-suite-root").arg(builder.src.join("tests").join(suite));
2454
2455 cmd.arg("--build-root").arg(&builder.out);
2459 cmd.arg("--build-test-suite-root").arg(testdir(builder, test_compiler.host).join(suite));
2460
2461 let sysroot = if builder.top_stage == 0 {
2466 builder.initial_sysroot.clone()
2467 } else {
2468 builder.sysroot(test_compiler)
2469 };
2470
2471 cmd.arg("--sysroot-base").arg(sysroot);
2472
2473 cmd.arg("--suite").arg(suite);
2474 cmd.arg("--mode").arg(mode.as_str());
2475 cmd.arg("--target").arg(target.rustc_target_arg());
2476 cmd.arg("--host").arg(&*test_compiler.host.triple);
2477
2478 let filecheck = builder.ensure(llvm::FileCheck { target: builder.config.host_target });
2479 cmd.arg("--llvm-filecheck").arg(filecheck);
2480
2481 if let Some(codegen_backend) = builder.config.cmd.test_codegen_backend() {
2482 if !builder
2483 .config
2484 .enabled_codegen_backends(test_compiler.host)
2485 .contains(codegen_backend)
2486 {
2487 eprintln!(
2488 "\
2489ERROR: No configured backend named `{name}`
2490HELP: You can add it into `bootstrap.toml` in `rust.codegen-backends = [{name:?}]`",
2491 name = codegen_backend.name(),
2492 );
2493 helpers::exit_process(1);
2494 }
2495
2496 if let CodegenBackendKind::Gcc = codegen_backend
2497 && builder.config.rustc_debug_assertions
2498 {
2499 eprintln!(
2500 r#"WARNING: Running tests with the GCC codegen backend while rustc debug assertions are enabled. This might lead to test failures.
2501Please disable assertions with `rust.debug-assertions = false`.
2502 "#
2503 );
2504 }
2505
2506 cmd.arg("--override-codegen-backend").arg(codegen_backend.name());
2509 cmd.arg("--default-codegen-backend").arg(codegen_backend.name());
2512 } else {
2513 cmd.arg("--default-codegen-backend")
2516 .arg(builder.config.default_codegen_backend(test_compiler.host).name());
2517 }
2518 if builder.config.cmd.bypass_ignore_backends() {
2519 cmd.arg("--bypass-ignore-backends");
2520 }
2521
2522 if builder.build.config.llvm_enzyme {
2523 cmd.arg("--has-enzyme");
2524 }
2525
2526 if builder.build.config.llvm_offload {
2527 cmd.arg("--has-offload");
2528 }
2529
2530 if builder.config.cmd.bless() {
2531 cmd.arg("--bless");
2532 }
2533
2534 if builder.config.cmd.force_rerun() {
2535 cmd.arg("--force-rerun");
2536 }
2537
2538 if builder.config.cmd.no_capture() {
2539 cmd.arg("--no-capture");
2540 }
2541
2542 let compare_mode =
2543 builder.config.cmd.compare_mode().or_else(|| {
2544 if builder.config.test_compare_mode { self.compare_mode } else { None }
2545 });
2546
2547 if let Some(ref pass) = builder.config.cmd.pass() {
2548 cmd.arg("--pass");
2549 cmd.arg(pass);
2550 }
2551
2552 if let Some(ref run) = builder.config.cmd.run() {
2553 cmd.arg("--run");
2554 cmd.arg(run);
2555 }
2556
2557 if let Some(ref nodejs) = builder.config.nodejs {
2558 cmd.arg("--nodejs").arg(nodejs);
2559 } else if mode == CompiletestMode::RustdocJs {
2560 panic!("need nodejs to run rustdoc-js suite");
2561 }
2562 if builder.config.rust_optimize_tests {
2563 cmd.arg("--optimize-tests");
2564 }
2565 if builder.config.rust_randomize_layout {
2566 cmd.arg("--rust-randomized-layout");
2567 }
2568 if builder.config.cmd.only_modified() {
2569 cmd.arg("--only-modified");
2570 }
2571 if let Some(compiletest_diff_tool) = &builder.config.compiletest_diff_tool {
2572 cmd.arg("--compiletest-diff-tool").arg(compiletest_diff_tool);
2573 }
2574
2575 let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
2576 flags.push(format!(
2577 "-Cdebuginfo={}",
2578 if mode == CompiletestMode::Codegen {
2579 if builder.config.rust_debuginfo_level_tests
2582 != crate::core::config::DebuginfoLevel::None
2583 {
2584 println!(
2585 "NOTE: ignoring `rust.debuginfo-level-tests={}` for codegen tests",
2586 builder.config.rust_debuginfo_level_tests
2587 );
2588 }
2589 crate::core::config::DebuginfoLevel::None
2590 } else {
2591 builder.config.rust_debuginfo_level_tests
2592 }
2593 ));
2594 flags.extend(builder.config.cmd.compiletest_rustc_args().iter().map(|s| s.to_string()));
2595
2596 if suite != "mir-opt" {
2597 if let Some(linker) = builder.linker(target) {
2598 cmd.arg("--target-linker").arg(linker);
2599 }
2600 if let Some(linker) = builder.linker(test_compiler.host) {
2601 cmd.arg("--host-linker").arg(linker);
2602 }
2603 }
2604
2605 if suite == "ui-fulldeps" && target.ends_with("darwin") {
2607 flags.push("-Alinker_messages".into());
2608 }
2609
2610 let mut hostflags = flags.clone();
2611 hostflags.extend(linker_flags(builder, test_compiler.host, LldThreads::No));
2612
2613 let mut targetflags = flags;
2614
2615 if suite == "ui" || suite == "incremental" {
2617 builder.ensure(TestHelpers { target: test_compiler.host });
2618 builder.ensure(TestHelpers { target });
2619 hostflags.push(format!(
2620 "-Lnative={}",
2621 builder.test_helpers_out(test_compiler.host).display()
2622 ));
2623 let target_helpers = builder.test_helpers_out(target);
2624 targetflags.push(format!("-Lnative={}", target_helpers.display()));
2625 if target.is_pauthtest() {
2626 targetflags.push(format!("-Clink-arg=-Wl,-rpath,{}", target_helpers.display()));
2629 }
2630 }
2631
2632 for flag in hostflags {
2633 cmd.arg("--host-rustcflags").arg(flag);
2634 }
2635 for flag in targetflags {
2636 cmd.arg("--target-rustcflags").arg(flag);
2637 }
2638 if target.is_synthetic() {
2639 cmd.arg("--target-rustcflags").arg("-Zunstable-options");
2640 }
2641
2642 cmd.arg("--python").arg(
2643 builder.config.python.as_ref().expect("python is required for running rustdoc tests"),
2644 );
2645
2646 let android = android::discover_android(builder, target);
2648 if let Some(android::Android { adb_path, adb_test_dir, android_cross_path }) = &android {
2649 cmd.arg("--adb-path").arg(adb_path);
2650 cmd.arg("--adb-test-dir").arg(adb_test_dir);
2651 cmd.arg("--android-cross-path").arg(android_cross_path);
2652 }
2653
2654 if mode == CompiletestMode::Debuginfo {
2655 if let Some(debuggers::Cdb { cdb }) = debuggers::discover_cdb(target) {
2656 cmd.arg("--cdb").arg(cdb);
2657 }
2658
2659 if let Some(debuggers::Gdb { gdb }) = debuggers::discover_gdb(builder, android.as_ref())
2660 {
2661 cmd.arg("--gdb").arg(gdb);
2662 }
2663
2664 if let Some(debuggers::Lldb { lldb_exe, lldb_version }) =
2665 debuggers::discover_lldb(builder)
2666 {
2667 cmd.arg("--lldb").arg(lldb_exe);
2668 cmd.arg("--lldb-version").arg(lldb_version);
2669 }
2670 }
2671
2672 if helpers::forcing_clang_based_tests() {
2673 let clang_exe = builder.llvm_out(target).join("bin").join("clang");
2674 cmd.arg("--run-clang-based-tests-with").arg(clang_exe);
2675 }
2676
2677 for exclude in &builder.config.skip {
2678 cmd.arg("--skip");
2679 cmd.arg(exclude);
2680 }
2681
2682 let mut paths = match &builder.config.cmd {
2684 Subcommand::Test { .. } => &builder.config.paths[..],
2685 _ => &[],
2686 };
2687
2688 let mut paths_v;
2691 if mode == CompiletestMode::RustdocJs {
2692 paths_v = paths.to_vec();
2693 for p in &mut paths_v {
2694 if let Some(ext) = p.extension()
2695 && ext == "js"
2696 {
2697 p.set_extension("rs");
2698 }
2699 }
2700 paths = &paths_v;
2701 }
2702
2703 let mut test_args = Vec::new();
2705 for p in paths {
2706 match helpers::is_valid_test_suite_arg(p, suite_path, builder) {
2707 TestFilterCategory::Fullsuite => {
2708 test_args.clear();
2713 break;
2714 }
2715 TestFilterCategory::Arg(a) => test_args.push(a),
2716 TestFilterCategory::Uninteresting => {}
2717 }
2718 }
2719
2720 test_args.append(&mut builder.config.test_args());
2721
2722 if cfg!(windows) {
2725 let test_args_win: Vec<String> =
2726 test_args.iter().map(|s| s.replace('/', "\\")).collect();
2727 cmd.args(&test_args_win);
2728 } else {
2729 cmd.args(&test_args);
2730 }
2731
2732 if builder.is_verbose() {
2733 cmd.arg("--verbose");
2734 }
2735
2736 if builder.config.cmd.verbose_run_make_subprocess_output() {
2737 cmd.arg("--verbose-run-make-subprocess-output");
2738 }
2739
2740 if builder.config.rustc_debug_assertions {
2741 cmd.arg("--with-rustc-debug-assertions");
2742 }
2743
2744 if builder.config.std_debug_assertions {
2745 cmd.arg("--with-std-debug-assertions");
2746 }
2747
2748 if builder.config.rust_remap_debuginfo {
2749 cmd.arg("--with-std-remap-debuginfo");
2750 }
2751
2752 cmd.arg("--jobs").arg(builder.jobs().to_string());
2753
2754 let mut llvm_components_passed = false;
2755 let mut copts_passed = false;
2756 if builder.config.llvm_enabled(test_compiler.host) {
2757 let llvm_output = builder.ensure(llvm::Llvm { target: builder.config.host_target });
2758 if !builder.config.dry_run() {
2759 let llvm_version = get_llvm_version(builder, &llvm_output.host_llvm_config);
2760 let llvm_components = command(&llvm_output.host_llvm_config)
2761 .cached()
2762 .arg("--components")
2763 .run_capture_stdout(builder)
2764 .stdout();
2765 cmd.arg("--llvm-version")
2767 .arg(llvm_version.trim())
2768 .arg("--llvm-components")
2769 .arg(llvm_components.trim());
2770 llvm_components_passed = true;
2771 }
2772 if !builder.config.is_rust_llvm(&llvm_output, target) {
2773 cmd.arg("--system-llvm");
2774 }
2775
2776 if !builder.config.dry_run() && suite.ends_with("fulldeps") {
2781 let llvm_libdir = command(&llvm_output.host_llvm_config)
2782 .cached()
2783 .arg("--libdir")
2784 .run_capture_stdout(builder)
2785 .stdout();
2786 let link_llvm = if target.is_msvc() {
2787 format!("-Clink-arg=-LIBPATH:{llvm_libdir}")
2788 } else {
2789 format!("-Clink-arg=-L{llvm_libdir}")
2790 };
2791 cmd.arg("--host-rustcflags").arg(link_llvm);
2792 }
2793
2794 if !builder.config.dry_run()
2795 && matches!(mode, CompiletestMode::RunMake | CompiletestMode::CoverageRun)
2796 {
2797 let llvm_bin_path = llvm_output
2802 .host_llvm_config
2803 .parent()
2804 .expect("Expected llvm-config to be contained in directory");
2805 assert!(llvm_bin_path.is_dir());
2806 cmd.arg("--llvm-bin-dir").arg(llvm_bin_path);
2807 }
2808
2809 if !builder.config.dry_run() && mode == CompiletestMode::RunMake {
2810 if builder.config.lld_enabled {
2812 let lld_install_root =
2813 builder.ensure(llvm::Lld { target: builder.config.host_target });
2814
2815 let lld_bin_path = lld_install_root.join("bin");
2816
2817 let old_path = env::var_os("PATH").unwrap_or_default();
2818 let new_path = env::join_paths(
2819 std::iter::once(lld_bin_path).chain(env::split_paths(&old_path)),
2820 )
2821 .expect("Could not add LLD bin path to PATH");
2822 cmd.env("PATH", new_path);
2823 }
2824 }
2825 }
2826
2827 if !builder.config.dry_run() && mode == CompiletestMode::RunMake {
2830 let mut cflags = builder.cc_handled_cflags(target, CLang::C);
2831 cflags.extend(builder.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::C));
2832 let mut cxxflags = builder.cc_handled_cflags(target, CLang::Cxx);
2833 cxxflags.extend(builder.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::Cxx));
2834 cmd.arg("--cc")
2835 .arg(builder.cc(target))
2836 .arg("--cxx")
2837 .arg(builder.cxx(target).unwrap())
2838 .arg("--cflags")
2839 .arg(cflags.join(" "))
2840 .arg("--cxxflags")
2841 .arg(cxxflags.join(" "));
2842 copts_passed = true;
2843 if let Some(ar) = builder.ar(target) {
2844 cmd.arg("--ar").arg(ar);
2845 }
2846 }
2847
2848 if !llvm_components_passed {
2849 cmd.arg("--llvm-components").arg("");
2850 }
2851 if !copts_passed {
2852 cmd.arg("--cc")
2853 .arg("")
2854 .arg("--cxx")
2855 .arg("")
2856 .arg("--cflags")
2857 .arg("")
2858 .arg("--cxxflags")
2859 .arg("");
2860 }
2861
2862 if builder.remote_tested(target) {
2863 cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient));
2864 } else if let Some(tool) = builder.runner(target) {
2865 cmd.arg("--runner").arg(tool);
2866 }
2867
2868 if suite != "mir-opt" {
2869 if !builder.config.dry_run() && target.is_msvc() {
2875 for (k, v) in builder.cc[&target].env() {
2876 if k != "PATH" {
2877 cmd.env(k, v);
2878 }
2879 }
2880 }
2881 }
2882
2883 if !builder.config.dry_run()
2885 && target.contains("msvc")
2886 && builder.config.sanitizers_enabled(target)
2887 {
2888 cmd.env("ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE", "1");
2891 let asan_runtime_path = builder.cc[&target].path().parent().unwrap().to_path_buf();
2893 let old_path = cmd
2894 .get_envs()
2895 .find_map(|(k, v)| (k == "PATH").then_some(v))
2896 .flatten()
2897 .map_or_else(|| env::var_os("PATH").unwrap_or_default(), |v| v.to_owned());
2898 let new_path = env::join_paths(
2899 env::split_paths(&old_path).chain(std::iter::once(asan_runtime_path)),
2900 )
2901 .expect("Could not add ASAN runtime path to PATH");
2902 cmd.env("PATH", new_path);
2903 }
2904
2905 cmd.env_remove("CARGO");
2908
2909 cmd.env("RUSTC_BOOTSTRAP", "1");
2910 cmd.env("RUSTC_FORCE_RUSTC_VERSION", "compiletest");
2913 cmd.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
2914 builder.add_rust_test_threads(&mut cmd);
2915
2916 if builder.config.sanitizers_enabled(target) {
2917 cmd.env("RUSTC_SANITIZER_SUPPORT", "1");
2918 }
2919
2920 if builder.config.profiler_enabled(target) {
2921 cmd.arg("--profiler-runtime");
2922 }
2923
2924 cmd.env("RUST_TEST_TMPDIR", builder.tempdir());
2925
2926 if builder.config.cmd.rustfix_coverage() {
2927 cmd.arg("--rustfix-coverage");
2928 }
2929
2930 cmd.arg("--channel").arg(&builder.config.channel);
2931
2932 if !builder.config.omit_git_hash {
2933 cmd.arg("--git-hash");
2934 }
2935
2936 let git_config = builder.config.git_config();
2937 cmd.arg("--nightly-branch").arg(git_config.nightly_branch);
2938 cmd.arg("--git-merge-commit-email").arg(git_config.git_merge_commit_email);
2939
2940 #[cfg(feature = "build-metrics")]
2941 builder.metrics.begin_test_suite(
2942 build_helper::metrics::TestSuiteMetadata::Compiletest {
2943 suite: suite.into(),
2944 mode: mode.to_string(),
2945 compare_mode: None,
2946 target: self.target.triple.to_string(),
2947 host: self.test_compiler.host.triple.to_string(),
2948 stage: self.test_compiler.stage,
2949 },
2950 builder,
2951 );
2952
2953 let _group = builder.msg_test(
2954 format!("with compiletest suite={suite} mode={mode}"),
2955 target,
2956 test_compiler.stage,
2957 );
2958 try_run_tests(builder, &mut cmd, false, record_failed_tests.clone());
2959
2960 if let Some(compare_mode) = compare_mode {
2961 cmd.arg("--compare-mode").arg(compare_mode);
2962
2963 #[cfg(feature = "build-metrics")]
2964 builder.metrics.begin_test_suite(
2965 build_helper::metrics::TestSuiteMetadata::Compiletest {
2966 suite: suite.into(),
2967 mode: mode.to_string(),
2968 compare_mode: Some(compare_mode.into()),
2969 target: self.target.triple.to_string(),
2970 host: self.test_compiler.host.triple.to_string(),
2971 stage: self.test_compiler.stage,
2972 },
2973 builder,
2974 );
2975
2976 builder.info(&format!(
2977 "Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
2978 suite, mode, compare_mode, test_compiler.host, target
2979 ));
2980 let _time = helpers::timeit(builder);
2981 try_run_tests(builder, &mut cmd, false, record_failed_tests);
2982 }
2983 }
2984
2985 fn metadata(&self) -> Option<StepMetadata> {
2986 Some(
2987 StepMetadata::test(&format!("compiletest-{}", self.suite), self.target)
2988 .stage(self.test_compiler.stage),
2989 )
2990 }
2991}
2992
2993#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2995struct BookTest {
2996 test_compiler: Compiler,
2997 path: PathBuf,
2998 name: &'static str,
2999 is_ext_doc: bool,
3000 dependencies: Vec<&'static str>,
3001}
3002
3003impl Step for BookTest {
3004 type Output = ();
3005
3006 fn run(self, builder: &Builder<'_>) {
3007 if self.is_ext_doc {
3017 self.run_ext_doc(builder);
3018 } else {
3019 self.run_local_doc(builder);
3020 }
3021 }
3022}
3023
3024impl BookTest {
3025 fn run_ext_doc(self, builder: &Builder<'_>) {
3028 let test_compiler = self.test_compiler;
3029
3030 builder.std(test_compiler, test_compiler.host);
3031
3032 let mut rustdoc_path = builder.rustdoc_for_compiler(test_compiler);
3035 rustdoc_path.pop();
3036 let old_path = env::var_os("PATH").unwrap_or_default();
3037 let new_path = env::join_paths(iter::once(rustdoc_path).chain(env::split_paths(&old_path)))
3038 .expect("could not add rustdoc to PATH");
3039
3040 let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
3041 let path = builder.src.join(&self.path);
3042 rustbook_cmd.env("RUSTC_BOOTSTRAP", "1");
3044 rustbook_cmd.env("PATH", new_path).arg("test").arg(path);
3045
3046 let libs = if !self.dependencies.is_empty() {
3051 let mut lib_paths = vec![];
3052 for dep in self.dependencies {
3053 let mode = Mode::ToolRustcPrivate;
3054 let target = builder.config.host_target;
3055 let cargo = tool::prepare_tool_cargo(
3056 builder,
3057 test_compiler,
3058 mode,
3059 target,
3060 Kind::Build,
3061 dep,
3062 SourceType::Submodule,
3063 &[],
3064 );
3065
3066 let stamp = BuildStamp::new(&builder.cargo_out(test_compiler, mode, target))
3067 .with_prefix(PathBuf::from(dep).file_name().and_then(|v| v.to_str()).unwrap());
3068
3069 let output_paths =
3070 run_cargo(builder, cargo, vec![], &stamp, vec![], ArtifactKeepMode::OnlyRlib);
3071 let directories = output_paths
3072 .into_iter()
3073 .filter_map(|p| p.parent().map(ToOwned::to_owned))
3074 .fold(HashSet::new(), |mut set, dir| {
3075 set.insert(dir);
3076 set
3077 });
3078
3079 lib_paths.extend(directories);
3080 }
3081 lib_paths
3082 } else {
3083 vec![]
3084 };
3085
3086 if !libs.is_empty() {
3087 let paths = libs
3088 .into_iter()
3089 .map(|path| path.into_os_string())
3090 .collect::<Vec<OsString>>()
3091 .join(OsStr::new(","));
3092 rustbook_cmd.args([OsString::from("--library-path"), paths]);
3093 }
3094
3095 builder.add_rust_test_threads(&mut rustbook_cmd);
3096 let _guard = builder.msg_test(
3097 format_args!("mdbook {}", self.path.display()),
3098 test_compiler.host,
3099 test_compiler.stage,
3100 );
3101 let _time = helpers::timeit(builder);
3102 let toolstate = if rustbook_cmd.delay_failure().run(builder) {
3103 ToolState::TestPass
3104 } else {
3105 ToolState::TestFail
3106 };
3107 builder.save_toolstate(self.name, toolstate);
3108 }
3109
3110 fn run_local_doc(self, builder: &Builder<'_>) {
3112 let test_compiler = self.test_compiler;
3113 let host = self.test_compiler.host;
3114
3115 builder.std(test_compiler, host);
3116
3117 let _guard = builder.msg_test(
3118 format!("book {}", self.name),
3119 test_compiler.host,
3120 test_compiler.stage,
3121 );
3122
3123 let mut stack = vec![builder.src.join(self.path)];
3126 let _time = helpers::timeit(builder);
3127 let mut files = Vec::new();
3128 while let Some(p) = stack.pop() {
3129 if p.is_dir() {
3130 stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
3131 continue;
3132 }
3133
3134 if p.extension().and_then(|s| s.to_str()) != Some("md") {
3135 continue;
3136 }
3137
3138 files.push(p);
3139 }
3140
3141 files.sort();
3142
3143 for file in files {
3144 markdown_test(builder, test_compiler, &file);
3145 }
3146 }
3147}
3148
3149macro_rules! test_book {
3150 ($(
3151 $name:ident, $path:expr, $book_name:expr,
3152 default=$default:expr
3153 $(,submodules = $submodules:expr)?
3154 $(,dependencies=$dependencies:expr)?
3155 ;
3156 )+) => {
3157 $(
3158 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
3159 pub struct $name {
3160 test_compiler: Compiler,
3161 }
3162
3163 impl CommandLineStep for $name {
3164 type Output = ();
3165 const IS_HOST: bool = true;
3166
3167 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3168 run.path($path)
3169 }
3170
3171 fn is_default_step(_builder: &Builder<'_>) -> bool {
3172 const { $default }
3173 }
3174
3175 fn make_run(run: RunConfig<'_>) {
3176 run.builder.ensure($name {
3177 test_compiler: run.builder.compiler(run.builder.top_stage, run.target),
3178 });
3179 }
3180
3181 fn run(self, builder: &Builder<'_>) {
3182 $(
3183 for submodule in $submodules {
3184 builder.require_submodule(submodule, None);
3185 }
3186 )*
3187
3188 let dependencies = vec![];
3189 $(
3190 let mut dependencies = dependencies;
3191 for dep in $dependencies {
3192 dependencies.push(dep);
3193 }
3194 )?
3195
3196 builder.ensure(BookTest {
3197 test_compiler: self.test_compiler,
3198 path: PathBuf::from($path),
3199 name: $book_name,
3200 is_ext_doc: !$default,
3201 dependencies,
3202 });
3203 }
3204 }
3205 )+
3206 }
3207}
3208
3209test_book!(
3210 Nomicon, "src/doc/nomicon", "nomicon", default=false, submodules=["src/doc/nomicon"];
3211 Reference, "src/doc/reference", "reference", default=false, submodules=["src/doc/reference"];
3212 RustdocBook, "src/doc/rustdoc", "rustdoc", default=true;
3213 RustcBook, "src/doc/rustc", "rustc", default=true;
3214 RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false, submodules=["src/doc/rust-by-example"];
3215 EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false, submodules=["src/doc/embedded-book"];
3216 TheBook, "src/doc/book", "book", default=false, submodules=["src/doc/book"], dependencies=["src/doc/book/packages/trpl"];
3217 UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
3218 EditionGuide, "src/doc/edition-guide", "edition-guide", default=false, submodules=["src/doc/edition-guide"];
3219);
3220
3221#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3222pub struct ErrorIndex {
3223 compilers: RustcPrivateCompilers,
3224}
3225
3226impl CommandLineStep for ErrorIndex {
3227 type Output = ();
3228 const IS_HOST: bool = true;
3229
3230 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3231 run.path("src/tools/error_index_generator").alias("error-index")
3234 }
3235
3236 fn is_default_step(_builder: &Builder<'_>) -> bool {
3237 true
3238 }
3239
3240 fn make_run(run: RunConfig<'_>) {
3241 let compilers = RustcPrivateCompilers::new(
3245 run.builder,
3246 run.builder.top_stage,
3247 run.builder.config.host_target,
3248 );
3249 run.builder.ensure(ErrorIndex { compilers });
3250 }
3251
3252 fn run(self, builder: &Builder<'_>) {
3259 let target_compiler = self.compilers.target_compiler();
3261
3262 let dir = testdir(builder, target_compiler.host);
3263 t!(fs::create_dir_all(&dir));
3264 let output = dir.join("error-index.md");
3265
3266 let mut tool = tool::ErrorIndex::command(builder, self.compilers);
3267 tool.arg("markdown").arg(&output);
3268
3269 let guard = builder.msg_test("error-index", target_compiler.host, target_compiler.stage);
3270 let _time = helpers::timeit(builder);
3271 tool.run_capture(builder);
3272 drop(guard);
3273 builder.std(target_compiler, target_compiler.host);
3276 markdown_test(builder, target_compiler, &output);
3277 }
3278}
3279
3280fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool {
3281 if let Ok(contents) = fs::read_to_string(markdown)
3282 && !contents.contains("```")
3283 {
3284 return true;
3285 }
3286
3287 builder.do_if_verbose(|| println!("doc tests for: {}", markdown.display()));
3288 let mut cmd = builder.rustdoc_cmd(compiler);
3289 builder.add_rust_test_threads(&mut cmd);
3290 cmd.arg("-Z");
3292 cmd.arg("unstable-options");
3293 cmd.arg("--test");
3294 cmd.arg(markdown);
3295 cmd.env("RUSTC_BOOTSTRAP", "1");
3296
3297 let test_args = builder.config.test_args().join(" ");
3298 cmd.arg("--test-args").arg(test_args);
3299
3300 cmd = cmd.delay_failure();
3301 if !builder.config.verbose_tests {
3302 cmd.run_capture(builder).is_success()
3303 } else {
3304 cmd.run(builder)
3305 }
3306}
3307
3308#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3313pub struct CrateLibrustc {
3314 build_compiler: Compiler,
3316 target: TargetSelection,
3317 crates: Vec<String>,
3318}
3319
3320impl CommandLineStep for CrateLibrustc {
3321 type Output = ();
3322 const IS_HOST: bool = true;
3323
3324 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3325 run.crate_or_deps("rustc-main").path("compiler")
3326 }
3327
3328 fn is_default_step(_builder: &Builder<'_>) -> bool {
3329 true
3330 }
3331
3332 fn make_run(run: RunConfig<'_>) {
3333 let builder = run.builder;
3334 let host = run.build_triple();
3335 let build_compiler = builder.compiler(builder.top_stage - 1, host);
3336 let crates = run.make_run_crates(Alias::Compiler);
3337
3338 builder.ensure(CrateLibrustc { build_compiler, target: run.target, crates });
3339 }
3340
3341 fn run(self, builder: &Builder<'_>) {
3342 builder.std(self.build_compiler, self.target);
3343
3344 builder.ensure(Crate {
3346 build_compiler: self.build_compiler,
3347 target: self.target,
3348 mode: Mode::Rustc,
3349 crates: self.crates,
3350 });
3351 }
3352
3353 fn metadata(&self) -> Option<StepMetadata> {
3354 Some(StepMetadata::test("CrateLibrustc", self.target).built_by(self.build_compiler))
3355 }
3356}
3357
3358fn run_cargo_test<'a>(
3362 cargo: builder::Cargo,
3363 libtest_args: &[&str],
3364 crates: &[String],
3365 description: impl Into<Option<&'a str>>,
3366 target: TargetSelection,
3367 builder: &Builder<'_>,
3368 record_failed_tests: RecordFailedTests,
3369) -> bool {
3370 let compiler = cargo.compiler();
3371 let stage = match cargo.mode() {
3372 Mode::Std => compiler.stage,
3373 _ => compiler.stage + 1,
3374 };
3375
3376 let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, target, builder);
3377 let _time = helpers::timeit(builder);
3378
3379 let _group = description.into().and_then(|what| builder.msg_test(what, target, stage));
3380
3381 #[cfg(feature = "build-metrics")]
3382 builder.metrics.begin_test_suite(
3383 build_helper::metrics::TestSuiteMetadata::CargoPackage {
3384 crates: crates.iter().map(|c| c.to_string()).collect(),
3385 target: target.triple.to_string(),
3386 host: compiler.host.triple.to_string(),
3387 stage: compiler.stage,
3388 },
3389 builder,
3390 );
3391 add_flags_and_try_run_tests(builder, &mut cargo, record_failed_tests)
3392}
3393
3394fn prepare_cargo_test(
3396 cargo: builder::Cargo,
3397 libtest_args: &[&str],
3398 crates: &[String],
3399 target: TargetSelection,
3400 builder: &Builder<'_>,
3401) -> BootstrapCommand {
3402 let compiler = cargo.compiler();
3403 let mut cargo: BootstrapCommand = cargo.into();
3404
3405 if builder.config.cmd.bless() && !cargo.get_envs().any(|v| v.0 == "RUSTC_BLESS") {
3409 cargo.env("RUSTC_BLESS", "Gesundheit");
3410 }
3411
3412 if builder.kind == Kind::Test && !builder.fail_fast {
3416 cargo.arg("--no-fail-fast");
3417 }
3418
3419 if builder.config.json_output {
3420 cargo.arg("--message-format=json");
3421 }
3422
3423 match builder.test_target {
3424 TestTarget::AllTargets => cargo.args(["--bins", "--examples", "--tests", "--benches"]),
3425 TestTarget::Default => &mut cargo,
3426 TestTarget::DocOnly => cargo.arg("--doc"),
3427 TestTarget::Tests => cargo.arg("--tests"),
3428 };
3429
3430 for krate in crates {
3431 cargo.arg("-p").arg(krate);
3432 }
3433
3434 cargo.arg("--").args(builder.config.test_args()).args(libtest_args);
3435 if !builder.config.verbose_tests {
3436 cargo.arg("--quiet");
3437 }
3438
3439 if builder.kind != Kind::Miri {
3448 let mut dylib_paths = builder.rustc_lib_paths(compiler);
3449 dylib_paths.push(builder.sysroot_target_libdir(compiler, target));
3450 helpers::add_dylib_path(dylib_paths, &mut cargo);
3451 }
3452
3453 if builder.remote_tested(target) {
3454 cargo.env(
3455 format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
3456 format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
3457 );
3458 } else if let Some(tool) = builder.runner(target) {
3459 cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), tool);
3460 }
3461
3462 cargo
3463}
3464
3465#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3473pub struct Crate {
3474 build_compiler: Compiler,
3476 target: TargetSelection,
3477 mode: Mode,
3478 crates: Vec<String>,
3479}
3480
3481impl CommandLineStep for Crate {
3482 type Output = ();
3483
3484 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3485 run.crate_or_deps("sysroot").crate_or_deps("coretests").crate_or_deps("alloctests")
3486 }
3487
3488 fn is_default_step(_builder: &Builder<'_>) -> bool {
3489 true
3490 }
3491
3492 fn make_run(run: RunConfig<'_>) {
3493 let builder = run.builder;
3494 let host = run.build_triple();
3495 let build_compiler = builder.compiler(builder.top_stage, host);
3496 let crates = run
3497 .paths
3498 .iter()
3499 .map(|p| builder.crate_paths[&p.assert_single_path().path].clone())
3500 .collect();
3501
3502 builder.ensure(Crate { build_compiler, target: run.target, mode: Mode::Std, crates });
3503 }
3504
3505 fn run(self, builder: &Builder<'_>) {
3514 let build_compiler = self.build_compiler;
3515 let target = self.target;
3516 let mode = self.mode;
3517
3518 builder.ensure(Std::new(build_compiler, build_compiler.host).force_recompile(true));
3521 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
3522
3523 let mut cargo = if builder.kind == Kind::Miri {
3524 if builder.top_stage == 0 {
3525 eprintln!("ERROR: `x.py miri` requires stage 1 or higher");
3526 std::process::exit(1);
3527 }
3528
3529 let mut cargo = builder::Cargo::new(
3532 builder,
3533 build_compiler,
3534 mode,
3535 SourceType::InTree,
3536 target,
3537 Kind::MiriTest,
3538 );
3539 cargo.env("MIRI_REPLACE_LIBRS_IF_NOT_TEST", "1");
3551 cargo.rustflag("-Zforce-unstable-if-unmarked");
3555 cargo.env(
3560 "MIRIFLAGS",
3561 format!(
3562 "{} -Zmiri-env-forward=RUSTC_BOOTSTRAP",
3563 env::var("MIRIFLAGS").unwrap_or_default()
3564 ),
3565 );
3566 cargo
3567 } else {
3568 if !builder.config.is_host_target(target) {
3570 builder.ensure(compile::Std::new(build_compiler, target).force_recompile(true));
3571 builder.ensure(RemoteCopyLibs { build_compiler, target });
3572 }
3573
3574 builder::Cargo::new(
3576 builder,
3577 build_compiler,
3578 mode,
3579 SourceType::InTree,
3580 target,
3581 builder.kind,
3582 )
3583 };
3584
3585 match mode {
3586 Mode::Std => {
3587 if builder.kind == Kind::Miri {
3588 cargo
3594 .arg("--manifest-path")
3595 .arg(builder.src.join("library/sysroot/Cargo.toml"));
3596 } else {
3597 compile::std_cargo(builder, target, &mut cargo, &[]);
3598 }
3599 }
3600 Mode::Rustc => {
3601 compile::rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
3602 }
3603 _ => panic!("can only test libraries"),
3604 };
3605
3606 let mut crates = self.crates.clone();
3607 if crates.iter().any(|crate_| crate_ == "core") {
3612 crates.push("coretests".to_owned());
3613 }
3614 if crates.iter().any(|crate_| crate_ == "alloc") {
3615 crates.push("alloctests".to_owned());
3616 };
3617 let description = crate_description(&self.crates);
3618 run_cargo_test(cargo, &[], &crates, &*description, target, builder, record_failed_tests);
3619 }
3620}
3621
3622#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3625pub struct CrateRustdoc {
3626 host: TargetSelection,
3627}
3628
3629impl CommandLineStep for CrateRustdoc {
3630 type Output = ();
3631 const IS_HOST: bool = true;
3632
3633 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3634 run.multi_path(&["src/librustdoc", "src/tools/rustdoc"])
3635 }
3636
3637 fn is_default_step(_builder: &Builder<'_>) -> bool {
3638 true
3639 }
3640
3641 fn make_run(run: RunConfig<'_>) {
3642 let builder = run.builder;
3643
3644 builder.ensure(CrateRustdoc { host: run.target });
3645 }
3646
3647 fn run(self, builder: &Builder<'_>) {
3648 let target = self.host;
3649 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
3650
3651 let compiler = if builder.download_rustc() {
3652 builder.compiler(builder.top_stage, target)
3653 } else {
3654 builder.compiler_for(builder.top_stage, target, target)
3659 };
3660 builder.std(compiler, target);
3665 builder.ensure(compile::Rustc::new(compiler, target));
3666
3667 let mut cargo = tool::prepare_tool_cargo(
3668 builder,
3669 compiler,
3670 Mode::ToolRustcPrivate,
3671 target,
3672 builder.kind,
3673 "src/tools/rustdoc",
3674 SourceType::InTree,
3675 &[],
3676 );
3677 if self.host.contains("musl") {
3678 cargo.arg("'-Ctarget-feature=-crt-static'");
3679 }
3680
3681 let libdir = if builder.download_rustc() {
3708 builder.rustc_libdir(compiler)
3709 } else {
3710 builder.sysroot_target_libdir(compiler, target).to_path_buf()
3711 };
3712 let mut dylib_path = dylib_path();
3713 dylib_path.insert(0, PathBuf::from(&*libdir));
3714 cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
3715
3716 run_cargo_test(
3717 cargo,
3718 &[],
3719 &["rustdoc:0.0.0".to_string()],
3720 "rustdoc",
3721 target,
3722 builder,
3723 record_failed_tests,
3724 );
3725 }
3726}
3727
3728#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3729pub struct CrateRustdocJsonTypes {
3730 build_compiler: Compiler,
3731 target: TargetSelection,
3732}
3733
3734impl CommandLineStep for CrateRustdocJsonTypes {
3735 type Output = ();
3736 const IS_HOST: bool = true;
3737
3738 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3739 run.path("src/rustdoc-json-types")
3740 }
3741
3742 fn is_default_step(_builder: &Builder<'_>) -> bool {
3743 true
3744 }
3745
3746 fn make_run(run: RunConfig<'_>) {
3747 let builder = run.builder;
3748
3749 builder.ensure(CrateRustdocJsonTypes {
3750 build_compiler: get_tool_target_compiler(
3751 builder,
3752 ToolTargetBuildMode::Build(run.target),
3753 ),
3754 target: run.target,
3755 });
3756 }
3757
3758 fn run(self, builder: &Builder<'_>) {
3759 let target = self.target;
3760 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
3761
3762 let cargo = tool::prepare_tool_cargo(
3763 builder,
3764 self.build_compiler,
3765 Mode::ToolTarget,
3766 target,
3767 builder.kind,
3768 "src/rustdoc-json-types",
3769 SourceType::InTree,
3770 &["rkyv_0_8".to_owned()],
3771 );
3772
3773 let libtest_args = if target.contains("musl") {
3775 ["'-Ctarget-feature=-crt-static'"].as_slice()
3776 } else {
3777 &[]
3778 };
3779
3780 run_cargo_test(
3781 cargo,
3782 libtest_args,
3783 &["rustdoc-json-types".to_string()],
3784 "rustdoc-json-types",
3785 target,
3786 builder,
3787 record_failed_tests,
3788 );
3789 }
3790}
3791
3792#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3802pub struct RemoteCopyLibs {
3803 build_compiler: Compiler,
3804 target: TargetSelection,
3805}
3806
3807impl Step for RemoteCopyLibs {
3808 type Output = ();
3809
3810 fn run(self, builder: &Builder<'_>) {
3811 let build_compiler = self.build_compiler;
3812 let target = self.target;
3813 if !builder.remote_tested(target) {
3814 return;
3815 }
3816
3817 builder.std(build_compiler, target);
3818
3819 builder.info(&format!("REMOTE copy libs to emulator ({target})"));
3820
3821 let remote_test_server = builder.ensure(tool::RemoteTestServer { build_compiler, target });
3822
3823 let tool = builder.tool_exe(Tool::RemoteTestClient);
3825 let mut cmd = command(&tool);
3826 cmd.arg("spawn-emulator")
3827 .arg(target.triple)
3828 .arg(&remote_test_server.tool_path)
3829 .arg(builder.tempdir());
3830 if let Some(rootfs) = builder.qemu_rootfs(target) {
3831 cmd.arg(rootfs);
3832 }
3833 cmd.run(builder);
3834
3835 for f in t!(builder.sysroot_target_libdir(build_compiler, target).read_dir()) {
3837 let f = t!(f);
3838 if helpers::is_dylib(&f.path()) {
3839 command(&tool).arg("push").arg(f.path()).run(builder);
3840 }
3841 }
3842 }
3843}
3844
3845#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3846pub struct Distcheck;
3847
3848impl CommandLineStep for Distcheck {
3849 type Output = ();
3850
3851 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3852 run.alias("distcheck")
3853 }
3854
3855 fn make_run(run: RunConfig<'_>) {
3856 run.builder.ensure(Distcheck);
3857 }
3858
3859 fn run(self, builder: &Builder<'_>) {
3869 let root_dir = std::env::temp_dir().join("distcheck");
3872
3873 distcheck_plain_source_tarball(builder, &root_dir.join("distcheck-rustc-src"));
3874 distcheck_rust_src(builder, &root_dir.join("distcheck-rust-src"));
3875 distcheck_rustc_dev(builder, &root_dir.join("distcheck-rustc-dev"));
3876 }
3877}
3878
3879fn distcheck_plain_source_tarball(builder: &Builder<'_>, plain_src_dir: &Path) {
3881 builder.info("Distcheck plain source tarball");
3882 let plain_src_tarball = builder.ensure(dist::PlainSourceTarball);
3883 builder.clear_dir(plain_src_dir);
3884
3885 let configure_args: Vec<String> = std::env::var("DISTCHECK_CONFIGURE_ARGS")
3886 .map(|args| args.split(" ").map(|s| s.to_string()).collect::<Vec<String>>())
3887 .unwrap_or_default();
3888
3889 command("tar")
3890 .arg("-xf")
3891 .arg(plain_src_tarball.tarball())
3892 .arg("--strip-components=1")
3893 .current_dir(plain_src_dir)
3894 .run(builder);
3895 command("./configure")
3896 .arg("--set")
3897 .arg("rust.omit-git-hash=false")
3898 .arg("--set")
3899 .arg("rust.remap-debuginfo=false")
3900 .args(&configure_args)
3901 .arg("--enable-vendor")
3902 .current_dir(plain_src_dir)
3903 .run(builder);
3904 command(helpers::make(&builder.config.host_target.triple))
3905 .arg("check")
3906 .env("GITHUB_ACTIONS", "0")
3909 .current_dir(plain_src_dir)
3910 .run(builder);
3911 builder.remove_dir(plain_src_dir);
3913}
3914
3915fn distcheck_rust_src(builder: &Builder<'_>, src_dir: &Path) {
3917 builder.info("Distcheck rust-src");
3918 let src_tarball = builder.ensure(dist::Src);
3919 builder.clear_dir(src_dir);
3920
3921 command("tar")
3922 .arg("-xf")
3923 .arg(src_tarball.tarball())
3924 .arg("--strip-components=1")
3925 .current_dir(src_dir)
3926 .run(builder);
3927
3928 let toml = src_dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml");
3929 command(&builder.initial_cargo)
3930 .env("RUSTC_BOOTSTRAP", "1")
3933 .arg("generate-lockfile")
3934 .arg("--manifest-path")
3935 .arg(&toml)
3936 .current_dir(src_dir)
3937 .run(builder);
3938 builder.remove_dir(src_dir);
3940}
3941
3942fn distcheck_rustc_dev(builder: &Builder<'_>, dir: &Path) {
3944 builder.info("Distcheck rustc-dev");
3945 let tarball = builder.ensure(dist::RustcDev::new(builder, builder.host_target)).unwrap();
3946 builder.clear_dir(dir);
3947
3948 command("tar")
3949 .arg("-xf")
3950 .arg(tarball.tarball())
3951 .arg("--strip-components=1")
3952 .current_dir(dir)
3953 .run(builder);
3954
3955 command(&builder.initial_cargo)
3956 .arg("metadata")
3957 .arg("--manifest-path")
3958 .arg("rustc-dev/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml")
3959 .env("RUSTC_BOOTSTRAP", "1")
3960 .env("RUSTC", &builder.initial_rustc)
3962 .current_dir(dir)
3963 .run(builder);
3964 builder.remove_dir(dir);
3966}
3967
3968#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3970pub(crate) struct BootstrapPy;
3971
3972impl CommandLineStep for BootstrapPy {
3973 type Output = ();
3974 const IS_HOST: bool = true;
3975
3976 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3977 run.alias("bootstrap-py")
3978 }
3979
3980 fn is_default_step(builder: &Builder<'_>) -> bool {
3981 builder.config.is_running_on_ci()
3985 }
3986
3987 fn make_run(run: RunConfig<'_>) {
3988 run.builder.ensure(BootstrapPy)
3989 }
3990
3991 fn run(self, builder: &Builder<'_>) -> Self::Output {
3992 let mut check_bootstrap = command(
3993 builder.config.python.as_ref().expect("python is required for running bootstrap tests"),
3994 );
3995 check_bootstrap
3996 .args(["-m", "unittest", "bootstrap_test.py"])
3997 .args(builder.config.test_args())
3999 .env("BUILD_DIR", &builder.out)
4000 .env("BUILD_PLATFORM", builder.build.host_target.triple)
4001 .env("BOOTSTRAP_TEST_RUSTC_BIN", &builder.initial_rustc)
4002 .env("BOOTSTRAP_TEST_CARGO_BIN", &builder.initial_cargo)
4003 .current_dir(builder.src.join("src/bootstrap/"));
4004 check_bootstrap.delay_failure().run(builder);
4005 }
4006}
4007
4008#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4009pub struct Bootstrap;
4010
4011impl CommandLineStep for Bootstrap {
4012 type Output = ();
4013 const IS_HOST: bool = true;
4014
4015 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4016 run.path("src/bootstrap")
4017 }
4018
4019 fn is_default_step(builder: &Builder<'_>) -> bool {
4020 builder.config.is_running_on_ci()
4024 }
4025
4026 fn run(self, builder: &Builder<'_>) {
4028 let host = builder.config.host_target;
4029 let build_compiler = builder.compiler(0, host);
4030 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
4031
4032 builder.build.require_submodule("src/tools/cargo", None);
4034
4035 let mut cargo = tool::prepare_tool_cargo(
4036 builder,
4037 build_compiler,
4038 Mode::ToolBootstrap,
4039 host,
4040 Kind::Test,
4041 "src/bootstrap",
4042 SourceType::InTree,
4043 &[],
4044 );
4045
4046 cargo.release_build(false);
4047
4048 cargo
4049 .rustflag("-Cdebuginfo=2")
4050 .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
4051 .env("INSTA_WORKSPACE_ROOT", &builder.src)
4053 .env("RUSTC_BOOTSTRAP", "1");
4054
4055 if builder.config.cmd.bless() {
4056 cargo.env("INSTA_UPDATE", "always");
4060 }
4061
4062 run_cargo_test(cargo, &[], &[], None, host, builder, record_failed_tests);
4063 }
4064
4065 fn make_run(run: RunConfig<'_>) {
4066 run.builder.ensure(Bootstrap);
4067 }
4068}
4069
4070fn get_compiler_to_test(builder: &Builder<'_>, target: TargetSelection) -> Compiler {
4071 builder.compiler(builder.top_stage, target)
4072}
4073
4074#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4077pub struct TierCheck {
4078 test_compiler: Compiler,
4079}
4080
4081impl CommandLineStep for TierCheck {
4082 type Output = ();
4083 const IS_HOST: bool = true;
4084
4085 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4086 run.path("src/tools/tier-check")
4087 }
4088
4089 fn is_default_step(_builder: &Builder<'_>) -> bool {
4090 true
4091 }
4092
4093 fn make_run(run: RunConfig<'_>) {
4094 run.builder
4095 .ensure(TierCheck { test_compiler: get_compiler_to_test(run.builder, run.target) });
4096 }
4097
4098 fn run(self, builder: &Builder<'_>) {
4099 let tool_build_compiler = builder.compiler(0, builder.host_target);
4100
4101 let mut cargo = tool::prepare_tool_cargo(
4102 builder,
4103 tool_build_compiler,
4104 Mode::ToolBootstrap,
4105 tool_build_compiler.host,
4106 Kind::Run,
4107 "src/tools/tier-check",
4108 SourceType::InTree,
4109 &[],
4110 );
4111 cargo.arg(builder.src.join("src/doc/rustc/src/platform-support.md"));
4112 cargo.arg(builder.rustc(self.test_compiler));
4113
4114 let _guard = builder.msg_test(
4115 "platform support check",
4116 self.test_compiler.host,
4117 self.test_compiler.stage,
4118 );
4119 BootstrapCommand::from(cargo).delay_failure().run(builder);
4120 }
4121
4122 fn metadata(&self) -> Option<StepMetadata> {
4123 Some(StepMetadata::test("tier-check", self.test_compiler.host))
4124 }
4125}
4126
4127#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4128pub struct LintDocs {
4129 build_compiler: Compiler,
4130 target: TargetSelection,
4131}
4132
4133impl CommandLineStep for LintDocs {
4134 type Output = ();
4135 const IS_HOST: bool = true;
4136
4137 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4138 run.path("src/tools/lint-docs")
4139 }
4140
4141 fn is_default_step(builder: &Builder<'_>) -> bool {
4142 builder.top_stage >= 2
4145 }
4146
4147 fn make_run(run: RunConfig<'_>) {
4148 if run.builder.top_stage < 2 {
4149 eprintln!("WARNING: lint-docs tests might not work below stage 2");
4150 }
4151
4152 run.builder.ensure(LintDocs {
4153 build_compiler: prepare_doc_compiler(
4154 run.builder,
4155 run.builder.config.host_target,
4156 run.builder.top_stage,
4157 ),
4158 target: run.target,
4159 });
4160 }
4161
4162 fn run(self, builder: &Builder<'_>) {
4165 builder.ensure(crate::core::build_steps::doc::RustcBook::validate(
4166 self.build_compiler,
4167 self.target,
4168 ));
4169 }
4170
4171 fn metadata(&self) -> Option<StepMetadata> {
4172 Some(StepMetadata::test("lint-docs", self.target).built_by(self.build_compiler))
4173 }
4174}
4175
4176#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4177pub struct RustInstaller;
4178
4179impl CommandLineStep for RustInstaller {
4180 type Output = ();
4181 const IS_HOST: bool = true;
4182
4183 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4184 run.path("src/tools/rust-installer")
4185 }
4186
4187 fn is_default_step(_builder: &Builder<'_>) -> bool {
4188 true
4189 }
4190
4191 fn make_run(run: RunConfig<'_>) {
4192 run.builder.ensure(Self);
4193 }
4194
4195 fn run(self, builder: &Builder<'_>) {
4197 let bootstrap_host = builder.config.host_target;
4198 let build_compiler = builder.compiler(0, bootstrap_host);
4199 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
4200 let cargo = tool::prepare_tool_cargo(
4201 builder,
4202 build_compiler,
4203 Mode::ToolBootstrap,
4204 bootstrap_host,
4205 Kind::Test,
4206 "src/tools/rust-installer",
4207 SourceType::InTree,
4208 &[],
4209 );
4210
4211 let _guard = builder.msg_test("rust-installer", bootstrap_host, 1);
4212 run_cargo_test(cargo, &[], &[], None, bootstrap_host, builder, record_failed_tests);
4213
4214 if bootstrap_host != "x86_64-unknown-linux-gnu" {
4218 return;
4219 }
4220
4221 let mut cmd = command(builder.src.join("src/tools/rust-installer/test.sh"));
4222 let tmpdir = testdir(builder, build_compiler.host).join("rust-installer");
4223 let _ = std::fs::remove_dir_all(&tmpdir);
4224 let _ = std::fs::create_dir_all(&tmpdir);
4225 cmd.current_dir(&tmpdir);
4226 cmd.env("CARGO_TARGET_DIR", tmpdir.join("cargo-target"));
4227 cmd.env("CARGO", &builder.initial_cargo);
4228 cmd.env("RUSTC", &builder.initial_rustc);
4229 cmd.env("TMP_DIR", &tmpdir);
4230 cmd.delay_failure().run(builder);
4231 }
4232}
4233
4234#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4235pub struct TestHelpers {
4236 pub target: TargetSelection,
4237}
4238
4239impl CommandLineStep for TestHelpers {
4240 type Output = ();
4241
4242 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4243 run.path("tests/auxiliary/rust_test_helpers.c")
4244 }
4245
4246 fn make_run(run: RunConfig<'_>) {
4247 run.builder.ensure(TestHelpers { target: run.target })
4248 }
4249
4250 fn run(self, builder: &Builder<'_>) {
4253 if builder.config.dry_run() {
4254 return;
4255 }
4256 let target = if self.target == "x86_64-fortanix-unknown-sgx" {
4260 TargetSelection::from_user("x86_64-unknown-linux-gnu")
4261 } else {
4262 self.target
4263 };
4264 let dst = builder.test_helpers_out(target);
4265 let src = builder.src.join("tests/auxiliary/rust_test_helpers.c");
4266 let _guard = builder.msg_unstaged(Kind::Build, "test helpers", target);
4267 t!(fs::create_dir_all(&dst));
4268
4269 if !up_to_date(&src, &dst.join("librust_test_helpers.a")) {
4270 let mut cfg = cc::Build::new();
4271
4272 if !target.is_msvc() {
4276 if let Some(ar) = builder.ar(target) {
4277 cfg.archiver(ar);
4278 }
4279 cfg.compiler(builder.cc(target));
4280 }
4281 cfg.cargo_metadata(false)
4282 .out_dir(&dst)
4283 .target(&target.triple)
4284 .host(&builder.config.host_target.triple)
4285 .opt_level(0)
4286 .warnings(false)
4287 .debug(false)
4288 .file(builder.src.join("tests/auxiliary/rust_test_helpers.c"))
4289 .compile("rust_test_helpers");
4290 }
4291 if target.is_pauthtest() {
4292 let so = dst.join("librust_test_helpers.so");
4293 if up_to_date(&src, &so) {
4294 return;
4295 }
4296
4297 let status = Command::new(builder.cc(target))
4298 .arg("-target")
4299 .arg(target.triple)
4300 .arg("-march=armv8.3-a+pauth")
4301 .arg("-fPIC")
4302 .arg("-shared")
4303 .arg("-O0") .arg("-o")
4305 .arg(&so)
4306 .arg(&src)
4307 .status()
4308 .unwrap_or_else(|_| panic!("Failed to run clang for {} toolchain", target.triple));
4309
4310 if !status.success() {
4311 panic!("Linking of librust_test_helpers.so failed (target: {})", target.triple);
4312 }
4313 }
4314 }
4315}
4316
4317#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4318pub struct CodegenCranelift {
4319 compilers: RustcPrivateCompilers,
4320 target: TargetSelection,
4321}
4322
4323impl CommandLineStep for CodegenCranelift {
4324 type Output = ();
4325 const IS_HOST: bool = true;
4326
4327 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4328 run.path("compiler/rustc_codegen_cranelift")
4329 }
4330
4331 fn is_default_step(_builder: &Builder<'_>) -> bool {
4332 true
4333 }
4334
4335 fn make_run(run: RunConfig<'_>) {
4336 let builder = run.builder;
4337 let host = run.build_triple();
4338 let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, host);
4339
4340 if builder.test_target == TestTarget::DocOnly {
4341 return;
4342 }
4343
4344 if builder.download_rustc() {
4345 builder.info("CI rustc uses the default codegen backend. skipping");
4346 return;
4347 }
4348
4349 if !target_supports_cranelift_backend(run.target) {
4350 builder.info("target not supported by rustc_codegen_cranelift. skipping");
4351 return;
4352 }
4353
4354 if builder.remote_tested(run.target) {
4355 builder.info("remote testing is not supported by rustc_codegen_cranelift. skipping");
4356 return;
4357 }
4358
4359 if !builder
4360 .config
4361 .enabled_codegen_backends(run.target)
4362 .contains(&CodegenBackendKind::Cranelift)
4363 {
4364 builder.info("cranelift not in rust.codegen-backends. skipping");
4365 return;
4366 }
4367
4368 builder.ensure(CodegenCranelift { compilers, target: run.target });
4369 }
4370
4371 fn run(self, builder: &Builder<'_>) {
4372 let compilers = self.compilers;
4373 let build_compiler = compilers.build_compiler();
4374
4375 let target_compiler = compilers.target_compiler();
4378 let target = self.target;
4379
4380 builder.std(target_compiler, target);
4381
4382 let mut cargo = builder::Cargo::new(
4383 builder,
4384 target_compiler,
4385 Mode::Codegen, SourceType::InTree,
4387 target,
4388 Kind::Run,
4389 );
4390
4391 cargo.current_dir(&builder.src.join("compiler/rustc_codegen_cranelift"));
4392 cargo
4393 .arg("--manifest-path")
4394 .arg(builder.src.join("compiler/rustc_codegen_cranelift/build_system/Cargo.toml"));
4395 compile::rustc_cargo_env(builder, &mut cargo, target);
4396
4397 cargo.env("CARGO_BUILD_INCREMENTAL", "false");
4399
4400 let _guard = builder.msg_test(
4401 "rustc_codegen_cranelift",
4402 target_compiler.host,
4403 target_compiler.stage,
4404 );
4405
4406 let download_dir = builder.out.join("cg_clif_download");
4408
4409 cargo
4410 .arg("--")
4411 .arg("test")
4412 .arg("--download-dir")
4413 .arg(&download_dir)
4414 .arg("--out-dir")
4415 .arg(builder.stage_out(build_compiler, Mode::Codegen).join("cg_clif"))
4416 .arg("--no-unstable-features")
4417 .arg("--use-backend")
4418 .arg("cranelift")
4419 .arg("--sysroot")
4421 .arg("llvm")
4422 .arg("--skip-test")
4425 .arg("testsuite.extended_sysroot");
4426
4427 cargo.into_cmd().run(builder);
4428 }
4429
4430 fn metadata(&self) -> Option<StepMetadata> {
4431 Some(
4432 StepMetadata::test("rustc_codegen_cranelift", self.target)
4433 .built_by(self.compilers.build_compiler()),
4434 )
4435 }
4436}
4437
4438#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4439pub struct CodegenGCC {
4440 compilers: RustcPrivateCompilers,
4441 target: TargetSelection,
4442}
4443
4444impl CommandLineStep for CodegenGCC {
4445 type Output = ();
4446 const IS_HOST: bool = true;
4447
4448 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4449 run.path("compiler/rustc_codegen_gcc")
4450 }
4451
4452 fn is_default_step(_builder: &Builder<'_>) -> bool {
4453 true
4454 }
4455
4456 fn make_run(run: RunConfig<'_>) {
4457 let builder = run.builder;
4458 let host = run.build_triple();
4459 let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, host);
4460
4461 if builder.test_target == TestTarget::DocOnly {
4462 return;
4463 }
4464
4465 if builder.download_rustc() {
4466 builder.info("CI rustc uses the default codegen backend. skipping");
4467 return;
4468 }
4469
4470 let triple = run.target.triple;
4471 let target_supported =
4472 if triple.contains("linux") { triple.contains("x86_64") } else { false };
4473 if !target_supported {
4474 builder.info("target not supported by rustc_codegen_gcc. skipping");
4475 return;
4476 }
4477
4478 if builder.remote_tested(run.target) {
4479 builder.info("remote testing is not supported by rustc_codegen_gcc. skipping");
4480 return;
4481 }
4482
4483 if !builder.config.enabled_codegen_backends(run.target).contains(&CodegenBackendKind::Gcc) {
4484 builder.info("gcc not in rust.codegen-backends. skipping");
4485 return;
4486 }
4487
4488 builder.ensure(CodegenGCC { compilers, target: run.target });
4489 }
4490
4491 fn run(self, builder: &Builder<'_>) {
4492 let compilers = self.compilers;
4493 let target = self.target;
4494
4495 let gcc = builder.ensure(Gcc { target_pair: GccTargetPair::for_native_build(target) });
4496
4497 builder.ensure(
4498 compile::Std::new(compilers.build_compiler(), target)
4499 .extra_rust_args(&["-Csymbol-mangling-version=v0", "-Cpanic=abort"]),
4500 );
4501
4502 let _guard = builder.msg_test(
4503 "rustc_codegen_gcc",
4504 compilers.target(),
4505 compilers.target_compiler().stage,
4506 );
4507
4508 let mut cargo = builder::Cargo::new(
4509 builder,
4510 compilers.build_compiler(),
4511 Mode::Codegen, SourceType::InTree,
4513 target,
4514 Kind::Run,
4515 );
4516
4517 cargo.current_dir(&builder.src.join("compiler/rustc_codegen_gcc"));
4518 cargo
4519 .arg("--manifest-path")
4520 .arg(builder.src.join("compiler/rustc_codegen_gcc/build_system/Cargo.toml"));
4521 compile::rustc_cargo_env(builder, &mut cargo, target);
4522 add_cg_gcc_cargo_flags(&mut cargo, &gcc);
4523
4524 cargo.env("CARGO_BUILD_INCREMENTAL", "false");
4526 cargo.rustflag("-Cpanic=abort");
4527
4528 cargo
4529 .env("CG_RUSTFLAGS", "-Alinker-messages")
4531 .arg("--")
4532 .arg("test")
4533 .arg("--use-backend")
4534 .arg("gcc")
4535 .arg("--gcc-path")
4536 .arg(gcc.libgccjit().parent().unwrap())
4537 .arg("--out-dir")
4538 .arg(builder.stage_out(compilers.build_compiler(), Mode::Codegen).join("cg_gcc"))
4539 .arg("--release")
4540 .arg("--mini-tests")
4541 .arg("--std-tests");
4542
4543 cargo.args(builder.config.test_args());
4544
4545 cargo.into_cmd().run(builder);
4546 }
4547
4548 fn metadata(&self) -> Option<StepMetadata> {
4549 Some(
4550 StepMetadata::test("rustc_codegen_gcc", self.target)
4551 .built_by(self.compilers.build_compiler()),
4552 )
4553 }
4554}
4555
4556#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4561pub struct TestFloatParse {
4562 build_compiler: Compiler,
4571 target: TargetSelection,
4573}
4574
4575impl CommandLineStep for TestFloatParse {
4576 type Output = ();
4577 const IS_HOST: bool = true;
4578
4579 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4580 run.path("src/tools/test-float-parse")
4581 }
4582
4583 fn is_default_step(_builder: &Builder<'_>) -> bool {
4584 true
4585 }
4586
4587 fn make_run(run: RunConfig<'_>) {
4588 run.builder.ensure(Self {
4589 build_compiler: get_compiler_to_test(run.builder, run.target),
4590 target: run.target,
4591 });
4592 }
4593
4594 fn run(self, builder: &Builder<'_>) {
4595 let build_compiler = self.build_compiler;
4596 let target = self.target;
4597
4598 builder.std(build_compiler, target);
4600 builder.std(build_compiler, builder.host_target);
4601 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
4602
4603 let mut cargo_test = tool::prepare_tool_cargo(
4605 builder,
4606 build_compiler,
4607 Mode::ToolStd,
4608 target,
4609 Kind::Test,
4610 "src/tools/test-float-parse",
4611 SourceType::InTree,
4612 &[],
4613 );
4614 cargo_test.allow_features(TEST_FLOAT_PARSE_ALLOW_FEATURES);
4615
4616 run_cargo_test(
4617 cargo_test,
4618 &[],
4619 &[],
4620 "test-float-parse",
4621 target,
4622 builder,
4623 record_failed_tests,
4624 );
4625
4626 let mut cargo_run = tool::prepare_tool_cargo(
4628 builder,
4629 build_compiler,
4630 Mode::ToolStd,
4631 target,
4632 Kind::Run,
4633 "src/tools/test-float-parse",
4634 SourceType::InTree,
4635 &[],
4636 );
4637 cargo_run.allow_features(TEST_FLOAT_PARSE_ALLOW_FEATURES);
4638
4639 if !matches!(env::var("FLOAT_PARSE_TESTS_NO_SKIP_HUGE").as_deref(), Ok("1") | Ok("true")) {
4640 cargo_run.args(["--", "--skip-huge"]);
4641 }
4642
4643 cargo_run.into_cmd().run(builder);
4644 }
4645}
4646
4647#[derive(Debug, Clone, Hash, PartialEq, Eq)]
4651pub struct CollectLicenseMetadata;
4652
4653impl CommandLineStep for CollectLicenseMetadata {
4654 type Output = PathBuf;
4655 const IS_HOST: bool = true;
4656
4657 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4658 run.path("src/tools/collect-license-metadata")
4659 }
4660
4661 fn make_run(run: RunConfig<'_>) {
4662 run.builder.ensure(CollectLicenseMetadata);
4663 }
4664
4665 fn run(self, builder: &Builder<'_>) -> Self::Output {
4666 let Some(reuse) = &builder.config.reuse else {
4667 panic!("REUSE is required to collect the license metadata");
4668 };
4669
4670 let dest = builder.src.join("license-metadata.json");
4671
4672 let mut cmd = builder.tool_cmd(Tool::CollectLicenseMetadata);
4673 cmd.env("REUSE_EXE", reuse);
4674 cmd.env("DEST", &dest);
4675 cmd.env("ONLY_CHECK", "1");
4676 cmd.run(builder);
4677
4678 dest
4679 }
4680}
4681
4682#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4683pub struct RemoteTestClientTests {
4684 host: TargetSelection,
4685}
4686
4687impl CommandLineStep for RemoteTestClientTests {
4688 type Output = ();
4689 const IS_HOST: bool = true;
4690
4691 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4692 run.path("src/tools/remote-test-client")
4693 }
4694
4695 fn is_default_step(_builder: &Builder<'_>) -> bool {
4696 true
4697 }
4698
4699 fn make_run(run: RunConfig<'_>) {
4700 run.builder.ensure(Self { host: run.target });
4701 }
4702
4703 fn run(self, builder: &Builder<'_>) {
4704 let bootstrap_host = builder.config.host_target;
4705 let compiler = builder.compiler(0, bootstrap_host);
4706 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
4707
4708 let cargo = tool::prepare_tool_cargo(
4709 builder,
4710 compiler,
4711 Mode::ToolBootstrap,
4712 bootstrap_host,
4713 Kind::Test,
4714 "src/tools/remote-test-client",
4715 SourceType::InTree,
4716 &[],
4717 );
4718
4719 run_cargo_test(
4720 cargo,
4721 &[],
4722 &[],
4723 "remote-test-client",
4724 bootstrap_host,
4725 builder,
4726 record_failed_tests,
4727 );
4728 }
4729}
4730
4731fn check_if_cargo_semver_checks_is_installed(builder: &Builder<'_>) -> bool {
4732 command(&builder.initial_cargo)
4733 .allow_failure()
4734 .arg("semver-checks")
4735 .arg("--version")
4736 .cached()
4738 .run_capture_stdout(builder)
4739 .is_success()
4740}
4741
4742#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4753pub struct StdSemverCheck {
4754 build_compiler: Compiler,
4755 target: TargetSelection,
4756 commit: String,
4758}
4759
4760impl CommandLineStep for StdSemverCheck {
4761 type Output = ();
4762
4763 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4764 run.alias("std-semver-check")
4765 }
4766
4767 fn make_run(run: RunConfig<'_>) {
4768 if !check_if_cargo_semver_checks_is_installed(run.builder) {
4769 panic!("cargo-semver-checks was not found, please install it");
4770 }
4771
4772 let baseline_commit =
4773 run.builder.config.stdlib_semver_baseline.clone().unwrap_or_else(|| {
4774 match get_closest_upstream_commit(
4775 Some(&run.builder.config.src),
4776 &run.builder.config.git_config(),
4777 run.builder.config.ci_env,
4778 ) {
4779 Ok(Some(commit)) => commit,
4780 Ok(None) => {
4781 panic!("No baseline parent commit found for std-semver-check");
4782 }
4783 Err(error) => {
4784 panic!("Cannot get baseline parent commit for std-semver-check: {error:?}");
4785 }
4786 }
4787 });
4788
4789 run.builder.ensure(Self {
4790 build_compiler: run.builder.compiler_for_std(run.builder.top_stage),
4791 target: run.target,
4792 commit: baseline_commit,
4793 });
4794 }
4795
4796 fn run(self, builder: &Builder<'_>) {
4797 const STDLIB_SEMVER_CHECK_STAMP_PATH: &str = "src/bootstrap/stdlib-semver-check-stamp";
4798
4799 if builder.config.ci_env.is_running_in_ci()
4800 && builder.config.has_changes_from_upstream(&[STDLIB_SEMVER_CHECK_STAMP_PATH])
4801 {
4802 builder.info(&format!("Skipping stdlib semver check, because {STDLIB_SEMVER_CHECK_STAMP_PATH} was modified."));
4803 return;
4804 }
4805
4806 let Some(docs_dir) = builder.config.download_std_json_docs(self.target, &self.commit)
4807 else {
4808 return;
4809 };
4810
4811 let directory = builder.ensure(crate::core::build_steps::doc::Std::from_build_compiler(
4812 self.build_compiler,
4813 self.target,
4814 DocumentationFormat::Json,
4815 ));
4816 let baseline_dir = docs_dir.join("share").join("doc").join("rust").join("json");
4817
4818 for library in ["core", "alloc", "std"] {
4819 println!("Checking semver compatibility of {library}");
4820 let mut cmd = command(&builder.initial_cargo);
4821 cmd.arg("semver-checks")
4822 .arg("-Z")
4823 .arg("unstable-options")
4824 .arg("--stability-aware")
4825 .arg("--release-type")
4826 .arg("minor")
4827 .arg("--current-rustdoc")
4828 .arg(directory.join(format!("{library}.json")))
4829 .arg("--baseline-rustdoc")
4830 .arg(baseline_dir.join(format!("{library}.json")));
4831
4832 let res = cmd.allow_failure().run_capture(builder);
4834 match res.status() {
4835 Some(status) if status.success() => {
4836 println!("{}\n{}", res.stdout(), res.stderr());
4837 }
4838 Some(status) if status.code() == Some(101) => {
4841 eprintln!(
4842 "cargo-semver-checks was unable to process {library} (this is not a fatal error)\n{}\n{}",
4843 res.stderr(),
4844 res.stdout()
4845 );
4846 }
4847 Some(status) if status.code() == Some(100) => {
4849 let error = format!(
4850 "cargo-semver-checks found semver breakage in {library}\n{}\n{}",
4851 res.stderr(),
4852 res.stdout()
4853 );
4854 if builder.fail_fast {
4855 eprintln!("{error}",);
4856 helpers::exit_process(1);
4857 } else {
4858 builder.config.exec_ctx().add_to_delay_failure(error);
4859 }
4860 }
4861 _ => {
4862 eprintln!("cargo-semver-checks failed.\n{}\n{}", res.stderr(), res.stdout());
4863 helpers::exit_process(1);
4864 }
4865 }
4866 }
4867 }
4868}