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!(AssemblyLlvm {
2044 path: "tests/assembly-llvm",
2045 mode: CompiletestMode::Assembly,
2046 suite: "assembly-llvm",
2047 default: true
2048});
2049
2050#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2053pub struct Coverage {
2054 pub compiler: Compiler,
2055 pub target: TargetSelection,
2056 pub(crate) mode: CompiletestMode,
2057}
2058
2059impl Coverage {
2060 const PATH: &'static str = "tests/coverage";
2061 const SUITE: &'static str = "coverage";
2062 const ALL_MODES: &[CompiletestMode] =
2063 &[CompiletestMode::CoverageMap, CompiletestMode::CoverageRun];
2064
2065 fn new(run: &RunConfig<'_>, mode: CompiletestMode) -> Self {
2066 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
2067 let target = run.target;
2068 Coverage { compiler, target, mode }
2069 }
2070}
2071
2072impl CommandLineStep for Coverage {
2073 type Output = ();
2074 const IS_HOST: bool = false;
2076
2077 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2078 run.suite_path(Coverage::PATH)
2085 }
2086
2087 fn is_default_step(_builder: &Builder<'_>) -> bool {
2088 true
2089 }
2090
2091 fn make_run(run: RunConfig<'_>) {
2092 for &mode in Coverage::ALL_MODES {
2096 if !run.builder.config.skip.iter().any(|skip| skip == Path::new(mode.as_str())) {
2097 run.builder.ensure(Coverage::new(&run, mode));
2098 }
2099 }
2100 }
2101
2102 fn run(self, builder: &Builder<'_>) {
2103 let Self { compiler, target, mode } = self;
2104 builder.ensure(Compiletest {
2107 test_compiler: compiler,
2108 target,
2109 mode,
2110 suite: Self::SUITE,
2111 path: Self::PATH,
2112 compare_mode: None,
2113 });
2114 }
2115}
2116
2117#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2125pub enum CoverageModeAlias {}
2126
2127impl CommandLineStep for CoverageModeAlias {
2128 type Output = ();
2129
2130 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2131 Coverage::ALL_MODES.iter().fold(run, |run, mode| run.alias(mode.as_str()))
2136 }
2137
2138 fn is_default_step(_builder: &Builder<'_>) -> bool {
2139 false
2140 }
2141
2142 fn make_run(run: RunConfig<'_>) {
2143 for path in &run.paths {
2144 let single_path = &path.assert_single_path().path;
2145 for &mode in Coverage::ALL_MODES {
2146 if single_path == Path::new(mode.as_str()) {
2147 run.builder.ensure(Coverage::new(&run, mode));
2150 }
2151 }
2152 }
2153 }
2154
2155 fn run(self, _builder: &Builder<'_>) {
2156 unreachable!("never instantiated; `make_run` creates a Coverage step instead");
2157 }
2158}
2159
2160test!(CoverageRunRustdoc {
2161 path: "tests/coverage-run-rustdoc",
2162 mode: CompiletestMode::CoverageRun,
2163 suite: "coverage-run-rustdoc",
2164 default: true,
2165 IS_HOST: true,
2166});
2167
2168#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2170pub struct MirOpt {
2171 pub compiler: Compiler,
2172 pub target: TargetSelection,
2173}
2174
2175impl CommandLineStep for MirOpt {
2176 type Output = ();
2177
2178 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2179 run.suite_path("tests/mir-opt")
2180 }
2181
2182 fn is_default_step(_builder: &Builder<'_>) -> bool {
2183 true
2184 }
2185
2186 fn make_run(run: RunConfig<'_>) {
2187 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
2188 run.builder.ensure(MirOpt { compiler, target: run.target });
2189 }
2190
2191 fn run(self, builder: &Builder<'_>) {
2192 let run = |target| {
2193 builder.ensure(Compiletest {
2194 test_compiler: self.compiler,
2195 target,
2196 mode: CompiletestMode::MirOpt,
2197 suite: "mir-opt",
2198 path: "tests/mir-opt",
2199 compare_mode: None,
2200 })
2201 };
2202
2203 run(self.target);
2204
2205 if builder.config.cmd.bless() {
2208 for target in ["aarch64-unknown-linux-gnu", "i686-pc-windows-msvc"] {
2214 run(TargetSelection::from_user(target));
2215 }
2216
2217 for target in ["x86_64-apple-darwin", "i686-unknown-linux-musl"] {
2218 let target = TargetSelection::from_user(target);
2219 let panic_abort_target = builder.ensure(MirOptPanicAbortSyntheticTarget {
2220 compiler: self.compiler,
2221 base: target,
2222 });
2223 run(panic_abort_target);
2224 }
2225 }
2226 }
2227}
2228
2229#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2235struct Compiletest {
2236 test_compiler: Compiler,
2238 target: TargetSelection,
2239 mode: CompiletestMode,
2240 suite: &'static str,
2241 path: &'static str,
2242 compare_mode: Option<&'static str>,
2243}
2244
2245impl Step for Compiletest {
2246 type Output = ();
2247
2248 fn run(self, builder: &Builder<'_>) {
2249 if builder.test_target == TestTarget::DocOnly {
2250 return;
2251 }
2252
2253 if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 {
2254 eprintln!("\
2255ERROR: `--stage 0` runs compiletest on the stage0 (precompiled) compiler, not your local changes, and will almost always cause tests to fail
2256HELP: to test the compiler or standard library, omit the stage or explicitly use `--stage 1` instead
2257NOTE: 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`."
2258 );
2259 helpers::exit_process(1);
2260 }
2261
2262 let mut test_compiler = self.test_compiler;
2263 let target = self.target;
2264 let mode = self.mode;
2265 let suite = self.suite;
2266 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
2267
2268 let suite_path = self.path;
2270
2271 if !builder.config.codegen_tests && mode == CompiletestMode::Codegen {
2273 return;
2274 }
2275
2276 let query_compiler;
2283 let (stage, stage_id) = if suite == "ui-fulldeps" && test_compiler.stage == 1 {
2284 builder.info("Warning: running ui-fulldeps tests in stage 1 might cause failures");
2285
2286 query_compiler = Some(test_compiler);
2289 let build = builder.sess.host_target;
2293 test_compiler = builder.compiler(test_compiler.stage - 1, build);
2294 let test_stage = test_compiler.stage + 1;
2295 (test_stage, format!("stage{test_stage}-{build}"))
2296 } else {
2297 query_compiler = None;
2298 let stage = test_compiler.stage;
2299 (stage, format!("stage{stage}-{target}"))
2300 };
2301
2302 if suite.ends_with("fulldeps") {
2303 builder.ensure(compile::Rustc::new(test_compiler, target));
2304 }
2305
2306 if builder.config.wasm_proc_macros {
2308 builder.ensure(compile::Std::new(
2309 test_compiler,
2310 TargetSelection::from_user("wasm32-wasip2"),
2311 ));
2312 }
2313
2314 if suite == "debuginfo" {
2315 builder.ensure(dist::DebuggerScripts {
2316 sysroot: builder.sysroot(test_compiler).to_path_buf(),
2317 target,
2318 });
2319 }
2320
2321 if suite == "mir-opt" {
2323 builder.ensure(
2324 compile::Std::new(test_compiler, test_compiler.host).is_for_mir_opt_tests(true),
2325 );
2326 } else {
2327 builder.std(test_compiler, test_compiler.host);
2328 }
2329
2330 let mut cmd = builder.tool_cmd(Tool::Compiletest);
2331
2332 if mode == CompiletestMode::RunMake {
2333 let output = builder.tool(Tool::RunMakeSupport);
2336 let find = |extension: &str| -> Option<&PathBuf> {
2337 output.artifacts.iter().find_map(|p| {
2338 let filename = p.file_name()?.to_str()?;
2343 if !filename.starts_with("librun_make_support") {
2344 return None;
2345 }
2346
2347 if extension == p.extension()? { Some(p) } else { None }
2348 })
2349 };
2350 if !builder.config.dry_run() {
2351 let rlib =
2352 find("rlib").expect(".rlib not found when compiling librun_make_support");
2353 cmd.arg("--run-make-support-rlib").arg(rlib);
2354
2355 if let Some(rmeta) = find("rmeta") {
2357 cmd.arg("--run-make-support-rmeta").arg(rmeta);
2358 }
2359 }
2360 }
2361
2362 if suite == "mir-opt" {
2363 builder.ensure(compile::Std::new(test_compiler, target).is_for_mir_opt_tests(true));
2364 } else {
2365 builder.std(test_compiler, target);
2366 }
2367
2368 builder.ensure(RemoteCopyLibs { build_compiler: test_compiler, target });
2369
2370 cmd.arg("--stage").arg(stage.to_string());
2374 cmd.arg("--stage-id").arg(stage_id);
2375
2376 cmd.arg("--compile-lib-path").arg(builder.rustc_libdir(test_compiler));
2377 cmd.arg("--run-lib-path").arg(builder.sysroot_target_libdir(test_compiler, target));
2378 cmd.arg("--rustc-path").arg(builder.rustc(test_compiler));
2379 if let Some(query_compiler) = query_compiler {
2380 cmd.arg("--query-rustc-path").arg(builder.rustc(query_compiler));
2381 cmd.arg("--query-rustc-lib-path").arg(builder.rustc_libdir(query_compiler));
2382 }
2383
2384 cmd.arg("--minicore-path")
2387 .arg(builder.src.join("tests").join("auxiliary").join("minicore.rs"));
2388
2389 let is_rustdoc = suite == "rustdoc-ui" || suite == "rustdoc-js";
2390
2391 if builder.config.wasm_proc_macros {
2392 cmd.arg("--wasm-proc-macros");
2393 }
2394
2395 if mode == CompiletestMode::RunMake {
2410 let stage0_rustc_path = builder.compiler(0, test_compiler.host);
2413 cmd.arg("--stage0-rustc-path").arg(builder.rustc(stage0_rustc_path));
2414
2415 if matches!(suite, "run-make-cargo" | "build-std") {
2416 let cargo_path = if test_compiler.stage == 0 {
2417 builder.initial_cargo.clone()
2419 } else {
2420 builder
2421 .ensure(tool::Cargo::from_build_compiler(
2422 builder.compiler(test_compiler.stage - 1, test_compiler.host),
2423 test_compiler.host,
2424 ))
2425 .tool_path
2426 };
2427
2428 cmd.arg("--cargo-path").arg(cargo_path);
2429 }
2430 }
2431
2432 if matches!(
2434 mode,
2435 CompiletestMode::RunMake
2436 | CompiletestMode::RustdocHtml
2437 | CompiletestMode::RustdocJs
2438 | CompiletestMode::RustdocJson
2439 ) || matches!(suite, "rustdoc-ui" | "coverage-run-rustdoc")
2440 {
2441 cmd.arg("--rustdoc-path").arg(builder.rustdoc_for_compiler(test_compiler));
2442 }
2443
2444 if mode == CompiletestMode::RustdocJson {
2445 let json_compiler = builder.compiler(0, builder.host_target);
2447 cmd.arg("--jsondocck-path")
2448 .arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target }).tool_path);
2449 cmd.arg("--jsondoclint-path").arg(
2450 builder.ensure(tool::JsonDocLint { compiler: json_compiler, target }).tool_path,
2451 );
2452 }
2453
2454 if matches!(mode, CompiletestMode::CoverageMap | CompiletestMode::CoverageRun) {
2455 let coverage_dump = builder.tool_exe(Tool::CoverageDump);
2456 cmd.arg("--coverage-dump-path").arg(coverage_dump);
2457 }
2458
2459 cmd.arg("--src-root").arg(&builder.src);
2460 cmd.arg("--src-test-suite-root").arg(builder.src.join("tests").join(suite));
2461
2462 cmd.arg("--build-root").arg(&builder.out);
2466 cmd.arg("--build-test-suite-root").arg(testdir(builder, test_compiler.host).join(suite));
2467
2468 let sysroot = if builder.top_stage == 0 {
2473 builder.initial_sysroot.clone()
2474 } else {
2475 builder.sysroot(test_compiler)
2476 };
2477
2478 cmd.arg("--sysroot-base").arg(sysroot);
2479
2480 cmd.arg("--suite").arg(suite);
2481 cmd.arg("--mode").arg(mode.as_str());
2482 cmd.arg("--target").arg(target.rustc_target_arg());
2483 cmd.arg("--host").arg(&*test_compiler.host.triple);
2484
2485 let filecheck = builder.ensure(llvm::FileCheck { target: builder.config.host_target });
2486 cmd.arg("--llvm-filecheck").arg(filecheck);
2487
2488 if let Some(codegen_backend) = builder.config.cmd.test_codegen_backend() {
2489 if !builder
2490 .config
2491 .enabled_codegen_backends(test_compiler.host)
2492 .contains(codegen_backend)
2493 {
2494 eprintln!(
2495 "\
2496ERROR: No configured backend named `{name}`
2497HELP: You can add it into `bootstrap.toml` in `rust.codegen-backends = [{name:?}]`",
2498 name = codegen_backend.name(),
2499 );
2500 helpers::exit_process(1);
2501 }
2502
2503 if let CodegenBackendKind::Gcc = codegen_backend
2504 && builder.config.rustc_debug_assertions
2505 {
2506 eprintln!(
2507 r#"WARNING: Running tests with the GCC codegen backend while rustc debug assertions are enabled. This might lead to test failures.
2508Please disable assertions with `rust.debug-assertions = false`.
2509 "#
2510 );
2511 }
2512
2513 cmd.arg("--override-codegen-backend").arg(codegen_backend.name());
2516 cmd.arg("--default-codegen-backend").arg(codegen_backend.name());
2519 } else {
2520 cmd.arg("--default-codegen-backend")
2523 .arg(builder.config.default_codegen_backend(test_compiler.host).name());
2524 }
2525 if builder.config.cmd.bypass_ignore_backends() {
2526 cmd.arg("--bypass-ignore-backends");
2527 }
2528
2529 if builder.sess.config.llvm_enzyme {
2530 cmd.arg("--has-enzyme");
2531 }
2532
2533 if builder.sess.config.llvm_offload {
2534 cmd.arg("--has-offload");
2535 }
2536
2537 if builder.config.cmd.bless() {
2538 cmd.arg("--bless");
2539 }
2540
2541 if builder.config.cmd.force_rerun() {
2542 cmd.arg("--force-rerun");
2543 }
2544
2545 if builder.config.cmd.no_capture() {
2546 cmd.arg("--no-capture");
2547 }
2548
2549 let compare_mode =
2550 builder.config.cmd.compare_mode().or_else(|| {
2551 if builder.config.test_compare_mode { self.compare_mode } else { None }
2552 });
2553
2554 if let Some(ref pass) = builder.config.cmd.pass() {
2555 cmd.arg("--pass");
2556 cmd.arg(pass);
2557 }
2558
2559 if let Some(ref run) = builder.config.cmd.run() {
2560 cmd.arg("--run");
2561 cmd.arg(run);
2562 }
2563
2564 if let Some(ref nodejs) = builder.config.nodejs {
2565 cmd.arg("--nodejs").arg(nodejs);
2566 } else if mode == CompiletestMode::RustdocJs {
2567 panic!("need nodejs to run rustdoc-js suite");
2568 }
2569 if builder.config.rust_optimize_tests {
2570 cmd.arg("--optimize-tests");
2571 }
2572 if !builder.config.docs_minification {
2573 cmd.arg("--disable-minification");
2574 }
2575 if builder.config.rust_randomize_layout {
2576 cmd.arg("--rust-randomized-layout");
2577 }
2578 if builder.config.cmd.only_modified() {
2579 cmd.arg("--only-modified");
2580 }
2581 if let Some(compiletest_diff_tool) = &builder.config.compiletest_diff_tool {
2582 cmd.arg("--compiletest-diff-tool").arg(compiletest_diff_tool);
2583 }
2584
2585 let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
2586 flags.push(format!(
2587 "-Cdebuginfo={}",
2588 if mode == CompiletestMode::Codegen {
2589 if builder.config.rust_debuginfo_level_tests
2592 != crate::core::config::DebuginfoLevel::None
2593 {
2594 println!(
2595 "NOTE: ignoring `rust.debuginfo-level-tests={}` for codegen tests",
2596 builder.config.rust_debuginfo_level_tests
2597 );
2598 }
2599 crate::core::config::DebuginfoLevel::None
2600 } else {
2601 builder.config.rust_debuginfo_level_tests
2602 }
2603 ));
2604 flags.extend(builder.config.cmd.compiletest_rustc_args().iter().map(|s| s.to_string()));
2605
2606 if suite != "mir-opt" {
2607 if let Some(linker) = builder.linker(target) {
2608 cmd.arg("--target-linker").arg(linker);
2609 }
2610 if let Some(linker) = builder.linker(test_compiler.host) {
2611 cmd.arg("--host-linker").arg(linker);
2612 }
2613 }
2614
2615 if suite == "ui-fulldeps" && target.ends_with("darwin") {
2617 flags.push("-Alinker_messages".into());
2618 }
2619
2620 let mut hostflags = flags.clone();
2621 hostflags.extend(linker_flags(builder, test_compiler.host, LldThreads::No));
2622
2623 let mut targetflags = flags;
2624
2625 if suite == "ui" || suite == "incremental" {
2627 let host_test_helpers = builder.ensure(TestHelpers { target: test_compiler.host });
2628 let target_helpers = builder.ensure(TestHelpers { target });
2629 hostflags.push(format!("-Lnative={}", host_test_helpers.display()));
2630 targetflags.push(format!("-Lnative={}", target_helpers.display()));
2631 if target.is_pauthtest() {
2632 targetflags.push(format!("-Clink-arg=-Wl,-rpath,{}", target_helpers.display()));
2635 }
2636 }
2637
2638 for flag in hostflags {
2639 cmd.arg("--host-rustcflags").arg(flag);
2640 }
2641 for flag in targetflags {
2642 cmd.arg("--target-rustcflags").arg(flag);
2643 }
2644 if target.is_synthetic() {
2645 cmd.arg("--target-rustcflags").arg("-Zunstable-options");
2646 }
2647
2648 cmd.arg("--python").arg(
2649 builder.config.python.as_ref().expect("python is required for running rustdoc tests"),
2650 );
2651
2652 let android = android::discover_android(builder, target);
2654 if let Some(android::Android { adb_path, adb_test_dir, android_cross_path }) = &android {
2655 cmd.arg("--adb-path").arg(adb_path);
2656 cmd.arg("--adb-test-dir").arg(adb_test_dir);
2657 cmd.arg("--android-cross-path").arg(android_cross_path);
2658 }
2659
2660 if mode == CompiletestMode::Debuginfo {
2661 if let Some(debuggers::Cdb { cdb }) = debuggers::discover_cdb(target) {
2662 cmd.arg("--cdb").arg(cdb);
2663 }
2664
2665 if let Some(debuggers::Gdb { gdb }) = debuggers::discover_gdb(builder, android.as_ref())
2666 {
2667 cmd.arg("--gdb").arg(gdb);
2668 }
2669
2670 if let Some(debuggers::Lldb { lldb_exe, lldb_version }) =
2671 debuggers::discover_lldb(builder)
2672 {
2673 cmd.arg("--lldb").arg(lldb_exe);
2674 cmd.arg("--lldb-version").arg(lldb_version);
2675 }
2676 }
2677
2678 if helpers::forcing_clang_based_tests() {
2679 let llvm = builder.ensure(llvm::Llvm { target });
2680 let clang_exe = llvm.root_dir().join("bin").join("clang");
2681 cmd.arg("--run-clang-based-tests-with").arg(clang_exe);
2682 }
2683
2684 for exclude in &builder.config.skip {
2685 cmd.arg("--skip");
2686 cmd.arg(exclude);
2687 }
2688
2689 let mut paths = match &builder.config.cmd {
2691 Subcommand::Test { .. } => &builder.config.paths[..],
2692 _ => &[],
2693 };
2694
2695 let mut paths_v;
2698 if mode == CompiletestMode::RustdocJs {
2699 paths_v = paths.to_vec();
2700 for p in &mut paths_v {
2701 if let Some(ext) = p.extension()
2702 && ext == "js"
2703 {
2704 p.set_extension("rs");
2705 }
2706 }
2707 paths = &paths_v;
2708 }
2709
2710 let mut test_args = Vec::new();
2712 for p in paths {
2713 match helpers::is_valid_test_suite_arg(p, suite_path, builder) {
2714 TestFilterCategory::Fullsuite => {
2715 test_args.clear();
2720 break;
2721 }
2722 TestFilterCategory::Arg(a) => test_args.push(a),
2723 TestFilterCategory::Uninteresting => {}
2724 }
2725 }
2726
2727 test_args.append(&mut builder.config.test_args());
2728
2729 if cfg!(windows) {
2732 let test_args_win: Vec<String> =
2733 test_args.iter().map(|s| s.replace('/', "\\")).collect();
2734 cmd.args(&test_args_win);
2735 } else {
2736 cmd.args(&test_args);
2737 }
2738
2739 if builder.is_verbose() {
2740 cmd.arg("--verbose");
2741 }
2742
2743 if builder.config.cmd.verbose_run_make_subprocess_output() {
2744 cmd.arg("--verbose-run-make-subprocess-output");
2745 }
2746
2747 if builder.config.rustc_debug_assertions {
2748 cmd.arg("--with-rustc-debug-assertions");
2749 }
2750
2751 if builder.config.std_debug_assertions {
2752 cmd.arg("--with-std-debug-assertions");
2753 }
2754
2755 if builder.config.rust_remap_debuginfo {
2756 cmd.arg("--with-std-remap-debuginfo");
2757 }
2758
2759 cmd.arg("--jobs").arg(builder.jobs().to_string());
2760
2761 let mut llvm_components_passed = false;
2762 let mut copts_passed = false;
2763 if builder.config.llvm_enabled(test_compiler.host) {
2764 let llvm_output = builder.ensure(llvm::Llvm { target: builder.config.host_target });
2765 if !builder.config.dry_run() {
2766 let llvm_version = get_llvm_version(builder, llvm_output.llvm_config());
2767 let llvm_components = command(llvm_output.llvm_config())
2768 .cached()
2769 .arg("--components")
2770 .run_capture_stdout(builder)
2771 .stdout();
2772 cmd.arg("--llvm-version")
2774 .arg(llvm_version.trim())
2775 .arg("--llvm-components")
2776 .arg(llvm_components.trim());
2777 llvm_components_passed = true;
2778 }
2779 if !builder.config.is_rust_llvm(&llvm_output, target) {
2780 cmd.arg("--system-llvm");
2781 }
2782
2783 if !builder.config.dry_run() && suite.ends_with("fulldeps") {
2788 let llvm_libdir = command(llvm_output.llvm_config())
2789 .cached()
2790 .arg("--libdir")
2791 .run_capture_stdout(builder)
2792 .stdout();
2793 let link_llvm = if target.is_msvc() {
2794 format!("-Clink-arg=-LIBPATH:{llvm_libdir}")
2795 } else {
2796 format!("-Clink-arg=-L{llvm_libdir}")
2797 };
2798 cmd.arg("--host-rustcflags").arg(link_llvm);
2799 }
2800
2801 if !builder.config.dry_run()
2802 && matches!(mode, CompiletestMode::RunMake | CompiletestMode::CoverageRun)
2803 {
2804 let llvm_bin_path = llvm_output
2809 .llvm_config()
2810 .parent()
2811 .expect("Expected llvm-config to be contained in directory");
2812 assert!(llvm_bin_path.is_dir());
2813 cmd.arg("--llvm-bin-dir").arg(llvm_bin_path);
2814 }
2815
2816 if !builder.config.dry_run() && mode == CompiletestMode::RunMake {
2817 if builder.config.lld_enabled {
2819 let lld_install_root =
2820 builder.ensure(llvm::Lld { target: builder.config.host_target });
2821
2822 let lld_bin_path = lld_install_root.join("bin");
2823
2824 let old_path = env::var_os("PATH").unwrap_or_default();
2825 let new_path = env::join_paths(
2826 std::iter::once(lld_bin_path).chain(env::split_paths(&old_path)),
2827 )
2828 .expect("Could not add LLD bin path to PATH");
2829 cmd.env("PATH", new_path);
2830 }
2831 }
2832 }
2833
2834 if !builder.config.dry_run() && mode == CompiletestMode::RunMake {
2837 let mut cflags = builder.cc_handled_cflags(target, CLang::C);
2838 cflags.extend(builder.cc_unhandled_cflags(target, CLang::C));
2839 let mut cxxflags = builder.cc_handled_cflags(target, CLang::Cxx);
2840 cxxflags.extend(builder.cc_unhandled_cflags(target, CLang::Cxx));
2841 cmd.arg("--cc")
2842 .arg(builder.cc(target))
2843 .arg("--cxx")
2844 .arg(builder.cxx(target).unwrap())
2845 .arg("--cflags")
2846 .arg(cflags.join(" "))
2847 .arg("--cxxflags")
2848 .arg(cxxflags.join(" "));
2849 copts_passed = true;
2850 if let Some(ar) = builder.ar(target) {
2851 cmd.arg("--ar").arg(ar);
2852 }
2853 }
2854
2855 if !llvm_components_passed {
2856 cmd.arg("--llvm-components").arg("");
2857 }
2858 if !copts_passed {
2859 cmd.arg("--cc")
2860 .arg("")
2861 .arg("--cxx")
2862 .arg("")
2863 .arg("--cflags")
2864 .arg("")
2865 .arg("--cxxflags")
2866 .arg("");
2867 }
2868
2869 if builder.remote_tested(target) {
2870 cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient));
2871 } else if let Some(tool) = builder.runner(target) {
2872 cmd.arg("--runner").arg(tool);
2873 }
2874
2875 if suite != "mir-opt" {
2876 if !builder.config.dry_run() && target.is_msvc() {
2882 for (k, v) in builder.cc[&target].env() {
2883 if k != "PATH" {
2884 cmd.env(k, v);
2885 }
2886 }
2887 }
2888 }
2889
2890 if !builder.config.dry_run()
2892 && target.contains("msvc")
2893 && builder.config.sanitizers_enabled(target)
2894 {
2895 cmd.env("ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE", "1");
2898 let asan_runtime_path = builder.cc[&target].path().parent().unwrap().to_path_buf();
2900 let old_path = cmd
2901 .get_envs()
2902 .find_map(|(k, v)| (k == "PATH").then_some(v))
2903 .flatten()
2904 .map_or_else(|| env::var_os("PATH").unwrap_or_default(), |v| v.to_owned());
2905 let new_path = env::join_paths(
2906 env::split_paths(&old_path).chain(std::iter::once(asan_runtime_path)),
2907 )
2908 .expect("Could not add ASAN runtime path to PATH");
2909 cmd.env("PATH", new_path);
2910 }
2911
2912 cmd.env_remove("CARGO");
2915
2916 cmd.env("RUSTC_BOOTSTRAP", "1");
2917 cmd.env("RUSTC_FORCE_RUSTC_VERSION", "compiletest");
2920 cmd.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
2921 builder.add_rust_test_threads(&mut cmd);
2922
2923 if builder.config.sanitizers_enabled(target) {
2924 cmd.env("RUSTC_SANITIZER_SUPPORT", "1");
2925 }
2926
2927 if builder.config.profiler_enabled(target) {
2928 cmd.arg("--profiler-runtime");
2929 }
2930
2931 cmd.env("RUST_TEST_TMPDIR", builder.tempdir());
2932
2933 if builder.config.cmd.rustfix_coverage() {
2934 cmd.arg("--rustfix-coverage");
2935 }
2936
2937 cmd.arg("--channel").arg(&builder.config.channel);
2938
2939 if !builder.config.omit_git_hash {
2940 cmd.arg("--git-hash");
2941 }
2942
2943 let git_config = builder.config.git_config();
2944 cmd.arg("--nightly-branch").arg(git_config.nightly_branch);
2945 cmd.arg("--git-merge-commit-email").arg(git_config.git_merge_commit_email);
2946
2947 #[cfg(feature = "build-metrics")]
2948 builder.metrics.begin_test_suite(
2949 build_helper::metrics::TestSuiteMetadata::Compiletest {
2950 suite: suite.into(),
2951 mode: mode.to_string(),
2952 compare_mode: None,
2953 target: self.target.triple.to_string(),
2954 host: self.test_compiler.host.triple.to_string(),
2955 stage: self.test_compiler.stage,
2956 },
2957 builder,
2958 );
2959
2960 let _group = builder.msg_test(
2961 format!("with compiletest suite={suite} mode={mode}"),
2962 target,
2963 test_compiler.stage,
2964 );
2965 try_run_tests(builder, &mut cmd, false, record_failed_tests.clone());
2966
2967 if let Some(compare_mode) = compare_mode {
2968 cmd.arg("--compare-mode").arg(compare_mode);
2969
2970 #[cfg(feature = "build-metrics")]
2971 builder.metrics.begin_test_suite(
2972 build_helper::metrics::TestSuiteMetadata::Compiletest {
2973 suite: suite.into(),
2974 mode: mode.to_string(),
2975 compare_mode: Some(compare_mode.into()),
2976 target: self.target.triple.to_string(),
2977 host: self.test_compiler.host.triple.to_string(),
2978 stage: self.test_compiler.stage,
2979 },
2980 builder,
2981 );
2982
2983 builder.info(&format!(
2984 "Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
2985 suite, mode, compare_mode, test_compiler.host, target
2986 ));
2987 let _time = helpers::timeit(builder);
2988 try_run_tests(builder, &mut cmd, false, record_failed_tests);
2989 }
2990 }
2991
2992 fn metadata(&self) -> Option<StepMetadata> {
2993 Some(
2994 StepMetadata::test(&format!("compiletest-{}", self.suite), self.target)
2995 .stage(self.test_compiler.stage),
2996 )
2997 }
2998}
2999
3000#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3002struct BookTest {
3003 test_compiler: Compiler,
3004 path: PathBuf,
3005 name: &'static str,
3006 is_ext_doc: bool,
3007 dependencies: Vec<&'static str>,
3008}
3009
3010impl Step for BookTest {
3011 type Output = ();
3012
3013 fn run(self, builder: &Builder<'_>) {
3014 if self.is_ext_doc {
3024 self.run_ext_doc(builder);
3025 } else {
3026 self.run_local_doc(builder);
3027 }
3028 }
3029}
3030
3031impl BookTest {
3032 fn run_ext_doc(self, builder: &Builder<'_>) {
3035 let test_compiler = self.test_compiler;
3036
3037 builder.std(test_compiler, test_compiler.host);
3038
3039 let mut rustdoc_path = builder.rustdoc_for_compiler(test_compiler);
3042 rustdoc_path.pop();
3043 let old_path = env::var_os("PATH").unwrap_or_default();
3044 let new_path = env::join_paths(iter::once(rustdoc_path).chain(env::split_paths(&old_path)))
3045 .expect("could not add rustdoc to PATH");
3046
3047 let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
3048 let path = builder.src.join(&self.path);
3049 rustbook_cmd.env("RUSTC_BOOTSTRAP", "1");
3051 rustbook_cmd.env("PATH", new_path).arg("test").arg(path);
3052
3053 let libs = if !self.dependencies.is_empty() {
3058 let mut lib_paths = vec![];
3059 for dep in self.dependencies {
3060 let mode = Mode::ToolRustcPrivate;
3061 let target = builder.config.host_target;
3062 let cargo = tool::prepare_tool_cargo(
3063 builder,
3064 test_compiler,
3065 mode,
3066 target,
3067 Kind::Build,
3068 dep,
3069 SourceType::Submodule,
3070 &[],
3071 );
3072
3073 let stamp = BuildStamp::new(&builder.cargo_out(test_compiler, mode, target))
3074 .with_prefix(PathBuf::from(dep).file_name().and_then(|v| v.to_str()).unwrap());
3075
3076 let output_paths = run_cargo(
3077 builder,
3078 cargo,
3079 vec![],
3080 &stamp,
3081 vec![],
3082 ArtifactKeepMode::BothRlibAndRmeta,
3083 );
3084 let directories = output_paths
3085 .into_iter()
3086 .filter_map(|p| p.parent().map(ToOwned::to_owned))
3087 .fold(HashSet::new(), |mut set, dir| {
3088 set.insert(dir);
3089 set
3090 });
3091
3092 lib_paths.extend(directories);
3093 }
3094 lib_paths
3095 } else {
3096 vec![]
3097 };
3098
3099 if !libs.is_empty() {
3100 let paths = libs
3101 .into_iter()
3102 .map(|path| path.into_os_string())
3103 .collect::<Vec<OsString>>()
3104 .join(OsStr::new(","));
3105 rustbook_cmd.args([OsString::from("--library-path"), paths]);
3106 }
3107
3108 builder.add_rust_test_threads(&mut rustbook_cmd);
3109 let _guard = builder.msg_test(
3110 format_args!("mdbook {}", self.path.display()),
3111 test_compiler.host,
3112 test_compiler.stage,
3113 );
3114 let _time = helpers::timeit(builder);
3115 let toolstate = if rustbook_cmd.delay_failure().run(builder) {
3116 ToolState::TestPass
3117 } else {
3118 ToolState::TestFail
3119 };
3120 builder.save_toolstate(self.name, toolstate);
3121 }
3122
3123 fn run_local_doc(self, builder: &Builder<'_>) {
3125 let test_compiler = self.test_compiler;
3126 let host = self.test_compiler.host;
3127
3128 builder.std(test_compiler, host);
3129
3130 let _guard = builder.msg_test(
3131 format!("book {}", self.name),
3132 test_compiler.host,
3133 test_compiler.stage,
3134 );
3135
3136 let mut stack = vec![builder.src.join(self.path)];
3139 let _time = helpers::timeit(builder);
3140 let mut files = Vec::new();
3141 while let Some(p) = stack.pop() {
3142 if p.is_dir() {
3143 stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
3144 continue;
3145 }
3146
3147 if p.extension().and_then(|s| s.to_str()) != Some("md") {
3148 continue;
3149 }
3150
3151 files.push(p);
3152 }
3153
3154 files.sort();
3155
3156 for file in files {
3157 markdown_test(builder, test_compiler, &file);
3158 }
3159 }
3160}
3161
3162macro_rules! test_book {
3163 ($(
3164 $name:ident, $path:expr, $book_name:expr,
3165 default=$default:expr
3166 $(,submodules = $submodules:expr)?
3167 $(,dependencies=$dependencies:expr)?
3168 ;
3169 )+) => {
3170 $(
3171 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
3172 pub struct $name {
3173 test_compiler: Compiler,
3174 }
3175
3176 impl CommandLineStep for $name {
3177 type Output = ();
3178 const IS_HOST: bool = true;
3179
3180 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3181 run.path($path)
3182 }
3183
3184 fn is_default_step(_builder: &Builder<'_>) -> bool {
3185 const { $default }
3186 }
3187
3188 fn make_run(run: RunConfig<'_>) {
3189 run.builder.ensure($name {
3190 test_compiler: run.builder.compiler(run.builder.top_stage, run.target),
3191 });
3192 }
3193
3194 fn run(self, builder: &Builder<'_>) {
3195 $(
3196 for submodule in $submodules {
3197 builder.require_submodule(submodule, None);
3198 }
3199 )*
3200
3201 let dependencies = vec![];
3202 $(
3203 let mut dependencies = dependencies;
3204 for dep in $dependencies {
3205 dependencies.push(dep);
3206 }
3207 )?
3208
3209 builder.ensure(BookTest {
3210 test_compiler: self.test_compiler,
3211 path: PathBuf::from($path),
3212 name: $book_name,
3213 is_ext_doc: !$default,
3214 dependencies,
3215 });
3216 }
3217 }
3218 )+
3219 }
3220}
3221
3222test_book!(
3223 Nomicon, "src/doc/nomicon", "nomicon", default=false, submodules=["src/doc/nomicon"];
3224 Reference, "src/doc/reference", "reference", default=false, submodules=["src/doc/reference"];
3225 RustdocBook, "src/doc/rustdoc", "rustdoc", default=true;
3226 RustcBook, "src/doc/rustc", "rustc", default=true;
3227 RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false, submodules=["src/doc/rust-by-example"];
3228 EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false, submodules=["src/doc/embedded-book"];
3229 TheBook, "src/doc/book", "book", default=false, submodules=["src/doc/book"], dependencies=["src/doc/book/packages/trpl"];
3230 UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
3231 EditionGuide, "src/doc/edition-guide", "edition-guide", default=false, submodules=["src/doc/edition-guide"];
3232);
3233
3234#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3235pub struct ErrorIndex {
3236 compilers: RustcPrivateCompilers,
3237}
3238
3239impl CommandLineStep for ErrorIndex {
3240 type Output = ();
3241 const IS_HOST: bool = true;
3242
3243 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3244 run.path("src/tools/error_index_generator").alias("error-index")
3247 }
3248
3249 fn is_default_step(_builder: &Builder<'_>) -> bool {
3250 true
3251 }
3252
3253 fn make_run(run: RunConfig<'_>) {
3254 let compilers = RustcPrivateCompilers::new(
3258 run.builder,
3259 run.builder.top_stage,
3260 run.builder.config.host_target,
3261 );
3262 run.builder.ensure(ErrorIndex { compilers });
3263 }
3264
3265 fn run(self, builder: &Builder<'_>) {
3272 let target_compiler = self.compilers.target_compiler();
3274
3275 let dir = testdir(builder, target_compiler.host);
3276 t!(fs::create_dir_all(&dir));
3277 let output = dir.join("error-index.md");
3278
3279 let mut tool = tool::ErrorIndex::command(builder, self.compilers);
3280 tool.arg("markdown").arg(&output);
3281
3282 let guard = builder.msg_test("error-index", target_compiler.host, target_compiler.stage);
3283 let _time = helpers::timeit(builder);
3284 tool.run_capture(builder);
3285 drop(guard);
3286 builder.std(target_compiler, target_compiler.host);
3289 markdown_test(builder, target_compiler, &output);
3290 }
3291}
3292
3293fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool {
3294 if let Ok(contents) = fs::read_to_string(markdown)
3295 && !contents.contains("```")
3296 {
3297 return true;
3298 }
3299
3300 builder.do_if_verbose(|| println!("doc tests for: {}", markdown.display()));
3301 let mut cmd = builder.rustdoc_cmd(compiler);
3302 builder.add_rust_test_threads(&mut cmd);
3303 cmd.arg("-Znext-solver=coherence");
3306 cmd.arg("-Z");
3308 cmd.arg("unstable-options");
3309 cmd.arg("--test");
3310 cmd.arg(markdown);
3311 cmd.env("RUSTC_BOOTSTRAP", "1");
3312
3313 let test_args = builder.config.test_args().join(" ");
3314 cmd.arg("--test-args").arg(test_args);
3315
3316 cmd = cmd.delay_failure();
3317 if !builder.config.verbose_tests {
3318 cmd.run_capture(builder).is_success()
3319 } else {
3320 cmd.run(builder)
3321 }
3322}
3323
3324#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3329pub struct CrateLibrustc {
3330 build_compiler: Compiler,
3332 target: TargetSelection,
3333 crates: Vec<String>,
3334}
3335
3336impl CommandLineStep for CrateLibrustc {
3337 type Output = ();
3338 const IS_HOST: bool = true;
3339
3340 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3341 run.crate_or_deps("rustc-main").path("compiler")
3342 }
3343
3344 fn is_default_step(_builder: &Builder<'_>) -> bool {
3345 true
3346 }
3347
3348 fn make_run(run: RunConfig<'_>) {
3349 let builder = run.builder;
3350 let host = run.build_triple();
3351 let build_compiler = builder.compiler(builder.top_stage - 1, host);
3352 let crates = run.make_run_crates(Alias::Compiler);
3353
3354 builder.ensure(CrateLibrustc { build_compiler, target: run.target, crates });
3355 }
3356
3357 fn run(self, builder: &Builder<'_>) {
3358 builder.std(self.build_compiler, self.target);
3359
3360 builder.ensure(Crate {
3362 build_compiler: self.build_compiler,
3363 target: self.target,
3364 mode: Mode::Rustc,
3365 crates: self.crates,
3366 });
3367 }
3368
3369 fn metadata(&self) -> Option<StepMetadata> {
3370 Some(StepMetadata::test("CrateLibrustc", self.target).built_by(self.build_compiler))
3371 }
3372}
3373
3374fn run_cargo_test<'a>(
3378 mut cargo: builder::Cargo,
3379 libtest_args: &[&str],
3380 crates: &[String],
3381 description: impl Into<Option<&'a str>>,
3382 target: TargetSelection,
3383 builder: &Builder<'_>,
3384 record_failed_tests: RecordFailedTests,
3385) -> bool {
3386 let compiler = cargo.compiler();
3387 let stage = match cargo.mode() {
3388 Mode::Std => compiler.stage,
3389 _ => compiler.stage + 1,
3390 };
3391
3392 cargo.rustdocflag("-Znext-solver=coherence");
3395
3396 let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, target, builder);
3397 let _time = helpers::timeit(builder);
3398
3399 let _group = description.into().and_then(|what| builder.msg_test(what, target, stage));
3400
3401 #[cfg(feature = "build-metrics")]
3402 builder.metrics.begin_test_suite(
3403 build_helper::metrics::TestSuiteMetadata::CargoPackage {
3404 crates: crates.iter().map(|c| c.to_string()).collect(),
3405 target: target.triple.to_string(),
3406 host: compiler.host.triple.to_string(),
3407 stage: compiler.stage,
3408 },
3409 builder,
3410 );
3411 add_flags_and_try_run_tests(builder, &mut cargo, record_failed_tests)
3412}
3413
3414fn prepare_cargo_test(
3416 cargo: builder::Cargo,
3417 libtest_args: &[&str],
3418 crates: &[String],
3419 target: TargetSelection,
3420 builder: &Builder<'_>,
3421) -> BootstrapCommand {
3422 let compiler = cargo.compiler();
3423 let mut cargo: BootstrapCommand = cargo.into();
3424
3425 if builder.config.cmd.bless() && !cargo.get_envs().any(|v| v.0 == "RUSTC_BLESS") {
3429 cargo.env("RUSTC_BLESS", "Gesundheit");
3430 }
3431
3432 if builder.kind == Kind::Test && !builder.fail_fast {
3436 cargo.arg("--no-fail-fast");
3437 }
3438
3439 if builder.config.json_output {
3440 cargo.arg("--message-format=json");
3441 }
3442
3443 match builder.test_target {
3444 TestTarget::AllTargets => cargo.args(["--bins", "--examples", "--tests", "--benches"]),
3445 TestTarget::Default => &mut cargo,
3446 TestTarget::DocOnly => cargo.arg("--doc"),
3447 TestTarget::Tests => cargo.arg("--tests"),
3448 };
3449
3450 for krate in crates {
3451 cargo.arg("-p").arg(krate);
3452 }
3453
3454 cargo.arg("--").args(builder.config.test_args()).args(libtest_args);
3455 if !builder.config.verbose_tests {
3456 cargo.arg("--quiet");
3457 }
3458
3459 if builder.kind != Kind::Miri {
3468 let mut dylib_paths = builder.rustc_lib_paths(compiler);
3469 dylib_paths.push(builder.sysroot_target_libdir(compiler, target));
3470 helpers::add_dylib_path(dylib_paths, &mut cargo);
3471 }
3472
3473 if builder.remote_tested(target) {
3474 cargo.env(
3475 format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
3476 format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
3477 );
3478 } else if let Some(tool) = builder.runner(target) {
3479 cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), tool);
3480 }
3481
3482 cargo
3483}
3484
3485#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3493pub struct Crate {
3494 build_compiler: Compiler,
3496 target: TargetSelection,
3497 mode: Mode,
3498 crates: Vec<String>,
3499}
3500
3501impl CommandLineStep for Crate {
3502 type Output = ();
3503
3504 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3505 run.crate_or_deps("sysroot").crate_or_deps("coretests").crate_or_deps("alloctests")
3506 }
3507
3508 fn is_default_step(_builder: &Builder<'_>) -> bool {
3509 true
3510 }
3511
3512 fn make_run(run: RunConfig<'_>) {
3513 let builder = run.builder;
3514 let host = run.build_triple();
3515 let build_compiler = builder.compiler(builder.top_stage, host);
3516 let crates = run
3517 .paths
3518 .iter()
3519 .map(|p| builder.crate_paths[&p.assert_single_path().path].clone())
3520 .collect();
3521
3522 builder.ensure(Crate { build_compiler, target: run.target, mode: Mode::Std, crates });
3523 }
3524
3525 fn run(self, builder: &Builder<'_>) {
3534 let build_compiler = self.build_compiler;
3535 let target = self.target;
3536 let mode = self.mode;
3537
3538 builder.ensure(Std::new(build_compiler, build_compiler.host).force_recompile(true));
3541 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
3542
3543 let mut cargo = if builder.kind == Kind::Miri {
3544 if builder.top_stage == 0 {
3545 eprintln!("ERROR: `x.py miri` requires stage 1 or higher");
3546 std::process::exit(1);
3547 }
3548
3549 let mut cargo = builder::Cargo::new(
3552 builder,
3553 build_compiler,
3554 mode,
3555 SourceType::InTree,
3556 target,
3557 Kind::MiriTest,
3558 );
3559 cargo.env("MIRI_REPLACE_LIBRS_IF_NOT_TEST", "1");
3571 cargo.rustflag("-Zforce-unstable-if-unmarked");
3575 cargo.env(
3580 "MIRIFLAGS",
3581 format!(
3582 "{} -Zmiri-env-forward=RUSTC_BOOTSTRAP",
3583 env::var("MIRIFLAGS").unwrap_or_default()
3584 ),
3585 );
3586 cargo
3587 } else {
3588 if !builder.config.is_host_target(target) {
3590 builder.ensure(compile::Std::new(build_compiler, target).force_recompile(true));
3591 builder.ensure(RemoteCopyLibs { build_compiler, target });
3592 }
3593
3594 builder::Cargo::new(
3596 builder,
3597 build_compiler,
3598 mode,
3599 SourceType::InTree,
3600 target,
3601 builder.kind,
3602 )
3603 };
3604
3605 match mode {
3606 Mode::Std => {
3607 if builder.kind == Kind::Miri {
3608 cargo
3614 .arg("--manifest-path")
3615 .arg(builder.src.join("library/sysroot/Cargo.toml"));
3616 } else {
3617 compile::std_cargo(builder, target, &mut cargo, &[]);
3618 }
3619 }
3620 Mode::Rustc => {
3621 compile::rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
3622 }
3623 _ => panic!("can only test libraries"),
3624 };
3625
3626 let mut crates = self.crates.clone();
3627 if crates.iter().any(|crate_| crate_ == "core") {
3632 crates.push("coretests".to_owned());
3633 }
3634 if crates.iter().any(|crate_| crate_ == "alloc") {
3635 crates.push("alloctests".to_owned());
3636 };
3637 let description = crate_description(&self.crates);
3638 run_cargo_test(cargo, &[], &crates, &*description, target, builder, record_failed_tests);
3639 }
3640}
3641
3642#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3645pub struct CrateRustdoc {
3646 host: TargetSelection,
3647}
3648
3649impl CommandLineStep for CrateRustdoc {
3650 type Output = ();
3651 const IS_HOST: bool = true;
3652
3653 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3654 run.multi_path(&["src/librustdoc", "src/tools/rustdoc"])
3655 }
3656
3657 fn is_default_step(_builder: &Builder<'_>) -> bool {
3658 true
3659 }
3660
3661 fn make_run(run: RunConfig<'_>) {
3662 let builder = run.builder;
3663
3664 builder.ensure(CrateRustdoc { host: run.target });
3665 }
3666
3667 fn run(self, builder: &Builder<'_>) {
3668 let target = self.host;
3669 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
3670
3671 let compiler = if builder.download_rustc() {
3672 builder.compiler(builder.top_stage, target)
3673 } else {
3674 builder.compiler_for(builder.top_stage, target, target)
3679 };
3680 builder.std(compiler, target);
3685 builder.ensure(compile::Rustc::new(compiler, target));
3686
3687 let mut cargo = tool::prepare_tool_cargo(
3688 builder,
3689 compiler,
3690 Mode::ToolRustcPrivate,
3691 target,
3692 builder.kind,
3693 "src/tools/rustdoc",
3694 SourceType::InTree,
3695 &[],
3696 );
3697 if self.host.contains("musl") {
3698 cargo.arg("'-Ctarget-feature=-crt-static'");
3699 }
3700
3701 let libdir = if builder.download_rustc() {
3728 builder.rustc_libdir(compiler)
3729 } else {
3730 builder.sysroot_target_libdir(compiler, target).to_path_buf()
3731 };
3732 let mut dylib_path = dylib_path();
3733 dylib_path.insert(0, PathBuf::from(&*libdir));
3734 cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
3735
3736 run_cargo_test(
3737 cargo,
3738 &[],
3739 &["rustdoc:0.0.0".to_string()],
3740 "rustdoc",
3741 target,
3742 builder,
3743 record_failed_tests,
3744 );
3745 }
3746}
3747
3748#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3749pub struct CrateRustdocJsonTypes {
3750 build_compiler: Compiler,
3751 target: TargetSelection,
3752}
3753
3754impl CommandLineStep for CrateRustdocJsonTypes {
3755 type Output = ();
3756 const IS_HOST: bool = true;
3757
3758 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3759 run.path("src/rustdoc-json-types")
3760 }
3761
3762 fn is_default_step(_builder: &Builder<'_>) -> bool {
3763 true
3764 }
3765
3766 fn make_run(run: RunConfig<'_>) {
3767 let builder = run.builder;
3768
3769 builder.ensure(CrateRustdocJsonTypes {
3770 build_compiler: get_tool_target_compiler(
3771 builder,
3772 ToolTargetBuildMode::Build(run.target),
3773 ),
3774 target: run.target,
3775 });
3776 }
3777
3778 fn run(self, builder: &Builder<'_>) {
3779 let target = self.target;
3780 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
3781
3782 let cargo = tool::prepare_tool_cargo(
3783 builder,
3784 self.build_compiler,
3785 Mode::ToolTarget,
3786 target,
3787 builder.kind,
3788 "src/rustdoc-json-types",
3789 SourceType::InTree,
3790 &["rkyv_0_8".to_owned()],
3791 );
3792
3793 let libtest_args = if target.contains("musl") {
3795 ["'-Ctarget-feature=-crt-static'"].as_slice()
3796 } else {
3797 &[]
3798 };
3799
3800 run_cargo_test(
3801 cargo,
3802 libtest_args,
3803 &["rustdoc-json-types".to_string()],
3804 "rustdoc-json-types",
3805 target,
3806 builder,
3807 record_failed_tests,
3808 );
3809 }
3810}
3811
3812#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3822pub struct RemoteCopyLibs {
3823 build_compiler: Compiler,
3824 target: TargetSelection,
3825}
3826
3827impl Step for RemoteCopyLibs {
3828 type Output = ();
3829
3830 fn run(self, builder: &Builder<'_>) {
3831 let build_compiler = self.build_compiler;
3832 let target = self.target;
3833 if !builder.remote_tested(target) {
3834 return;
3835 }
3836
3837 builder.std(build_compiler, target);
3838
3839 builder.info(&format!("REMOTE copy libs to emulator ({target})"));
3840
3841 let remote_test_server = builder.ensure(tool::RemoteTestServer { build_compiler, target });
3842
3843 let tool = builder.tool_exe(Tool::RemoteTestClient);
3845 let mut cmd = command(&tool);
3846 cmd.arg("spawn-emulator")
3847 .arg(target.triple)
3848 .arg(&remote_test_server.tool_path)
3849 .arg(builder.tempdir());
3850 if let Some(rootfs) = builder.qemu_rootfs(target) {
3851 cmd.arg(rootfs);
3852 }
3853 cmd.run(builder);
3854
3855 for f in t!(builder.sysroot_target_libdir(build_compiler, target).read_dir()) {
3857 let f = t!(f);
3858 if helpers::is_dylib(&f.path()) {
3859 command(&tool).arg("push").arg(f.path()).run(builder);
3860 }
3861 }
3862 }
3863}
3864
3865#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3866pub struct Distcheck;
3867
3868impl CommandLineStep for Distcheck {
3869 type Output = ();
3870
3871 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3872 run.alias("distcheck")
3873 }
3874
3875 fn make_run(run: RunConfig<'_>) {
3876 run.builder.ensure(Distcheck);
3877 }
3878
3879 fn run(self, builder: &Builder<'_>) {
3889 let root_dir = std::env::temp_dir().join("distcheck");
3892
3893 distcheck_plain_source_tarball(builder, &root_dir.join("distcheck-rustc-src"));
3894 distcheck_rust_src(builder, &root_dir.join("distcheck-rust-src"));
3895 distcheck_rustc_dev(builder, &root_dir.join("distcheck-rustc-dev"));
3896 }
3897}
3898
3899fn distcheck_plain_source_tarball(builder: &Builder<'_>, plain_src_dir: &Path) {
3901 builder.info("Distcheck plain source tarball");
3902 let plain_src_tarball = builder.ensure(dist::PlainSourceTarball);
3903 builder.clear_dir(plain_src_dir);
3904
3905 let configure_args: Vec<String> = std::env::var("DISTCHECK_CONFIGURE_ARGS")
3906 .map(|args| args.split(" ").map(|s| s.to_string()).collect::<Vec<String>>())
3907 .unwrap_or_default();
3908
3909 command("tar")
3910 .arg("-xf")
3911 .arg(plain_src_tarball.tarball())
3912 .arg("--strip-components=1")
3913 .current_dir(plain_src_dir)
3914 .run(builder);
3915 command("./configure")
3916 .arg("--set")
3917 .arg("rust.omit-git-hash=false")
3918 .arg("--set")
3919 .arg("rust.remap-debuginfo=false")
3920 .args(&configure_args)
3921 .arg("--enable-vendor")
3922 .current_dir(plain_src_dir)
3923 .run(builder);
3924 command(helpers::make(&builder.config.host_target.triple))
3925 .arg("check")
3926 .env("GITHUB_ACTIONS", "0")
3929 .current_dir(plain_src_dir)
3930 .run(builder);
3931 builder.remove_dir(plain_src_dir);
3933}
3934
3935fn distcheck_rust_src(builder: &Builder<'_>, src_dir: &Path) {
3937 builder.info("Distcheck rust-src");
3938 let src_tarball = builder.ensure(dist::Src);
3939 builder.clear_dir(src_dir);
3940
3941 command("tar")
3942 .arg("-xf")
3943 .arg(src_tarball.tarball())
3944 .arg("--strip-components=1")
3945 .current_dir(src_dir)
3946 .run(builder);
3947
3948 let toml = src_dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml");
3949 command(&builder.initial_cargo)
3950 .env("RUSTC_BOOTSTRAP", "1")
3953 .arg("generate-lockfile")
3954 .arg("--manifest-path")
3955 .arg(&toml)
3956 .current_dir(src_dir)
3957 .run(builder);
3958 builder.remove_dir(src_dir);
3960}
3961
3962fn distcheck_rustc_dev(builder: &Builder<'_>, dir: &Path) {
3964 builder.info("Distcheck rustc-dev");
3965 let tarball = builder.ensure(dist::RustcDev::new(builder, builder.host_target)).unwrap();
3966 builder.clear_dir(dir);
3967
3968 command("tar")
3969 .arg("-xf")
3970 .arg(tarball.tarball())
3971 .arg("--strip-components=1")
3972 .current_dir(dir)
3973 .run(builder);
3974
3975 command(&builder.initial_cargo)
3976 .arg("metadata")
3977 .arg("--manifest-path")
3978 .arg("rustc-dev/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml")
3979 .env("RUSTC_BOOTSTRAP", "1")
3980 .env("RUSTC", &builder.initial_rustc)
3982 .current_dir(dir)
3983 .run(builder);
3984 builder.remove_dir(dir);
3986}
3987
3988#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3990pub(crate) struct BootstrapPy;
3991
3992impl CommandLineStep for BootstrapPy {
3993 type Output = ();
3994 const IS_HOST: bool = true;
3995
3996 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3997 run.alias("bootstrap-py")
3998 }
3999
4000 fn is_default_step(builder: &Builder<'_>) -> bool {
4001 builder.config.is_running_on_ci()
4005 }
4006
4007 fn make_run(run: RunConfig<'_>) {
4008 run.builder.ensure(BootstrapPy)
4009 }
4010
4011 fn run(self, builder: &Builder<'_>) -> Self::Output {
4012 let mut check_bootstrap = command(
4013 builder.config.python.as_ref().expect("python is required for running bootstrap tests"),
4014 );
4015 check_bootstrap
4016 .args(["-m", "unittest", "bootstrap_test.py"])
4017 .args(builder.config.test_args())
4019 .env("BUILD_DIR", &builder.out)
4020 .env("BUILD_PLATFORM", builder.sess.host_target.triple)
4021 .env("BOOTSTRAP_TEST_RUSTC_BIN", &builder.initial_rustc)
4022 .env("BOOTSTRAP_TEST_CARGO_BIN", &builder.initial_cargo)
4023 .current_dir(builder.src.join("src/bootstrap/"));
4024 check_bootstrap.delay_failure().run(builder);
4025 }
4026}
4027
4028#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4029pub struct Bootstrap;
4030
4031impl CommandLineStep for Bootstrap {
4032 type Output = ();
4033 const IS_HOST: bool = true;
4034
4035 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4036 run.path("src/bootstrap")
4037 }
4038
4039 fn is_default_step(builder: &Builder<'_>) -> bool {
4040 builder.config.is_running_on_ci()
4044 }
4045
4046 fn run(self, builder: &Builder<'_>) {
4048 let host = builder.config.host_target;
4049 let build_compiler = builder.compiler(0, host);
4050 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
4051
4052 builder.sess.require_submodule("src/tools/cargo", None);
4054
4055 let mut cargo = tool::prepare_tool_cargo(
4056 builder,
4057 build_compiler,
4058 Mode::ToolBootstrap,
4059 host,
4060 Kind::Test,
4061 "src/bootstrap",
4062 SourceType::InTree,
4063 &[],
4064 );
4065
4066 cargo.release_build(false);
4067
4068 cargo
4069 .rustflag("-Cdebuginfo=2")
4070 .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
4071 .env("INSTA_WORKSPACE_ROOT", &builder.src)
4073 .env("RUSTC_BOOTSTRAP", "1");
4074
4075 if builder.config.cmd.bless() {
4076 cargo.env("INSTA_UPDATE", "always");
4080 }
4081
4082 run_cargo_test(cargo, &[], &[], None, host, builder, record_failed_tests);
4083 }
4084
4085 fn make_run(run: RunConfig<'_>) {
4086 run.builder.ensure(Bootstrap);
4087 }
4088}
4089
4090fn get_compiler_to_test(builder: &Builder<'_>, target: TargetSelection) -> Compiler {
4091 builder.compiler(builder.top_stage, target)
4092}
4093
4094#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4097pub struct TierCheck {
4098 test_compiler: Compiler,
4099}
4100
4101impl CommandLineStep for TierCheck {
4102 type Output = ();
4103 const IS_HOST: bool = true;
4104
4105 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4106 run.path("src/tools/tier-check")
4107 }
4108
4109 fn is_default_step(_builder: &Builder<'_>) -> bool {
4110 true
4111 }
4112
4113 fn make_run(run: RunConfig<'_>) {
4114 run.builder
4115 .ensure(TierCheck { test_compiler: get_compiler_to_test(run.builder, run.target) });
4116 }
4117
4118 fn run(self, builder: &Builder<'_>) {
4119 let tool_build_compiler = builder.compiler(0, builder.host_target);
4120
4121 let mut cargo = tool::prepare_tool_cargo(
4122 builder,
4123 tool_build_compiler,
4124 Mode::ToolBootstrap,
4125 tool_build_compiler.host,
4126 Kind::Run,
4127 "src/tools/tier-check",
4128 SourceType::InTree,
4129 &[],
4130 );
4131 cargo.arg(builder.src.join("src/doc/rustc/src/platform-support.md"));
4132 cargo.arg(builder.rustc(self.test_compiler));
4133
4134 let _guard = builder.msg_test(
4135 "platform support check",
4136 self.test_compiler.host,
4137 self.test_compiler.stage,
4138 );
4139 BootstrapCommand::from(cargo).delay_failure().run(builder);
4140 }
4141
4142 fn metadata(&self) -> Option<StepMetadata> {
4143 Some(StepMetadata::test("tier-check", self.test_compiler.host))
4144 }
4145}
4146
4147#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4148pub struct LintDocs {
4149 build_compiler: Compiler,
4150 target: TargetSelection,
4151}
4152
4153impl CommandLineStep for LintDocs {
4154 type Output = ();
4155 const IS_HOST: bool = true;
4156
4157 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4158 run.path("src/tools/lint-docs")
4159 }
4160
4161 fn is_default_step(builder: &Builder<'_>) -> bool {
4162 builder.top_stage >= 2
4165 }
4166
4167 fn make_run(run: RunConfig<'_>) {
4168 if run.builder.top_stage < 2 {
4169 eprintln!("WARNING: lint-docs tests might not work below stage 2");
4170 }
4171
4172 run.builder.ensure(LintDocs {
4173 build_compiler: prepare_doc_compiler(
4174 run.builder,
4175 run.builder.config.host_target,
4176 run.builder.top_stage,
4177 ),
4178 target: run.target,
4179 });
4180 }
4181
4182 fn run(self, builder: &Builder<'_>) {
4185 builder.ensure(crate::core::build_steps::doc::RustcBook::validate(
4186 self.build_compiler,
4187 self.target,
4188 ));
4189 }
4190
4191 fn metadata(&self) -> Option<StepMetadata> {
4192 Some(StepMetadata::test("lint-docs", self.target).built_by(self.build_compiler))
4193 }
4194}
4195
4196#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4197pub struct RustInstaller;
4198
4199impl CommandLineStep for RustInstaller {
4200 type Output = ();
4201 const IS_HOST: bool = true;
4202
4203 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4204 run.path("src/tools/rust-installer")
4205 }
4206
4207 fn is_default_step(_builder: &Builder<'_>) -> bool {
4208 true
4209 }
4210
4211 fn make_run(run: RunConfig<'_>) {
4212 run.builder.ensure(Self);
4213 }
4214
4215 fn run(self, builder: &Builder<'_>) {
4217 let bootstrap_host = builder.config.host_target;
4218 let build_compiler = builder.compiler(0, bootstrap_host);
4219 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
4220 let cargo = tool::prepare_tool_cargo(
4221 builder,
4222 build_compiler,
4223 Mode::ToolBootstrap,
4224 bootstrap_host,
4225 Kind::Test,
4226 "src/tools/rust-installer",
4227 SourceType::InTree,
4228 &[],
4229 );
4230
4231 let _guard = builder.msg_test("rust-installer", bootstrap_host, 1);
4232 run_cargo_test(cargo, &[], &[], None, bootstrap_host, builder, record_failed_tests);
4233
4234 if bootstrap_host != "x86_64-unknown-linux-gnu" {
4238 return;
4239 }
4240
4241 let mut cmd = command(builder.src.join("src/tools/rust-installer/test.sh"));
4242 let tmpdir = testdir(builder, build_compiler.host).join("rust-installer");
4243 let _ = std::fs::remove_dir_all(&tmpdir);
4244 let _ = std::fs::create_dir_all(&tmpdir);
4245 cmd.current_dir(&tmpdir);
4246 cmd.env("CARGO_TARGET_DIR", tmpdir.join("cargo-target"));
4247 cmd.env("CARGO", &builder.initial_cargo);
4248 cmd.env("RUSTC", &builder.initial_rustc);
4249 cmd.env("TMP_DIR", &tmpdir);
4250 cmd.delay_failure().run(builder);
4251 }
4252}
4253
4254#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4258pub struct TestHelpers {
4259 pub target: TargetSelection,
4260}
4261
4262impl CommandLineStep for TestHelpers {
4263 type Output = PathBuf;
4264
4265 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4266 run.path("tests/auxiliary/rust_test_helpers.c")
4267 }
4268
4269 fn make_run(run: RunConfig<'_>) {
4270 run.builder.ensure(TestHelpers { target: run.target });
4271 }
4272
4273 fn run(self, builder: &Builder<'_>) -> Self::Output {
4276 let target = if self.target == "x86_64-fortanix-unknown-sgx" {
4280 TargetSelection::from_user("x86_64-unknown-linux-gnu")
4281 } else {
4282 self.target
4283 };
4284 let dst = builder.native_dir(target).join("rust-test-helpers");
4285 if builder.config.dry_run() {
4286 return dst;
4287 }
4288
4289 let src = builder.src.join("tests/auxiliary/rust_test_helpers.c");
4290 let _guard = builder.msg_unstaged(Kind::Build, "test helpers", target);
4291 t!(fs::create_dir_all(&dst));
4292
4293 if !up_to_date(&src, &dst.join("librust_test_helpers.a")) {
4294 let mut cfg = cc::Build::new();
4295
4296 if !target.is_msvc() {
4300 if let Some(ar) = builder.ar(target) {
4301 cfg.archiver(ar);
4302 }
4303 cfg.compiler(builder.cc(target));
4304 }
4305 cfg.cargo_metadata(false)
4306 .out_dir(&dst)
4307 .target(&target.triple)
4308 .host(&builder.config.host_target.triple)
4309 .opt_level(0)
4310 .warnings(false)
4311 .debug(false)
4312 .file(builder.src.join("tests/auxiliary/rust_test_helpers.c"))
4313 .compile("rust_test_helpers");
4314 }
4315 if target.is_pauthtest() {
4316 let so = dst.join("librust_test_helpers.so");
4317 if up_to_date(&src, &so) {
4318 return dst;
4319 }
4320
4321 let status = Command::new(builder.cc(target))
4322 .arg("-target")
4323 .arg(target.triple)
4324 .arg("-march=armv8.3-a+pauth")
4325 .arg("-fPIC")
4326 .arg("-shared")
4327 .arg("-O0") .arg("-o")
4329 .arg(&so)
4330 .arg(&src)
4331 .status()
4332 .unwrap_or_else(|_| panic!("Failed to run clang for {} toolchain", target.triple));
4333
4334 if !status.success() {
4335 panic!("Linking of librust_test_helpers.so failed (target: {})", target.triple);
4336 }
4337 }
4338 dst
4339 }
4340}
4341
4342#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4343pub struct CodegenCranelift {
4344 compilers: RustcPrivateCompilers,
4345 target: TargetSelection,
4346}
4347
4348impl CommandLineStep for CodegenCranelift {
4349 type Output = ();
4350 const IS_HOST: bool = true;
4351
4352 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4353 run.path("compiler/rustc_codegen_cranelift")
4354 }
4355
4356 fn is_default_step(_builder: &Builder<'_>) -> bool {
4357 true
4358 }
4359
4360 fn make_run(run: RunConfig<'_>) {
4361 let builder = run.builder;
4362 let host = run.build_triple();
4363 let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, host);
4364
4365 if builder.test_target == TestTarget::DocOnly {
4366 return;
4367 }
4368
4369 if builder.download_rustc() {
4370 builder.info("CI rustc uses the default codegen backend. skipping");
4371 return;
4372 }
4373
4374 if !target_supports_cranelift_backend(run.target) {
4375 builder.info("target not supported by rustc_codegen_cranelift. skipping");
4376 return;
4377 }
4378
4379 if builder.remote_tested(run.target) {
4380 builder.info("remote testing is not supported by rustc_codegen_cranelift. skipping");
4381 return;
4382 }
4383
4384 if !builder
4385 .config
4386 .enabled_codegen_backends(run.target)
4387 .contains(&CodegenBackendKind::Cranelift)
4388 {
4389 builder.info("cranelift not in rust.codegen-backends. skipping");
4390 return;
4391 }
4392
4393 builder.ensure(CodegenCranelift { compilers, target: run.target });
4394 }
4395
4396 fn run(self, builder: &Builder<'_>) {
4397 let compilers = self.compilers;
4398 let build_compiler = compilers.build_compiler();
4399
4400 let target_compiler = compilers.target_compiler();
4403 let target = self.target;
4404
4405 builder.std(target_compiler, target);
4406
4407 let mut cargo = builder::Cargo::new(
4408 builder,
4409 target_compiler,
4410 Mode::Codegen, SourceType::InTree,
4412 target,
4413 Kind::Run,
4414 );
4415
4416 cargo.current_dir(&builder.src.join("compiler/rustc_codegen_cranelift"));
4417 cargo
4418 .arg("--manifest-path")
4419 .arg(builder.src.join("compiler/rustc_codegen_cranelift/build_system/Cargo.toml"));
4420
4421 cargo.env("CARGO_BUILD_INCREMENTAL", "false");
4423
4424 let _guard = builder.msg_test(
4425 "rustc_codegen_cranelift",
4426 target_compiler.host,
4427 target_compiler.stage,
4428 );
4429
4430 let download_dir = builder.out.join("cg_clif_download");
4432
4433 cargo
4434 .arg("--")
4435 .arg("test")
4436 .arg("--download-dir")
4437 .arg(&download_dir)
4438 .arg("--out-dir")
4439 .arg(builder.stage_out(build_compiler, Mode::Codegen).join("cg_clif"))
4440 .arg("--no-unstable-features")
4441 .arg("--use-backend")
4442 .arg("cranelift")
4443 .arg("--sysroot")
4445 .arg("llvm")
4446 .arg("--skip-test")
4449 .arg("testsuite.extended_sysroot");
4450
4451 cargo.into_cmd().run(builder);
4452 }
4453
4454 fn metadata(&self) -> Option<StepMetadata> {
4455 Some(
4456 StepMetadata::test("rustc_codegen_cranelift", self.target)
4457 .built_by(self.compilers.build_compiler()),
4458 )
4459 }
4460}
4461
4462#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4463pub struct CodegenGCC {
4464 compilers: RustcPrivateCompilers,
4465 target: TargetSelection,
4466}
4467
4468impl CommandLineStep for CodegenGCC {
4469 type Output = ();
4470 const IS_HOST: bool = true;
4471
4472 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4473 run.path("compiler/rustc_codegen_gcc")
4474 }
4475
4476 fn is_default_step(_builder: &Builder<'_>) -> bool {
4477 true
4478 }
4479
4480 fn make_run(run: RunConfig<'_>) {
4481 let builder = run.builder;
4482 let host = run.build_triple();
4483 let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, host);
4484
4485 if builder.test_target == TestTarget::DocOnly {
4486 return;
4487 }
4488
4489 if builder.download_rustc() {
4490 builder.info("CI rustc uses the default codegen backend. skipping");
4491 return;
4492 }
4493
4494 let triple = run.target.triple;
4495 let target_supported =
4496 if triple.contains("linux") { triple.contains("x86_64") } else { false };
4497 if !target_supported {
4498 builder.info("target not supported by rustc_codegen_gcc. skipping");
4499 return;
4500 }
4501
4502 if builder.remote_tested(run.target) {
4503 builder.info("remote testing is not supported by rustc_codegen_gcc. skipping");
4504 return;
4505 }
4506
4507 if !builder.config.enabled_codegen_backends(run.target).contains(&CodegenBackendKind::Gcc) {
4508 builder.info("gcc not in rust.codegen-backends. skipping");
4509 return;
4510 }
4511
4512 builder.ensure(CodegenGCC { compilers, target: run.target });
4513 }
4514
4515 fn run(self, builder: &Builder<'_>) {
4516 let compilers = self.compilers;
4517 let target = self.target;
4518
4519 let gcc = builder.ensure(Gcc { target_pair: GccTargetPair::for_native_build(target) });
4520
4521 builder.ensure(
4522 compile::Std::new(compilers.build_compiler(), target)
4523 .extra_rust_args(&["-Csymbol-mangling-version=v0", "-Cpanic=abort"]),
4524 );
4525
4526 let _guard = builder.msg_test(
4527 "rustc_codegen_gcc",
4528 compilers.target(),
4529 compilers.target_compiler().stage,
4530 );
4531
4532 let mut cargo = builder::Cargo::new(
4533 builder,
4534 compilers.build_compiler(),
4535 Mode::Codegen, SourceType::InTree,
4537 target,
4538 Kind::Run,
4539 );
4540
4541 cargo.current_dir(&builder.src.join("compiler/rustc_codegen_gcc"));
4542 cargo
4543 .arg("--manifest-path")
4544 .arg(builder.src.join("compiler/rustc_codegen_gcc/build_system/Cargo.toml"));
4545 add_cg_gcc_cargo_flags(&mut cargo, &gcc);
4546
4547 cargo.env("CARGO_BUILD_INCREMENTAL", "false");
4549 cargo.rustflag("-Cpanic=abort");
4550
4551 cargo
4552 .env("CG_RUSTFLAGS", "-Alinker-messages")
4554 .arg("--")
4555 .arg("test")
4556 .arg("--use-backend")
4557 .arg("gcc")
4558 .arg("--gcc-path")
4559 .arg(gcc.libgccjit().parent().unwrap())
4560 .arg("--out-dir")
4561 .arg(builder.stage_out(compilers.build_compiler(), Mode::Codegen).join("cg_gcc"))
4562 .arg("--release")
4563 .arg("--mini-tests")
4564 .arg("--std-tests");
4565
4566 cargo.args(builder.config.test_args());
4567
4568 cargo.into_cmd().run(builder);
4569 }
4570
4571 fn metadata(&self) -> Option<StepMetadata> {
4572 Some(
4573 StepMetadata::test("rustc_codegen_gcc", self.target)
4574 .built_by(self.compilers.build_compiler()),
4575 )
4576 }
4577}
4578
4579#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4584pub struct TestFloatParse {
4585 build_compiler: Compiler,
4594 target: TargetSelection,
4596}
4597
4598impl CommandLineStep for TestFloatParse {
4599 type Output = ();
4600 const IS_HOST: bool = true;
4601
4602 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4603 run.path("src/tools/test-float-parse")
4604 }
4605
4606 fn is_default_step(_builder: &Builder<'_>) -> bool {
4607 true
4608 }
4609
4610 fn make_run(run: RunConfig<'_>) {
4611 run.builder.ensure(Self {
4612 build_compiler: get_compiler_to_test(run.builder, run.target),
4613 target: run.target,
4614 });
4615 }
4616
4617 fn run(self, builder: &Builder<'_>) {
4618 let build_compiler = self.build_compiler;
4619 let target = self.target;
4620
4621 builder.std(build_compiler, target);
4623 builder.std(build_compiler, builder.host_target);
4624 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
4625
4626 let mut cargo_test = tool::prepare_tool_cargo(
4628 builder,
4629 build_compiler,
4630 Mode::ToolStd,
4631 target,
4632 Kind::Test,
4633 "src/tools/test-float-parse",
4634 SourceType::InTree,
4635 &[],
4636 );
4637 cargo_test.allow_features(TEST_FLOAT_PARSE_ALLOW_FEATURES);
4638
4639 run_cargo_test(
4640 cargo_test,
4641 &[],
4642 &[],
4643 "test-float-parse",
4644 target,
4645 builder,
4646 record_failed_tests,
4647 );
4648
4649 let mut cargo_run = tool::prepare_tool_cargo(
4651 builder,
4652 build_compiler,
4653 Mode::ToolStd,
4654 target,
4655 Kind::Run,
4656 "src/tools/test-float-parse",
4657 SourceType::InTree,
4658 &[],
4659 );
4660 cargo_run.allow_features(TEST_FLOAT_PARSE_ALLOW_FEATURES);
4661
4662 if !matches!(env::var("FLOAT_PARSE_TESTS_NO_SKIP_HUGE").as_deref(), Ok("1") | Ok("true")) {
4663 cargo_run.args(["--", "--skip-huge"]);
4664 }
4665
4666 cargo_run.into_cmd().run(builder);
4667 }
4668}
4669
4670#[derive(Debug, Clone, Hash, PartialEq, Eq)]
4674pub struct CollectLicenseMetadata;
4675
4676impl CommandLineStep for CollectLicenseMetadata {
4677 type Output = PathBuf;
4678 const IS_HOST: bool = true;
4679
4680 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4681 run.path("src/tools/collect-license-metadata")
4682 }
4683
4684 fn make_run(run: RunConfig<'_>) {
4685 run.builder.ensure(CollectLicenseMetadata);
4686 }
4687
4688 fn run(self, builder: &Builder<'_>) -> Self::Output {
4689 let Some(reuse) = &builder.config.reuse else {
4690 panic!("REUSE is required to collect the license metadata");
4691 };
4692
4693 let dest = builder.src.join("license-metadata.json");
4694
4695 let mut cmd = builder.tool_cmd(Tool::CollectLicenseMetadata);
4696 cmd.env("REUSE_EXE", reuse);
4697 cmd.env("DEST", &dest);
4698 cmd.env("ONLY_CHECK", "1");
4699 cmd.run(builder);
4700
4701 dest
4702 }
4703}
4704
4705#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4706pub struct RemoteTestClientTests {
4707 host: TargetSelection,
4708}
4709
4710impl CommandLineStep for RemoteTestClientTests {
4711 type Output = ();
4712 const IS_HOST: bool = true;
4713
4714 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4715 run.path("src/tools/remote-test-client")
4716 }
4717
4718 fn is_default_step(_builder: &Builder<'_>) -> bool {
4719 true
4720 }
4721
4722 fn make_run(run: RunConfig<'_>) {
4723 run.builder.ensure(Self { host: run.target });
4724 }
4725
4726 fn run(self, builder: &Builder<'_>) {
4727 let bootstrap_host = builder.config.host_target;
4728 let compiler = builder.compiler(0, bootstrap_host);
4729 let record_failed_tests = builder.ensure(SetupFailedTestsFile);
4730
4731 let cargo = tool::prepare_tool_cargo(
4732 builder,
4733 compiler,
4734 Mode::ToolBootstrap,
4735 bootstrap_host,
4736 Kind::Test,
4737 "src/tools/remote-test-client",
4738 SourceType::InTree,
4739 &[],
4740 );
4741
4742 run_cargo_test(
4743 cargo,
4744 &[],
4745 &[],
4746 "remote-test-client",
4747 bootstrap_host,
4748 builder,
4749 record_failed_tests,
4750 );
4751 }
4752}
4753
4754fn check_if_cargo_semver_checks_is_installed(builder: &Builder<'_>) -> bool {
4755 command(&builder.initial_cargo)
4756 .allow_failure()
4757 .arg("semver-checks")
4758 .arg("--version")
4759 .cached()
4761 .run_capture_stdout(builder)
4762 .is_success()
4763}
4764
4765#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4776pub struct StdSemverCheck {
4777 build_compiler: Compiler,
4778 target: TargetSelection,
4779 commit: String,
4781}
4782
4783impl CommandLineStep for StdSemverCheck {
4784 type Output = ();
4785
4786 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4787 run.alias("std-semver-check")
4788 }
4789
4790 fn make_run(run: RunConfig<'_>) {
4791 if !check_if_cargo_semver_checks_is_installed(run.builder) {
4792 panic!("cargo-semver-checks was not found, please install it");
4793 }
4794
4795 let baseline_commit =
4796 run.builder.config.stdlib_semver_baseline.clone().unwrap_or_else(|| {
4797 match get_closest_upstream_commit(
4798 Some(&run.builder.config.src),
4799 &run.builder.config.git_config(),
4800 run.builder.config.ci_env,
4801 ) {
4802 Ok(Some(commit)) => commit,
4803 Ok(None) => {
4804 panic!("No baseline parent commit found for std-semver-check");
4805 }
4806 Err(error) => {
4807 panic!("Cannot get baseline parent commit for std-semver-check: {error:?}");
4808 }
4809 }
4810 });
4811
4812 run.builder.ensure(Self {
4813 build_compiler: run.builder.compiler_for_std(run.builder.top_stage),
4814 target: run.target,
4815 commit: baseline_commit,
4816 });
4817 }
4818
4819 fn run(self, builder: &Builder<'_>) {
4820 const STDLIB_SEMVER_CHECK_STAMP_PATH: &str = "src/bootstrap/stdlib-semver-check-stamp";
4821
4822 if builder.config.ci_env.is_running_in_ci()
4823 && builder.config.has_changes_from_upstream(&[STDLIB_SEMVER_CHECK_STAMP_PATH])
4824 {
4825 builder.info(&format!("Skipping stdlib semver check, because {STDLIB_SEMVER_CHECK_STAMP_PATH} was modified."));
4826 return;
4827 }
4828
4829 let Some(docs_dir) = builder.config.download_std_json_docs(self.target, &self.commit)
4830 else {
4831 return;
4832 };
4833
4834 let directory = builder.ensure(crate::core::build_steps::doc::Std::from_build_compiler(
4835 self.build_compiler,
4836 self.target,
4837 DocumentationFormat::Json,
4838 ));
4839 let baseline_dir = docs_dir.join("share").join("doc").join("rust").join("json");
4840
4841 for library in ["core", "alloc", "std"] {
4842 println!("Checking semver compatibility of {library}");
4843 let mut cmd = command(&builder.initial_cargo);
4844 cmd.arg("semver-checks")
4845 .arg("-Z")
4846 .arg("unstable-options")
4847 .arg("--stability-aware")
4848 .arg("--release-type")
4849 .arg("minor")
4850 .arg("--current-rustdoc")
4851 .arg(directory.join(format!("{library}.json")))
4852 .arg("--baseline-rustdoc")
4853 .arg(baseline_dir.join(format!("{library}.json")));
4854
4855 let res = cmd.allow_failure().run_capture(builder);
4857 match res.status() {
4858 Some(status) if status.success() => {
4859 println!("{}\n{}", res.stdout(), res.stderr());
4860 }
4861 Some(status) if status.code() == Some(101) => {
4864 eprintln!(
4865 "cargo-semver-checks was unable to process {library} (this is not a fatal error)\n{}\n{}",
4866 res.stderr(),
4867 res.stdout()
4868 );
4869 }
4870 Some(status) if status.code() == Some(100) => {
4872 let error = format!(
4873 "cargo-semver-checks found semver breakage in {library}\n{}\n{}",
4874 res.stderr(),
4875 res.stdout()
4876 );
4877 if builder.fail_fast {
4878 eprintln!("{error}",);
4879 helpers::exit_process(1);
4880 } else {
4881 builder.config.exec_ctx().add_to_delay_failure(error);
4882 }
4883 }
4884 _ => {
4885 eprintln!("cargo-semver-checks failed.\n{}\n{}", res.stderr(), res.stdout());
4886 helpers::exit_process(1);
4887 }
4888 }
4889 }
4890 }
4891}