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