1use std::collections::HashSet;
7use std::env::split_paths;
8use std::ffi::{OsStr, OsString};
9use std::path::{Path, PathBuf};
10use std::{env, fs, iter};
11
12use build_helper::exit;
13
14use crate::core::build_steps::compile::{Std, run_cargo};
15use crate::core::build_steps::doc::{DocumentationFormat, prepare_doc_compiler};
16use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags};
17use crate::core::build_steps::llvm::get_llvm_version;
18use crate::core::build_steps::run::{get_completion_paths, get_help_path};
19use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
20use crate::core::build_steps::tool::{
21 self, RustcPrivateCompilers, SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, Tool,
22 ToolTargetBuildMode, get_tool_target_compiler,
23};
24use crate::core::build_steps::toolstate::ToolState;
25use crate::core::build_steps::{compile, dist, llvm};
26use crate::core::builder::{
27 self, Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step, StepMetadata,
28 crate_description,
29};
30use crate::core::config::TargetSelection;
31use crate::core::config::flags::{Subcommand, get_completion, top_level_help};
32use crate::core::debuggers;
33use crate::utils::build_stamp::{self, BuildStamp};
34use crate::utils::exec::{BootstrapCommand, command};
35use crate::utils::helpers::{
36 self, LldThreads, add_dylib_path, add_rustdoc_cargo_linker_args, dylib_path, dylib_path_var,
37 linker_args, linker_flags, t, target_supports_cranelift_backend, up_to_date,
38};
39use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests};
40use crate::{CLang, CodegenBackendKind, DocTests, GitRepo, Mode, PathSet, envify};
41
42#[derive(Debug, Clone, PartialEq, Eq, Hash)]
44pub struct CrateBootstrap {
45 path: PathBuf,
46 host: TargetSelection,
47}
48
49impl Step for CrateBootstrap {
50 type Output = ();
51 const IS_HOST: bool = true;
52 const DEFAULT: bool = true;
53
54 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
55 run.path("src/tools/jsondoclint")
60 .path("src/tools/replace-version-placeholder")
61 .path("src/tools/coverage-dump")
62 .alias("tidyselftest")
65 }
66
67 fn make_run(run: RunConfig<'_>) {
68 for path in run.paths {
71 let path = path.assert_single_path().path.clone();
72 run.builder.ensure(CrateBootstrap { host: run.target, path });
73 }
74 }
75
76 fn run(self, builder: &Builder<'_>) {
77 let bootstrap_host = builder.config.host_target;
78 let compiler = builder.compiler(0, bootstrap_host);
79 let mut path = self.path.to_str().unwrap();
80
81 if path == "tidyselftest" {
83 path = "src/tools/tidy";
84 }
85
86 let cargo = tool::prepare_tool_cargo(
87 builder,
88 compiler,
89 Mode::ToolBootstrap,
90 bootstrap_host,
91 Kind::Test,
92 path,
93 SourceType::InTree,
94 &[],
95 );
96
97 let crate_name = path.rsplit_once('/').unwrap().1;
98 run_cargo_test(cargo, &[], &[], crate_name, bootstrap_host, builder);
99 }
100
101 fn metadata(&self) -> Option<StepMetadata> {
102 Some(
103 StepMetadata::test("crate-bootstrap", self.host)
104 .with_metadata(self.path.as_path().to_string_lossy().to_string()),
105 )
106 }
107}
108
109#[derive(Debug, Clone, PartialEq, Eq, Hash)]
110pub struct Linkcheck {
111 host: TargetSelection,
112}
113
114impl Step for Linkcheck {
115 type Output = ();
116 const IS_HOST: bool = true;
117 const DEFAULT: bool = true;
118
119 fn run(self, builder: &Builder<'_>) {
124 let host = self.host;
125 let hosts = &builder.hosts;
126 let targets = &builder.targets;
127
128 if (hosts != targets) && !hosts.is_empty() && !targets.is_empty() {
133 panic!(
134 "Linkcheck currently does not support builds with different hosts and targets.
135You can skip linkcheck with --skip src/tools/linkchecker"
136 );
137 }
138
139 builder.info(&format!("Linkcheck ({host})"));
140
141 let bootstrap_host = builder.config.host_target;
143 let compiler = builder.compiler(0, bootstrap_host);
144
145 let cargo = tool::prepare_tool_cargo(
146 builder,
147 compiler,
148 Mode::ToolBootstrap,
149 bootstrap_host,
150 Kind::Test,
151 "src/tools/linkchecker",
152 SourceType::InTree,
153 &[],
154 );
155 run_cargo_test(cargo, &[], &[], "linkchecker self tests", bootstrap_host, builder);
156
157 if builder.doc_tests == DocTests::No {
158 return;
159 }
160
161 builder.run_default_doc_steps();
163
164 let linkchecker = builder.tool_cmd(Tool::Linkchecker);
166
167 let _guard = builder.msg_test("Linkcheck", bootstrap_host, 1);
169 let _time = helpers::timeit(builder);
170 linkchecker.delay_failure().arg(builder.out.join(host).join("doc")).run(builder);
171 }
172
173 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
174 let builder = run.builder;
175 let run = run.path("src/tools/linkchecker");
176 run.default_condition(builder.config.docs)
177 }
178
179 fn make_run(run: RunConfig<'_>) {
180 run.builder.ensure(Linkcheck { host: run.target });
181 }
182
183 fn metadata(&self) -> Option<StepMetadata> {
184 Some(StepMetadata::test("link-check", self.host))
185 }
186}
187
188fn check_if_tidy_is_installed(builder: &Builder<'_>) -> bool {
189 command("tidy").allow_failure().arg("--version").run_capture_stdout(builder).is_success()
190}
191
192#[derive(Debug, Clone, PartialEq, Eq, Hash)]
193pub struct HtmlCheck {
194 target: TargetSelection,
195}
196
197impl Step for HtmlCheck {
198 type Output = ();
199 const DEFAULT: bool = true;
200 const IS_HOST: bool = true;
201
202 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
203 let builder = run.builder;
204 let run = run.path("src/tools/html-checker");
205 run.lazy_default_condition(Box::new(|| check_if_tidy_is_installed(builder)))
206 }
207
208 fn make_run(run: RunConfig<'_>) {
209 run.builder.ensure(HtmlCheck { target: run.target });
210 }
211
212 fn run(self, builder: &Builder<'_>) {
213 if !check_if_tidy_is_installed(builder) {
214 eprintln!("not running HTML-check tool because `tidy` is missing");
215 eprintln!(
216 "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."
217 );
218 panic!("Cannot run html-check tests");
219 }
220 builder.run_default_doc_steps();
222 builder.ensure(crate::core::build_steps::doc::Rustc::for_stage(
223 builder,
224 builder.top_stage,
225 self.target,
226 ));
227
228 builder
229 .tool_cmd(Tool::HtmlChecker)
230 .delay_failure()
231 .arg(builder.doc_out(self.target))
232 .run(builder);
233 }
234
235 fn metadata(&self) -> Option<StepMetadata> {
236 Some(StepMetadata::test("html-check", self.target))
237 }
238}
239
240#[derive(Debug, Clone, PartialEq, Eq, Hash)]
244pub struct Cargotest {
245 build_compiler: Compiler,
246 host: TargetSelection,
247}
248
249impl Step for Cargotest {
250 type Output = ();
251 const IS_HOST: bool = true;
252
253 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
254 run.path("src/tools/cargotest")
255 }
256
257 fn make_run(run: RunConfig<'_>) {
258 if run.builder.top_stage == 0 {
259 eprintln!(
260 "ERROR: running cargotest with stage 0 is currently unsupported. Use at least stage 1."
261 );
262 exit!(1);
263 }
264 run.builder.ensure(Cargotest {
268 build_compiler: run.builder.compiler(run.builder.top_stage - 1, run.target),
269 host: run.target,
270 });
271 }
272
273 fn run(self, builder: &Builder<'_>) {
278 let cargo =
288 builder.ensure(tool::Cargo::from_build_compiler(self.build_compiler, self.host));
289 let tested_compiler = builder.compiler(self.build_compiler.stage + 1, self.host);
290 builder.std(tested_compiler, self.host);
291
292 let out_dir = builder.out.join("ct");
296 t!(fs::create_dir_all(&out_dir));
297
298 let _time = helpers::timeit(builder);
299 let mut cmd = builder.tool_cmd(Tool::CargoTest);
300 cmd.arg(&cargo.tool_path)
301 .arg(&out_dir)
302 .args(builder.config.test_args())
303 .env("RUSTC", builder.rustc(tested_compiler))
304 .env("RUSTDOC", builder.rustdoc_for_compiler(tested_compiler));
305 add_rustdoc_cargo_linker_args(&mut cmd, builder, tested_compiler.host, LldThreads::No);
306 cmd.delay_failure().run(builder);
307 }
308
309 fn metadata(&self) -> Option<StepMetadata> {
310 Some(StepMetadata::test("cargotest", self.host).stage(self.build_compiler.stage + 1))
311 }
312}
313
314#[derive(Debug, Clone, PartialEq, Eq, Hash)]
317pub struct Cargo {
318 build_compiler: Compiler,
319 host: TargetSelection,
320}
321
322impl Cargo {
323 const CRATE_PATH: &str = "src/tools/cargo";
324}
325
326impl Step for Cargo {
327 type Output = ();
328 const IS_HOST: bool = true;
329
330 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
331 run.path(Self::CRATE_PATH)
332 }
333
334 fn make_run(run: RunConfig<'_>) {
335 run.builder.ensure(Cargo {
336 build_compiler: get_tool_target_compiler(
337 run.builder,
338 ToolTargetBuildMode::Build(run.target),
339 ),
340 host: run.target,
341 });
342 }
343
344 fn run(self, builder: &Builder<'_>) {
346 builder.ensure(tool::Cargo::from_build_compiler(self.build_compiler, self.host));
350
351 let tested_compiler = builder.compiler(self.build_compiler.stage + 1, self.host);
352 builder.std(tested_compiler, self.host);
353 builder.rustdoc_for_compiler(tested_compiler);
357
358 let cargo = tool::prepare_tool_cargo(
359 builder,
360 self.build_compiler,
361 Mode::ToolTarget,
362 self.host,
363 Kind::Test,
364 Self::CRATE_PATH,
365 SourceType::Submodule,
366 &[],
367 );
368
369 let mut cargo = prepare_cargo_test(cargo, &[], &[], self.host, builder);
371
372 cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
375 cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1");
378
379 cargo.env("PATH", bin_path_for_cargo(builder, tested_compiler));
383
384 let mut existing_dylib_paths = cargo
389 .get_envs()
390 .find(|(k, _)| *k == OsStr::new(dylib_path_var()))
391 .and_then(|(_, v)| v)
392 .map(|value| split_paths(value).collect::<Vec<PathBuf>>())
393 .unwrap_or_default();
394 existing_dylib_paths.insert(0, builder.rustc_libdir(tested_compiler));
395 add_dylib_path(existing_dylib_paths, &mut cargo);
396
397 cargo.env("CARGO_RUSTC_CURRENT_DIR", builder.src.display().to_string());
401
402 #[cfg(feature = "build-metrics")]
403 builder.metrics.begin_test_suite(
404 build_helper::metrics::TestSuiteMetadata::CargoPackage {
405 crates: vec!["cargo".into()],
406 target: self.host.triple.to_string(),
407 host: self.host.triple.to_string(),
408 stage: self.build_compiler.stage + 1,
409 },
410 builder,
411 );
412
413 let _time = helpers::timeit(builder);
414 add_flags_and_try_run_tests(builder, &mut cargo);
415 }
416
417 fn metadata(&self) -> Option<StepMetadata> {
418 Some(StepMetadata::test("cargo", self.host).built_by(self.build_compiler))
419 }
420}
421
422#[derive(Debug, Clone, PartialEq, Eq, Hash)]
423pub struct RustAnalyzer {
424 compilers: RustcPrivateCompilers,
425}
426
427impl Step for RustAnalyzer {
428 type Output = ();
429 const IS_HOST: bool = true;
430 const DEFAULT: bool = true;
431
432 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
433 run.path("src/tools/rust-analyzer")
434 }
435
436 fn make_run(run: RunConfig<'_>) {
437 run.builder.ensure(Self {
438 compilers: RustcPrivateCompilers::new(
439 run.builder,
440 run.builder.top_stage,
441 run.builder.host_target,
442 ),
443 });
444 }
445
446 fn run(self, builder: &Builder<'_>) {
448 let host = self.compilers.target();
449
450 let workspace_path = "src/tools/rust-analyzer";
451 let crate_path = "src/tools/rust-analyzer/crates/proc-macro-srv";
454 let mut cargo = tool::prepare_tool_cargo(
455 builder,
456 self.compilers.build_compiler(),
457 Mode::ToolRustcPrivate,
458 host,
459 Kind::Test,
460 crate_path,
461 SourceType::InTree,
462 &["in-rust-tree".to_owned()],
463 );
464 cargo.allow_features(tool::RustAnalyzer::ALLOW_FEATURES);
465
466 let dir = builder.src.join(workspace_path);
467 cargo.env("CARGO_WORKSPACE_DIR", &dir);
470
471 cargo.env("SKIP_SLOW_TESTS", "1");
474
475 cargo.add_rustc_lib_path(builder);
476 run_cargo_test(cargo, &[], &[], "rust-analyzer", host, builder);
477 }
478
479 fn metadata(&self) -> Option<StepMetadata> {
480 Some(
481 StepMetadata::test("rust-analyzer", self.compilers.target())
482 .built_by(self.compilers.build_compiler()),
483 )
484 }
485}
486
487#[derive(Debug, Clone, PartialEq, Eq, Hash)]
489pub struct Rustfmt {
490 compilers: RustcPrivateCompilers,
491}
492
493impl Step for Rustfmt {
494 type Output = ();
495 const IS_HOST: bool = true;
496
497 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
498 run.path("src/tools/rustfmt")
499 }
500
501 fn make_run(run: RunConfig<'_>) {
502 run.builder.ensure(Rustfmt {
503 compilers: RustcPrivateCompilers::new(
504 run.builder,
505 run.builder.top_stage,
506 run.builder.host_target,
507 ),
508 });
509 }
510
511 fn run(self, builder: &Builder<'_>) {
513 let tool_result = builder.ensure(tool::Rustfmt::from_compilers(self.compilers));
514 let build_compiler = tool_result.build_compiler;
515 let target = self.compilers.target();
516
517 let mut cargo = tool::prepare_tool_cargo(
518 builder,
519 build_compiler,
520 Mode::ToolRustcPrivate,
521 target,
522 Kind::Test,
523 "src/tools/rustfmt",
524 SourceType::InTree,
525 &[],
526 );
527
528 let dir = testdir(builder, target);
529 t!(fs::create_dir_all(&dir));
530 cargo.env("RUSTFMT_TEST_DIR", dir);
531
532 cargo.add_rustc_lib_path(builder);
533
534 run_cargo_test(cargo, &[], &[], "rustfmt", target, builder);
535 }
536
537 fn metadata(&self) -> Option<StepMetadata> {
538 Some(
539 StepMetadata::test("rustfmt", self.compilers.target())
540 .built_by(self.compilers.build_compiler()),
541 )
542 }
543}
544
545#[derive(Debug, Clone, PartialEq, Eq, Hash)]
546pub struct Miri {
547 target: TargetSelection,
548}
549
550impl Miri {
551 pub fn build_miri_sysroot(
553 builder: &Builder<'_>,
554 compiler: Compiler,
555 target: TargetSelection,
556 ) -> PathBuf {
557 let miri_sysroot = builder.out.join(compiler.host).join("miri-sysroot");
558 let mut cargo = builder::Cargo::new(
559 builder,
560 compiler,
561 Mode::Std,
562 SourceType::Submodule,
563 target,
564 Kind::MiriSetup,
565 );
566
567 cargo.env("MIRI_LIB_SRC", builder.src.join("library"));
569 cargo.env("MIRI_SYSROOT", &miri_sysroot);
571
572 let mut cargo = BootstrapCommand::from(cargo);
573 let _guard =
574 builder.msg(Kind::Build, "miri sysroot", Mode::ToolRustcPrivate, compiler, target);
575 cargo.run(builder);
576
577 cargo.arg("--print-sysroot");
583
584 builder.do_if_verbose(|| println!("running: {cargo:?}"));
585 let stdout = cargo.run_capture_stdout(builder).stdout();
586 let sysroot = stdout.trim_end();
588 builder.do_if_verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
589 PathBuf::from(sysroot)
590 }
591}
592
593impl Step for Miri {
594 type Output = ();
595
596 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
597 run.path("src/tools/miri")
598 }
599
600 fn make_run(run: RunConfig<'_>) {
601 run.builder.ensure(Miri { target: run.target });
602 }
603
604 fn run(self, builder: &Builder<'_>) {
606 let host = builder.build.host_target;
607 let target = self.target;
608 let stage = builder.top_stage;
609 if stage == 0 {
610 eprintln!("miri cannot be tested at stage 0");
611 std::process::exit(1);
612 }
613
614 let compilers = RustcPrivateCompilers::new(builder, stage, host);
616
617 let miri = builder.ensure(tool::Miri::from_compilers(compilers));
619 builder.ensure(tool::CargoMiri::from_compilers(compilers));
621
622 let target_compiler = compilers.target_compiler();
623
624 let miri_sysroot = Miri::build_miri_sysroot(builder, target_compiler, target);
627 builder.std(target_compiler, host);
628 let host_sysroot = builder.sysroot(target_compiler);
629
630 if !builder.config.dry_run() {
633 let ui_test_dep_dir = builder
636 .stage_out(miri.build_compiler, Mode::ToolStd)
637 .join(host)
638 .join("tmp")
639 .join("miri_ui");
640 build_stamp::clear_if_dirty(builder, &ui_test_dep_dir, &miri_sysroot);
644 }
645
646 let mut cargo = tool::prepare_tool_cargo(
649 builder,
650 miri.build_compiler,
651 Mode::ToolRustcPrivate,
652 host,
653 Kind::Test,
654 "src/tools/miri",
655 SourceType::InTree,
656 &[],
657 );
658
659 cargo.add_rustc_lib_path(builder);
660
661 let mut cargo = prepare_cargo_test(cargo, &[], &[], host, builder);
664
665 cargo.env("MIRI_SYSROOT", &miri_sysroot);
667 cargo.env("MIRI_HOST_SYSROOT", &host_sysroot);
668 cargo.env("MIRI", &miri.tool_path);
669
670 cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg());
672
673 {
674 let _guard = builder.msg_test("miri", target, target_compiler.stage);
675 let _time = helpers::timeit(builder);
676 cargo.run(builder);
677 }
678
679 if builder.config.test_args().is_empty() {
681 cargo.env("MIRIFLAGS", "-O -Zmir-opt-level=4 -Cdebug-assertions=yes");
682 cargo.env("MIRI_SKIP_UI_CHECKS", "1");
684 cargo.env_remove("RUSTC_BLESS");
686 cargo.args(["tests/pass", "tests/panic"]);
688
689 {
690 let _guard =
691 builder.msg_test("miri (mir-opt-level 4)", target, target_compiler.stage);
692 let _time = helpers::timeit(builder);
693 cargo.run(builder);
694 }
695 }
696 }
697}
698
699#[derive(Debug, Clone, PartialEq, Eq, Hash)]
702pub struct CargoMiri {
703 target: TargetSelection,
704}
705
706impl Step for CargoMiri {
707 type Output = ();
708
709 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
710 run.path("src/tools/miri/cargo-miri")
711 }
712
713 fn make_run(run: RunConfig<'_>) {
714 run.builder.ensure(CargoMiri { target: run.target });
715 }
716
717 fn run(self, builder: &Builder<'_>) {
719 let host = builder.build.host_target;
720 let target = self.target;
721 let stage = builder.top_stage;
722 if stage == 0 {
723 eprintln!("cargo-miri cannot be tested at stage 0");
724 std::process::exit(1);
725 }
726
727 let build_compiler = builder.compiler(stage, host);
729
730 let mut cargo = tool::prepare_tool_cargo(
735 builder,
736 build_compiler,
737 Mode::ToolStd, target,
739 Kind::MiriTest,
740 "src/tools/miri/test-cargo-miri",
741 SourceType::Submodule,
742 &[],
743 );
744
745 match builder.doc_tests {
748 DocTests::Yes => {}
749 DocTests::No => {
750 cargo.args(["--lib", "--bins", "--examples", "--tests", "--benches"]);
751 }
752 DocTests::Only => {
753 cargo.arg("--doc");
754 }
755 }
756 cargo.arg("--").args(builder.config.test_args());
757
758 let mut cargo = BootstrapCommand::from(cargo);
760 {
761 let _guard = builder.msg_test("cargo-miri", target, stage);
762 let _time = helpers::timeit(builder);
763 cargo.run(builder);
764 }
765 }
766}
767
768#[derive(Debug, Clone, PartialEq, Eq, Hash)]
769pub struct CompiletestTest {
770 host: TargetSelection,
771}
772
773impl Step for CompiletestTest {
774 type Output = ();
775
776 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
777 run.path("src/tools/compiletest")
778 }
779
780 fn make_run(run: RunConfig<'_>) {
781 run.builder.ensure(CompiletestTest { host: run.target });
782 }
783
784 fn run(self, builder: &Builder<'_>) {
786 let host = self.host;
787
788 if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 {
794 eprintln!("\
795ERROR: `--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
796NOTE: 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`."
797 );
798 crate::exit!(1);
799 }
800
801 let bootstrap_compiler = builder.compiler(0, host);
802 let staged_compiler = builder.compiler(builder.top_stage, host);
803
804 let mut cargo = tool::prepare_tool_cargo(
805 builder,
806 bootstrap_compiler,
807 Mode::ToolBootstrap,
808 host,
809 Kind::Test,
810 "src/tools/compiletest",
811 SourceType::InTree,
812 &[],
813 );
814
815 cargo.env("TEST_RUSTC", builder.rustc(staged_compiler));
819
820 run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder);
821 }
822}
823
824#[derive(Debug, Clone, PartialEq, Eq, Hash)]
825pub struct Clippy {
826 compilers: RustcPrivateCompilers,
827}
828
829impl Step for Clippy {
830 type Output = ();
831 const IS_HOST: bool = true;
832 const DEFAULT: bool = false;
833
834 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
835 run.suite_path("src/tools/clippy/tests").path("src/tools/clippy")
836 }
837
838 fn make_run(run: RunConfig<'_>) {
839 run.builder.ensure(Clippy {
840 compilers: RustcPrivateCompilers::new(
841 run.builder,
842 run.builder.top_stage,
843 run.builder.host_target,
844 ),
845 });
846 }
847
848 fn run(self, builder: &Builder<'_>) {
850 let target = self.compilers.target();
851
852 let compilers = self.compilers;
856 let target_compiler = compilers.target_compiler();
857
858 let tool_result = builder.ensure(tool::Clippy::from_compilers(compilers));
859 let build_compiler = tool_result.build_compiler;
860 let mut cargo = tool::prepare_tool_cargo(
861 builder,
862 build_compiler,
863 Mode::ToolRustcPrivate,
864 target,
865 Kind::Test,
866 "src/tools/clippy",
867 SourceType::InTree,
868 &[],
869 );
870
871 cargo.env("RUSTC_TEST_SUITE", builder.rustc(build_compiler));
872 cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(build_compiler));
873 let host_libs =
874 builder.stage_out(build_compiler, Mode::ToolRustcPrivate).join(builder.cargo_dir());
875 cargo.env("HOST_LIBS", host_libs);
876
877 builder.std(target_compiler, target);
879 cargo.env("TEST_SYSROOT", builder.sysroot(target_compiler));
880 cargo.env("TEST_RUSTC", builder.rustc(target_compiler));
881 cargo.env("TEST_RUSTC_LIB", builder.rustc_libdir(target_compiler));
882
883 'partially_test: {
885 let paths = &builder.config.paths[..];
886 let mut test_names = Vec::new();
887 for path in paths {
888 if let Some(path) =
889 helpers::is_valid_test_suite_arg(path, "src/tools/clippy/tests", builder)
890 {
891 test_names.push(path);
892 } else if path.ends_with("src/tools/clippy") {
893 break 'partially_test;
895 }
896 }
897 cargo.env("TESTNAME", test_names.join(","));
898 }
899
900 cargo.add_rustc_lib_path(builder);
901 let cargo = prepare_cargo_test(cargo, &[], &[], target, builder);
902
903 let _guard = builder.msg_test("clippy", target, target_compiler.stage);
904
905 if cargo.allow_failure().run(builder) {
907 return;
909 }
910
911 if !builder.config.cmd.bless() {
912 crate::exit!(1);
913 }
914 }
915
916 fn metadata(&self) -> Option<StepMetadata> {
917 Some(
918 StepMetadata::test("clippy", self.compilers.target())
919 .built_by(self.compilers.build_compiler()),
920 )
921 }
922}
923
924fn bin_path_for_cargo(builder: &Builder<'_>, compiler: Compiler) -> OsString {
925 let path = builder.sysroot(compiler).join("bin");
926 let old_path = env::var_os("PATH").unwrap_or_default();
927 env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("")
928}
929
930#[derive(Debug, Clone, Hash, PartialEq, Eq)]
932pub struct RustdocTheme {
933 test_compiler: Compiler,
935}
936
937impl Step for RustdocTheme {
938 type Output = ();
939 const DEFAULT: bool = true;
940 const IS_HOST: bool = true;
941
942 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
943 run.path("src/tools/rustdoc-themes")
944 }
945
946 fn make_run(run: RunConfig<'_>) {
947 let test_compiler = run.builder.compiler(run.builder.top_stage, run.target);
948
949 run.builder.ensure(RustdocTheme { test_compiler });
950 }
951
952 fn run(self, builder: &Builder<'_>) {
953 let rustdoc = builder.bootstrap_out.join("rustdoc");
954 let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
955 cmd.arg(rustdoc.to_str().unwrap())
956 .arg(builder.src.join("src/librustdoc/html/static/css/rustdoc.css").to_str().unwrap())
957 .env("RUSTC_STAGE", self.test_compiler.stage.to_string())
958 .env("RUSTC_SYSROOT", builder.sysroot(self.test_compiler))
959 .env(
960 "RUSTDOC_LIBDIR",
961 builder.sysroot_target_libdir(self.test_compiler, self.test_compiler.host),
962 )
963 .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
964 .env("RUSTDOC_REAL", builder.rustdoc_for_compiler(self.test_compiler))
965 .env("RUSTC_BOOTSTRAP", "1");
966 cmd.args(linker_args(builder, self.test_compiler.host, LldThreads::No));
967
968 cmd.delay_failure().run(builder);
969 }
970
971 fn metadata(&self) -> Option<StepMetadata> {
972 Some(
973 StepMetadata::test("rustdoc-theme", self.test_compiler.host)
974 .stage(self.test_compiler.stage),
975 )
976 }
977}
978
979#[derive(Debug, Clone, Hash, PartialEq, Eq)]
981pub struct RustdocJSStd {
982 build_compiler: Compiler,
984 target: TargetSelection,
985}
986
987impl Step for RustdocJSStd {
988 type Output = ();
989 const DEFAULT: bool = true;
990 const IS_HOST: bool = true;
991
992 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
993 let default = run.builder.config.nodejs.is_some();
994 run.suite_path("tests/rustdoc-js-std").default_condition(default)
995 }
996
997 fn make_run(run: RunConfig<'_>) {
998 run.builder.ensure(RustdocJSStd {
999 build_compiler: run.builder.compiler(run.builder.top_stage, run.builder.host_target),
1000 target: run.target,
1001 });
1002 }
1003
1004 fn run(self, builder: &Builder<'_>) {
1005 let nodejs =
1006 builder.config.nodejs.as_ref().expect("need nodejs to run rustdoc-js-std tests");
1007 let mut command = command(nodejs);
1008 command
1009 .arg(builder.src.join("src/tools/rustdoc-js/tester.js"))
1010 .arg("--crate-name")
1011 .arg("std")
1012 .arg("--resource-suffix")
1013 .arg(&builder.version)
1014 .arg("--doc-folder")
1015 .arg(builder.doc_out(self.target))
1016 .arg("--test-folder")
1017 .arg(builder.src.join("tests/rustdoc-js-std"));
1018 for path in &builder.paths {
1019 if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder)
1020 {
1021 if !p.ends_with(".js") {
1022 eprintln!("A non-js file was given: `{}`", path.display());
1023 panic!("Cannot run rustdoc-js-std tests");
1024 }
1025 command.arg("--test-file").arg(path);
1026 }
1027 }
1028 builder.ensure(crate::core::build_steps::doc::Std::from_build_compiler(
1029 self.build_compiler,
1030 self.target,
1031 DocumentationFormat::Html,
1032 ));
1033 let _guard = builder.msg_test("rustdoc-js-std", self.target, self.build_compiler.stage);
1034 command.run(builder);
1035 }
1036
1037 fn metadata(&self) -> Option<StepMetadata> {
1038 Some(StepMetadata::test("rustdoc-js-std", self.target).stage(self.build_compiler.stage))
1039 }
1040}
1041
1042#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1043pub struct RustdocJSNotStd {
1044 pub target: TargetSelection,
1045 pub compiler: Compiler,
1046}
1047
1048impl Step for RustdocJSNotStd {
1049 type Output = ();
1050 const DEFAULT: bool = true;
1051 const IS_HOST: bool = true;
1052
1053 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1054 let default = run.builder.config.nodejs.is_some();
1055 run.suite_path("tests/rustdoc-js").default_condition(default)
1056 }
1057
1058 fn make_run(run: RunConfig<'_>) {
1059 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1060 run.builder.ensure(RustdocJSNotStd { target: run.target, compiler });
1061 }
1062
1063 fn run(self, builder: &Builder<'_>) {
1064 builder.ensure(Compiletest {
1065 test_compiler: self.compiler,
1066 target: self.target,
1067 mode: "rustdoc-js",
1068 suite: "rustdoc-js",
1069 path: "tests/rustdoc-js",
1070 compare_mode: None,
1071 });
1072 }
1073}
1074
1075fn get_browser_ui_test_version_inner(
1076 builder: &Builder<'_>,
1077 npm: &Path,
1078 global: bool,
1079) -> Option<String> {
1080 let mut command = command(npm);
1081 command.arg("list").arg("--parseable").arg("--long").arg("--depth=0");
1082 if global {
1083 command.arg("--global");
1084 }
1085 let lines = command.allow_failure().run_capture(builder).stdout();
1086 lines
1087 .lines()
1088 .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@"))
1089 .map(|v| v.to_owned())
1090}
1091
1092fn get_browser_ui_test_version(builder: &Builder<'_>, npm: &Path) -> Option<String> {
1093 get_browser_ui_test_version_inner(builder, npm, false)
1094 .or_else(|| get_browser_ui_test_version_inner(builder, npm, true))
1095}
1096
1097#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1099pub struct RustdocGUI {
1100 test_compiler: Compiler,
1102 target: TargetSelection,
1103}
1104
1105impl Step for RustdocGUI {
1106 type Output = ();
1107 const DEFAULT: bool = true;
1108 const IS_HOST: bool = true;
1109
1110 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1111 let builder = run.builder;
1112 let run = run.suite_path("tests/rustdoc-gui");
1113 run.lazy_default_condition(Box::new(move || {
1114 builder.config.nodejs.is_some()
1115 && builder.doc_tests != DocTests::Only
1116 && builder
1117 .config
1118 .npm
1119 .as_ref()
1120 .map(|p| get_browser_ui_test_version(builder, p).is_some())
1121 .unwrap_or(false)
1122 }))
1123 }
1124
1125 fn make_run(run: RunConfig<'_>) {
1126 let test_compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1127 run.builder.ensure(RustdocGUI { test_compiler, target: run.target });
1128 }
1129
1130 fn run(self, builder: &Builder<'_>) {
1131 builder.std(self.test_compiler, self.target);
1132
1133 let mut cmd = builder.tool_cmd(Tool::RustdocGUITest);
1134
1135 let out_dir = builder.test_out(self.target).join("rustdoc-gui");
1136 build_stamp::clear_if_dirty(
1137 builder,
1138 &out_dir,
1139 &builder.rustdoc_for_compiler(self.test_compiler),
1140 );
1141
1142 if let Some(src) = builder.config.src.to_str() {
1143 cmd.arg("--rust-src").arg(src);
1144 }
1145
1146 if let Some(out_dir) = out_dir.to_str() {
1147 cmd.arg("--out-dir").arg(out_dir);
1148 }
1149
1150 if let Some(initial_cargo) = builder.config.initial_cargo.to_str() {
1151 cmd.arg("--initial-cargo").arg(initial_cargo);
1152 }
1153
1154 cmd.arg("--jobs").arg(builder.jobs().to_string());
1155
1156 cmd.env("RUSTDOC", builder.rustdoc_for_compiler(self.test_compiler))
1157 .env("RUSTC", builder.rustc(self.test_compiler));
1158
1159 add_rustdoc_cargo_linker_args(&mut cmd, builder, self.test_compiler.host, LldThreads::No);
1160
1161 for path in &builder.paths {
1162 if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) {
1163 if !p.ends_with(".goml") {
1164 eprintln!("A non-goml file was given: `{}`", path.display());
1165 panic!("Cannot run rustdoc-gui tests");
1166 }
1167 if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
1168 cmd.arg("--goml-file").arg(name);
1169 }
1170 }
1171 }
1172
1173 for test_arg in builder.config.test_args() {
1174 cmd.arg("--test-arg").arg(test_arg);
1175 }
1176
1177 if let Some(ref nodejs) = builder.config.nodejs {
1178 cmd.arg("--nodejs").arg(nodejs);
1179 }
1180
1181 if let Some(ref npm) = builder.config.npm {
1182 cmd.arg("--npm").arg(npm);
1183 }
1184
1185 let _time = helpers::timeit(builder);
1186 let _guard = builder.msg_test("rustdoc-gui", self.target, self.test_compiler.stage);
1187 try_run_tests(builder, &mut cmd, true);
1188 }
1189
1190 fn metadata(&self) -> Option<StepMetadata> {
1191 Some(StepMetadata::test("rustdoc-gui", self.target).stage(self.test_compiler.stage))
1192 }
1193}
1194
1195#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1200pub struct Tidy;
1201
1202impl Step for Tidy {
1203 type Output = ();
1204 const DEFAULT: bool = true;
1205 const IS_HOST: bool = true;
1206
1207 fn run(self, builder: &Builder<'_>) {
1216 let mut cmd = builder.tool_cmd(Tool::Tidy);
1217 cmd.arg(&builder.src);
1218 cmd.arg(&builder.initial_cargo);
1219 cmd.arg(&builder.out);
1220 let jobs = builder.config.jobs.unwrap_or_else(|| {
1222 8 * std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32
1223 });
1224 cmd.arg(jobs.to_string());
1225 if let Some(npm) = &builder.config.npm {
1227 cmd.arg(npm);
1228 } else {
1229 cmd.arg("npm");
1230 }
1231 if builder.is_verbose() {
1232 cmd.arg("--verbose");
1233 }
1234 if builder.config.cmd.bless() {
1235 cmd.arg("--bless");
1236 }
1237 if let Some(s) =
1238 builder.config.cmd.extra_checks().or(builder.config.tidy_extra_checks.as_deref())
1239 {
1240 cmd.arg(format!("--extra-checks={s}"));
1241 }
1242 let mut args = std::env::args_os();
1243 if args.any(|arg| arg == OsStr::new("--")) {
1244 cmd.arg("--");
1245 cmd.args(args);
1246 }
1247
1248 if builder.config.channel == "dev" || builder.config.channel == "nightly" {
1249 if !builder.config.json_output {
1250 builder.info("fmt check");
1251 if builder.config.initial_rustfmt.is_none() {
1252 let inferred_rustfmt_dir = builder.initial_sysroot.join("bin");
1253 eprintln!(
1254 "\
1255ERROR: no `rustfmt` binary found in {PATH}
1256INFO: `rust.channel` is currently set to \"{CHAN}\"
1257HELP: if you are testing a beta branch, set `rust.channel` to \"beta\" in the `bootstrap.toml` file
1258HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to `x.py test`",
1259 PATH = inferred_rustfmt_dir.display(),
1260 CHAN = builder.config.channel,
1261 );
1262 crate::exit!(1);
1263 }
1264 let all = false;
1265 crate::core::build_steps::format::format(
1266 builder,
1267 !builder.config.cmd.bless(),
1268 all,
1269 &[],
1270 );
1271 } else {
1272 eprintln!(
1273 "WARNING: `--json-output` is not supported on rustfmt, formatting will be skipped"
1274 );
1275 }
1276 }
1277
1278 builder.info("tidy check");
1279 cmd.delay_failure().run(builder);
1280
1281 builder.info("x.py completions check");
1282 let completion_paths = get_completion_paths(builder);
1283 if builder.config.cmd.bless() {
1284 builder.ensure(crate::core::build_steps::run::GenerateCompletions);
1285 } else if completion_paths
1286 .into_iter()
1287 .any(|(shell, path)| get_completion(shell, &path).is_some())
1288 {
1289 eprintln!(
1290 "x.py completions were changed; run `x.py run generate-completions` to update them"
1291 );
1292 crate::exit!(1);
1293 }
1294
1295 builder.info("x.py help check");
1296 if builder.config.cmd.bless() {
1297 builder.ensure(crate::core::build_steps::run::GenerateHelp);
1298 } else {
1299 let help_path = get_help_path(builder);
1300 let cur_help = std::fs::read_to_string(&help_path).unwrap_or_else(|err| {
1301 eprintln!("couldn't read {}: {}", help_path.display(), err);
1302 crate::exit!(1);
1303 });
1304 let new_help = top_level_help();
1305
1306 if new_help != cur_help {
1307 eprintln!("x.py help was changed; run `x.py run generate-help` to update it");
1308 crate::exit!(1);
1309 }
1310 }
1311 }
1312
1313 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1314 let default = run.builder.doc_tests != DocTests::Only;
1315 run.path("src/tools/tidy").default_condition(default)
1316 }
1317
1318 fn make_run(run: RunConfig<'_>) {
1319 run.builder.ensure(Tidy);
1320 }
1321
1322 fn metadata(&self) -> Option<StepMetadata> {
1323 Some(StepMetadata::test("tidy", TargetSelection::default()))
1324 }
1325}
1326
1327#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1330pub struct CrateRunMakeSupport {
1331 host: TargetSelection,
1332}
1333
1334impl Step for CrateRunMakeSupport {
1335 type Output = ();
1336 const IS_HOST: bool = true;
1337
1338 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1339 run.path("src/tools/run-make-support")
1340 }
1341
1342 fn make_run(run: RunConfig<'_>) {
1343 run.builder.ensure(CrateRunMakeSupport { host: run.target });
1344 }
1345
1346 fn run(self, builder: &Builder<'_>) {
1348 let host = self.host;
1349 let compiler = builder.compiler(0, host);
1350
1351 let mut cargo = tool::prepare_tool_cargo(
1352 builder,
1353 compiler,
1354 Mode::ToolBootstrap,
1355 host,
1356 Kind::Test,
1357 "src/tools/run-make-support",
1358 SourceType::InTree,
1359 &[],
1360 );
1361 cargo.allow_features("test");
1362 run_cargo_test(cargo, &[], &[], "run-make-support self test", host, builder);
1363 }
1364}
1365
1366#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1367pub struct CrateBuildHelper {
1368 host: TargetSelection,
1369}
1370
1371impl Step for CrateBuildHelper {
1372 type Output = ();
1373 const IS_HOST: bool = true;
1374
1375 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1376 run.path("src/build_helper")
1377 }
1378
1379 fn make_run(run: RunConfig<'_>) {
1380 run.builder.ensure(CrateBuildHelper { host: run.target });
1381 }
1382
1383 fn run(self, builder: &Builder<'_>) {
1385 let host = self.host;
1386 let compiler = builder.compiler(0, host);
1387
1388 let mut cargo = tool::prepare_tool_cargo(
1389 builder,
1390 compiler,
1391 Mode::ToolBootstrap,
1392 host,
1393 Kind::Test,
1394 "src/build_helper",
1395 SourceType::InTree,
1396 &[],
1397 );
1398 cargo.allow_features("test");
1399 run_cargo_test(cargo, &[], &[], "build_helper self test", host, builder);
1400 }
1401}
1402
1403fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf {
1404 builder.out.join(host).join("test")
1405}
1406
1407macro_rules! test {
1409 (
1410 $( #[$attr:meta] )* $name:ident {
1412 path: $path:expr,
1413 mode: $mode:expr,
1414 suite: $suite:expr,
1415 default: $default:expr
1416 $( , IS_HOST: $IS_HOST:expr )? $( , compare_mode: $compare_mode:expr )? $( , )? }
1420 ) => {
1421 $( #[$attr] )*
1422 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
1423 pub struct $name {
1424 test_compiler: Compiler,
1425 target: TargetSelection,
1426 }
1427
1428 impl Step for $name {
1429 type Output = ();
1430 const DEFAULT: bool = $default;
1431 const IS_HOST: bool = (const {
1432 #[allow(unused_assignments, unused_mut)]
1433 let mut value = false;
1434 $( value = $IS_HOST; )?
1435 value
1436 });
1437
1438 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1439 run.suite_path($path)
1440 }
1441
1442 fn make_run(run: RunConfig<'_>) {
1443 let test_compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1444
1445 run.builder.ensure($name { test_compiler, target: run.target });
1446 }
1447
1448 fn run(self, builder: &Builder<'_>) {
1449 builder.ensure(Compiletest {
1450 test_compiler: self.test_compiler,
1451 target: self.target,
1452 mode: $mode,
1453 suite: $suite,
1454 path: $path,
1455 compare_mode: (const {
1456 #[allow(unused_assignments, unused_mut)]
1457 let mut value = None;
1458 $( value = $compare_mode; )?
1459 value
1460 }),
1461 })
1462 }
1463 }
1464 };
1465}
1466
1467test!(Ui { path: "tests/ui", mode: "ui", suite: "ui", default: true });
1468
1469test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes", default: true });
1470
1471test!(CodegenLlvm {
1472 path: "tests/codegen-llvm",
1473 mode: "codegen",
1474 suite: "codegen-llvm",
1475 default: true
1476});
1477
1478test!(CodegenUnits {
1479 path: "tests/codegen-units",
1480 mode: "codegen-units",
1481 suite: "codegen-units",
1482 default: true,
1483});
1484
1485test!(Incremental {
1486 path: "tests/incremental",
1487 mode: "incremental",
1488 suite: "incremental",
1489 default: true,
1490});
1491
1492test!(Debuginfo {
1493 path: "tests/debuginfo",
1494 mode: "debuginfo",
1495 suite: "debuginfo",
1496 default: true,
1497 compare_mode: Some("split-dwarf"),
1498});
1499
1500test!(UiFullDeps {
1501 path: "tests/ui-fulldeps",
1502 mode: "ui",
1503 suite: "ui-fulldeps",
1504 default: true,
1505 IS_HOST: true,
1506});
1507
1508test!(Rustdoc {
1509 path: "tests/rustdoc",
1510 mode: "rustdoc",
1511 suite: "rustdoc",
1512 default: true,
1513 IS_HOST: true,
1514});
1515test!(RustdocUi {
1516 path: "tests/rustdoc-ui",
1517 mode: "ui",
1518 suite: "rustdoc-ui",
1519 default: true,
1520 IS_HOST: true,
1521});
1522
1523test!(RustdocJson {
1524 path: "tests/rustdoc-json",
1525 mode: "rustdoc-json",
1526 suite: "rustdoc-json",
1527 default: true,
1528 IS_HOST: true,
1529});
1530
1531test!(Pretty {
1532 path: "tests/pretty",
1533 mode: "pretty",
1534 suite: "pretty",
1535 default: true,
1536 IS_HOST: true,
1537});
1538
1539test!(RunMake { path: "tests/run-make", mode: "run-make", suite: "run-make", default: true });
1540test!(RunMakeCargo {
1541 path: "tests/run-make-cargo",
1542 mode: "run-make",
1543 suite: "run-make-cargo",
1544 default: true
1545});
1546
1547test!(AssemblyLlvm {
1548 path: "tests/assembly-llvm",
1549 mode: "assembly",
1550 suite: "assembly-llvm",
1551 default: true
1552});
1553
1554#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1557pub struct Coverage {
1558 pub compiler: Compiler,
1559 pub target: TargetSelection,
1560 pub mode: &'static str,
1561}
1562
1563impl Coverage {
1564 const PATH: &'static str = "tests/coverage";
1565 const SUITE: &'static str = "coverage";
1566 const ALL_MODES: &[&str] = &["coverage-map", "coverage-run"];
1567}
1568
1569impl Step for Coverage {
1570 type Output = ();
1571 const DEFAULT: bool = true;
1572 const IS_HOST: bool = false;
1574
1575 fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {
1576 run = run.suite_path(Self::PATH);
1582 for mode in Self::ALL_MODES {
1583 run = run.alias(mode);
1584 }
1585 run
1586 }
1587
1588 fn make_run(run: RunConfig<'_>) {
1589 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1590 let target = run.target;
1591
1592 let mut modes = vec![];
1596
1597 for path in &run.paths {
1600 match path {
1601 PathSet::Set(_) => {
1602 for mode in Self::ALL_MODES {
1603 if path.assert_single_path().path == Path::new(mode) {
1604 modes.push(mode);
1605 break;
1606 }
1607 }
1608 }
1609 PathSet::Suite(_) => {
1610 modes.extend(Self::ALL_MODES);
1611 break;
1612 }
1613 }
1614 }
1615
1616 modes.retain(|mode| !run.builder.config.skip.iter().any(|skip| skip == Path::new(mode)));
1619
1620 for mode in modes {
1628 run.builder.ensure(Coverage { compiler, target, mode });
1629 }
1630 }
1631
1632 fn run(self, builder: &Builder<'_>) {
1633 let Self { compiler, target, mode } = self;
1634 builder.ensure(Compiletest {
1637 test_compiler: compiler,
1638 target,
1639 mode,
1640 suite: Self::SUITE,
1641 path: Self::PATH,
1642 compare_mode: None,
1643 });
1644 }
1645}
1646
1647test!(CoverageRunRustdoc {
1648 path: "tests/coverage-run-rustdoc",
1649 mode: "coverage-run",
1650 suite: "coverage-run-rustdoc",
1651 default: true,
1652 IS_HOST: true,
1653});
1654
1655#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1657pub struct MirOpt {
1658 pub compiler: Compiler,
1659 pub target: TargetSelection,
1660}
1661
1662impl Step for MirOpt {
1663 type Output = ();
1664 const DEFAULT: bool = true;
1665
1666 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1667 run.suite_path("tests/mir-opt")
1668 }
1669
1670 fn make_run(run: RunConfig<'_>) {
1671 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1672 run.builder.ensure(MirOpt { compiler, target: run.target });
1673 }
1674
1675 fn run(self, builder: &Builder<'_>) {
1676 let run = |target| {
1677 builder.ensure(Compiletest {
1678 test_compiler: self.compiler,
1679 target,
1680 mode: "mir-opt",
1681 suite: "mir-opt",
1682 path: "tests/mir-opt",
1683 compare_mode: None,
1684 })
1685 };
1686
1687 run(self.target);
1688
1689 if builder.config.cmd.bless() {
1692 for target in ["aarch64-unknown-linux-gnu", "i686-pc-windows-msvc"] {
1698 run(TargetSelection::from_user(target));
1699 }
1700
1701 for target in ["x86_64-apple-darwin", "i686-unknown-linux-musl"] {
1702 let target = TargetSelection::from_user(target);
1703 let panic_abort_target = builder.ensure(MirOptPanicAbortSyntheticTarget {
1704 compiler: self.compiler,
1705 base: target,
1706 });
1707 run(panic_abort_target);
1708 }
1709 }
1710 }
1711}
1712
1713#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1719struct Compiletest {
1720 test_compiler: Compiler,
1722 target: TargetSelection,
1723 mode: &'static str,
1724 suite: &'static str,
1725 path: &'static str,
1726 compare_mode: Option<&'static str>,
1727}
1728
1729impl Step for Compiletest {
1730 type Output = ();
1731
1732 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1733 run.never()
1734 }
1735
1736 fn run(self, builder: &Builder<'_>) {
1737 if builder.doc_tests == DocTests::Only {
1738 return;
1739 }
1740
1741 if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 {
1742 eprintln!("\
1743ERROR: `--stage 0` runs compiletest on the stage0 (precompiled) compiler, not your local changes, and will almost always cause tests to fail
1744HELP: to test the compiler or standard library, omit the stage or explicitly use `--stage 1` instead
1745NOTE: 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`."
1746 );
1747 crate::exit!(1);
1748 }
1749
1750 let mut test_compiler = self.test_compiler;
1751 let target = self.target;
1752 let mode = self.mode;
1753 let suite = self.suite;
1754
1755 let suite_path = self.path;
1757
1758 if !builder.config.codegen_tests && mode == "codegen" {
1760 return;
1761 }
1762
1763 let query_compiler;
1770 let (stage, stage_id) = if suite == "ui-fulldeps" && test_compiler.stage == 1 {
1771 query_compiler = Some(test_compiler);
1774 let build = builder.build.host_target;
1778 test_compiler = builder.compiler(test_compiler.stage - 1, build);
1779 let test_stage = test_compiler.stage + 1;
1780 (test_stage, format!("stage{test_stage}-{build}"))
1781 } else {
1782 query_compiler = None;
1783 let stage = test_compiler.stage;
1784 (stage, format!("stage{stage}-{target}"))
1785 };
1786
1787 if suite.ends_with("fulldeps") {
1788 builder.ensure(compile::Rustc::new(test_compiler, target));
1789 }
1790
1791 if suite == "debuginfo" {
1792 builder.ensure(dist::DebuggerScripts {
1793 sysroot: builder.sysroot(test_compiler).to_path_buf(),
1794 target,
1795 });
1796 }
1797 if mode == "run-make" {
1798 builder.tool_exe(Tool::RunMakeSupport);
1799 }
1800
1801 if suite == "mir-opt" {
1803 builder.ensure(
1804 compile::Std::new(test_compiler, test_compiler.host).is_for_mir_opt_tests(true),
1805 );
1806 } else {
1807 builder.std(test_compiler, test_compiler.host);
1808 }
1809
1810 let mut cmd = builder.tool_cmd(Tool::Compiletest);
1811
1812 if suite == "mir-opt" {
1813 builder.ensure(compile::Std::new(test_compiler, target).is_for_mir_opt_tests(true));
1814 } else {
1815 builder.std(test_compiler, target);
1816 }
1817
1818 builder.ensure(RemoteCopyLibs { build_compiler: test_compiler, target });
1819
1820 cmd.arg("--stage").arg(stage.to_string());
1824 cmd.arg("--stage-id").arg(stage_id);
1825
1826 cmd.arg("--compile-lib-path").arg(builder.rustc_libdir(test_compiler));
1827 cmd.arg("--run-lib-path").arg(builder.sysroot_target_libdir(test_compiler, target));
1828 cmd.arg("--rustc-path").arg(builder.rustc(test_compiler));
1829 if let Some(query_compiler) = query_compiler {
1830 cmd.arg("--query-rustc-path").arg(builder.rustc(query_compiler));
1831 }
1832
1833 cmd.arg("--minicore-path")
1836 .arg(builder.src.join("tests").join("auxiliary").join("minicore.rs"));
1837
1838 let is_rustdoc = suite == "rustdoc-ui" || suite == "rustdoc-js";
1839
1840 if mode == "run-make" {
1855 let stage0_rustc_path = builder.compiler(0, test_compiler.host);
1858 cmd.arg("--stage0-rustc-path").arg(builder.rustc(stage0_rustc_path));
1859
1860 if suite == "run-make-cargo" {
1861 let cargo_path = if test_compiler.stage == 0 {
1862 builder.initial_cargo.clone()
1864 } else {
1865 builder
1866 .ensure(tool::Cargo::from_build_compiler(
1867 builder.compiler(test_compiler.stage - 1, test_compiler.host),
1868 test_compiler.host,
1869 ))
1870 .tool_path
1871 };
1872
1873 cmd.arg("--cargo-path").arg(cargo_path);
1874 }
1875 }
1876
1877 if mode == "rustdoc"
1879 || mode == "run-make"
1880 || (mode == "ui" && is_rustdoc)
1881 || mode == "rustdoc-js"
1882 || mode == "rustdoc-json"
1883 || suite == "coverage-run-rustdoc"
1884 {
1885 cmd.arg("--rustdoc-path").arg(builder.rustdoc_for_compiler(test_compiler));
1886 }
1887
1888 if mode == "rustdoc-json" {
1889 let json_compiler = builder.compiler(0, builder.host_target);
1891 cmd.arg("--jsondocck-path")
1892 .arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target }).tool_path);
1893 cmd.arg("--jsondoclint-path").arg(
1894 builder.ensure(tool::JsonDocLint { compiler: json_compiler, target }).tool_path,
1895 );
1896 }
1897
1898 if matches!(mode, "coverage-map" | "coverage-run") {
1899 let coverage_dump = builder.tool_exe(Tool::CoverageDump);
1900 cmd.arg("--coverage-dump-path").arg(coverage_dump);
1901 }
1902
1903 cmd.arg("--src-root").arg(&builder.src);
1904 cmd.arg("--src-test-suite-root").arg(builder.src.join("tests").join(suite));
1905
1906 cmd.arg("--build-root").arg(&builder.out);
1910 cmd.arg("--build-test-suite-root").arg(testdir(builder, test_compiler.host).join(suite));
1911
1912 let sysroot = if builder.top_stage == 0 {
1917 builder.initial_sysroot.clone()
1918 } else {
1919 builder.sysroot(test_compiler)
1920 };
1921
1922 cmd.arg("--sysroot-base").arg(sysroot);
1923
1924 cmd.arg("--suite").arg(suite);
1925 cmd.arg("--mode").arg(mode);
1926 cmd.arg("--target").arg(target.rustc_target_arg());
1927 cmd.arg("--host").arg(&*test_compiler.host.triple);
1928 cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.host_target));
1929
1930 if let Some(codegen_backend) = builder.config.cmd.test_codegen_backend() {
1931 if !builder
1932 .config
1933 .enabled_codegen_backends(test_compiler.host)
1934 .contains(codegen_backend)
1935 {
1936 eprintln!(
1937 "\
1938ERROR: No configured backend named `{name}`
1939HELP: You can add it into `bootstrap.toml` in `rust.codegen-backends = [{name:?}]`",
1940 name = codegen_backend.name(),
1941 );
1942 crate::exit!(1);
1943 }
1944
1945 if let CodegenBackendKind::Gcc = codegen_backend
1946 && builder.config.rustc_debug_assertions
1947 {
1948 eprintln!(
1949 r#"WARNING: Running tests with the GCC codegen backend while rustc debug assertions are enabled. This might lead to test failures.
1950Please disable assertions with `rust.debug-assertions = false`.
1951 "#
1952 );
1953 }
1954
1955 cmd.arg("--override-codegen-backend").arg(codegen_backend.name());
1958 cmd.arg("--default-codegen-backend").arg(codegen_backend.name());
1961 } else {
1962 cmd.arg("--default-codegen-backend")
1965 .arg(builder.config.default_codegen_backend(test_compiler.host).name());
1966 }
1967 if builder.config.cmd.bypass_ignore_backends() {
1968 cmd.arg("--bypass-ignore-backends");
1969 }
1970
1971 if builder.build.config.llvm_enzyme {
1972 cmd.arg("--has-enzyme");
1973 }
1974
1975 if builder.config.cmd.bless() {
1976 cmd.arg("--bless");
1977 }
1978
1979 if builder.config.cmd.force_rerun() {
1980 cmd.arg("--force-rerun");
1981 }
1982
1983 if builder.config.cmd.no_capture() {
1984 cmd.arg("--no-capture");
1985 }
1986
1987 let compare_mode =
1988 builder.config.cmd.compare_mode().or_else(|| {
1989 if builder.config.test_compare_mode { self.compare_mode } else { None }
1990 });
1991
1992 if let Some(ref pass) = builder.config.cmd.pass() {
1993 cmd.arg("--pass");
1994 cmd.arg(pass);
1995 }
1996
1997 if let Some(ref run) = builder.config.cmd.run() {
1998 cmd.arg("--run");
1999 cmd.arg(run);
2000 }
2001
2002 if let Some(ref nodejs) = builder.config.nodejs {
2003 cmd.arg("--nodejs").arg(nodejs);
2004 } else if mode == "rustdoc-js" {
2005 panic!("need nodejs to run rustdoc-js suite");
2006 }
2007 if builder.config.rust_optimize_tests {
2008 cmd.arg("--optimize-tests");
2009 }
2010 if builder.config.rust_randomize_layout {
2011 cmd.arg("--rust-randomized-layout");
2012 }
2013 if builder.config.cmd.only_modified() {
2014 cmd.arg("--only-modified");
2015 }
2016 if let Some(compiletest_diff_tool) = &builder.config.compiletest_diff_tool {
2017 cmd.arg("--compiletest-diff-tool").arg(compiletest_diff_tool);
2018 }
2019
2020 let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
2021 flags.push(format!(
2022 "-Cdebuginfo={}",
2023 if mode == "codegen" {
2024 if builder.config.rust_debuginfo_level_tests
2027 != crate::core::config::DebuginfoLevel::None
2028 {
2029 println!(
2030 "NOTE: ignoring `rust.debuginfo-level-tests={}` for codegen tests",
2031 builder.config.rust_debuginfo_level_tests
2032 );
2033 }
2034 crate::core::config::DebuginfoLevel::None
2035 } else {
2036 builder.config.rust_debuginfo_level_tests
2037 }
2038 ));
2039 flags.extend(builder.config.cmd.compiletest_rustc_args().iter().map(|s| s.to_string()));
2040
2041 if suite != "mir-opt" {
2042 if let Some(linker) = builder.linker(target) {
2043 cmd.arg("--target-linker").arg(linker);
2044 }
2045 if let Some(linker) = builder.linker(test_compiler.host) {
2046 cmd.arg("--host-linker").arg(linker);
2047 }
2048 }
2049
2050 if suite == "ui-fulldeps" && target.ends_with("darwin") {
2052 flags.push("-Alinker_messages".into());
2053 }
2054
2055 let mut hostflags = flags.clone();
2056 hostflags.extend(linker_flags(builder, test_compiler.host, LldThreads::No));
2057
2058 let mut targetflags = flags;
2059
2060 if suite == "ui" || suite == "incremental" {
2062 builder.ensure(TestHelpers { target: test_compiler.host });
2063 builder.ensure(TestHelpers { target });
2064 hostflags.push(format!(
2065 "-Lnative={}",
2066 builder.test_helpers_out(test_compiler.host).display()
2067 ));
2068 targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
2069 }
2070
2071 for flag in hostflags {
2072 cmd.arg("--host-rustcflags").arg(flag);
2073 }
2074 for flag in targetflags {
2075 cmd.arg("--target-rustcflags").arg(flag);
2076 }
2077
2078 cmd.arg("--python").arg(builder.python());
2079
2080 if let Some(debuggers::Android { adb_path, adb_test_dir, android_cross_path }) =
2085 debuggers::discover_android(builder, target)
2086 {
2087 cmd.arg("--adb-path").arg(adb_path);
2088 cmd.arg("--adb-test-dir").arg(adb_test_dir);
2089 cmd.arg("--android-cross-path").arg(android_cross_path);
2090 }
2091
2092 if mode == "debuginfo" {
2093 if let Some(debuggers::Gdb { gdb }) = debuggers::discover_gdb(builder) {
2094 cmd.arg("--gdb").arg(gdb);
2095 }
2096
2097 if let Some(debuggers::Lldb { lldb_version, lldb_python_dir }) =
2098 debuggers::discover_lldb(builder)
2099 {
2100 cmd.arg("--lldb-version").arg(lldb_version);
2101 cmd.arg("--lldb-python-dir").arg(lldb_python_dir);
2102 }
2103 }
2104
2105 if helpers::forcing_clang_based_tests() {
2106 let clang_exe = builder.llvm_out(target).join("bin").join("clang");
2107 cmd.arg("--run-clang-based-tests-with").arg(clang_exe);
2108 }
2109
2110 for exclude in &builder.config.skip {
2111 cmd.arg("--skip");
2112 cmd.arg(exclude);
2113 }
2114
2115 let mut paths = match &builder.config.cmd {
2117 Subcommand::Test { .. } => &builder.config.paths[..],
2118 _ => &[],
2119 };
2120
2121 let mut paths_v;
2124 if mode == "rustdoc-js" {
2125 paths_v = paths.to_vec();
2126 for p in &mut paths_v {
2127 if let Some(ext) = p.extension()
2128 && ext == "js"
2129 {
2130 p.set_extension("rs");
2131 }
2132 }
2133 paths = &paths_v;
2134 }
2135 let mut test_args: Vec<&str> = paths
2137 .iter()
2138 .filter_map(|p| helpers::is_valid_test_suite_arg(p, suite_path, builder))
2139 .collect();
2140
2141 test_args.append(&mut builder.config.test_args());
2142
2143 if cfg!(windows) {
2146 let test_args_win: Vec<String> =
2147 test_args.iter().map(|s| s.replace('/', "\\")).collect();
2148 cmd.args(&test_args_win);
2149 } else {
2150 cmd.args(&test_args);
2151 }
2152
2153 if builder.is_verbose() {
2154 cmd.arg("--verbose");
2155 }
2156
2157 if builder.config.rustc_debug_assertions {
2158 cmd.arg("--with-rustc-debug-assertions");
2159 }
2160
2161 if builder.config.std_debug_assertions {
2162 cmd.arg("--with-std-debug-assertions");
2163 }
2164
2165 let mut llvm_components_passed = false;
2166 let mut copts_passed = false;
2167 if builder.config.llvm_enabled(test_compiler.host) {
2168 let llvm::LlvmResult { host_llvm_config, .. } =
2169 builder.ensure(llvm::Llvm { target: builder.config.host_target });
2170 if !builder.config.dry_run() {
2171 let llvm_version = get_llvm_version(builder, &host_llvm_config);
2172 let llvm_components = command(&host_llvm_config)
2173 .cached()
2174 .arg("--components")
2175 .run_capture_stdout(builder)
2176 .stdout();
2177 cmd.arg("--llvm-version")
2179 .arg(llvm_version.trim())
2180 .arg("--llvm-components")
2181 .arg(llvm_components.trim());
2182 llvm_components_passed = true;
2183 }
2184 if !builder.config.is_rust_llvm(target) {
2185 cmd.arg("--system-llvm");
2186 }
2187
2188 if !builder.config.dry_run() && suite.ends_with("fulldeps") {
2193 let llvm_libdir = command(&host_llvm_config)
2194 .cached()
2195 .arg("--libdir")
2196 .run_capture_stdout(builder)
2197 .stdout();
2198 let link_llvm = if target.is_msvc() {
2199 format!("-Clink-arg=-LIBPATH:{llvm_libdir}")
2200 } else {
2201 format!("-Clink-arg=-L{llvm_libdir}")
2202 };
2203 cmd.arg("--host-rustcflags").arg(link_llvm);
2204 }
2205
2206 if !builder.config.dry_run() && matches!(mode, "run-make" | "coverage-run") {
2207 let llvm_bin_path = host_llvm_config
2212 .parent()
2213 .expect("Expected llvm-config to be contained in directory");
2214 assert!(llvm_bin_path.is_dir());
2215 cmd.arg("--llvm-bin-dir").arg(llvm_bin_path);
2216 }
2217
2218 if !builder.config.dry_run() && mode == "run-make" {
2219 if builder.config.lld_enabled {
2221 let lld_install_root =
2222 builder.ensure(llvm::Lld { target: builder.config.host_target });
2223
2224 let lld_bin_path = lld_install_root.join("bin");
2225
2226 let old_path = env::var_os("PATH").unwrap_or_default();
2227 let new_path = env::join_paths(
2228 std::iter::once(lld_bin_path).chain(env::split_paths(&old_path)),
2229 )
2230 .expect("Could not add LLD bin path to PATH");
2231 cmd.env("PATH", new_path);
2232 }
2233 }
2234 }
2235
2236 if !builder.config.dry_run() && mode == "run-make" {
2239 let mut cflags = builder.cc_handled_clags(target, CLang::C);
2240 cflags.extend(builder.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::C));
2241 let mut cxxflags = builder.cc_handled_clags(target, CLang::Cxx);
2242 cxxflags.extend(builder.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::Cxx));
2243 cmd.arg("--cc")
2244 .arg(builder.cc(target))
2245 .arg("--cxx")
2246 .arg(builder.cxx(target).unwrap())
2247 .arg("--cflags")
2248 .arg(cflags.join(" "))
2249 .arg("--cxxflags")
2250 .arg(cxxflags.join(" "));
2251 copts_passed = true;
2252 if let Some(ar) = builder.ar(target) {
2253 cmd.arg("--ar").arg(ar);
2254 }
2255 }
2256
2257 if !llvm_components_passed {
2258 cmd.arg("--llvm-components").arg("");
2259 }
2260 if !copts_passed {
2261 cmd.arg("--cc")
2262 .arg("")
2263 .arg("--cxx")
2264 .arg("")
2265 .arg("--cflags")
2266 .arg("")
2267 .arg("--cxxflags")
2268 .arg("");
2269 }
2270
2271 if builder.remote_tested(target) {
2272 cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient));
2273 } else if let Some(tool) = builder.runner(target) {
2274 cmd.arg("--runner").arg(tool);
2275 }
2276
2277 if suite != "mir-opt" {
2278 if !builder.config.dry_run() && target.is_msvc() {
2284 for (k, v) in builder.cc[&target].env() {
2285 if k != "PATH" {
2286 cmd.env(k, v);
2287 }
2288 }
2289 }
2290 }
2291
2292 if !builder.config.dry_run()
2294 && target.contains("msvc")
2295 && builder.config.sanitizers_enabled(target)
2296 {
2297 cmd.env("ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE", "1");
2300 let asan_runtime_path = builder.cc[&target].path().parent().unwrap().to_path_buf();
2302 let old_path = cmd
2303 .get_envs()
2304 .find_map(|(k, v)| (k == "PATH").then_some(v))
2305 .flatten()
2306 .map_or_else(|| env::var_os("PATH").unwrap_or_default(), |v| v.to_owned());
2307 let new_path = env::join_paths(
2308 env::split_paths(&old_path).chain(std::iter::once(asan_runtime_path)),
2309 )
2310 .expect("Could not add ASAN runtime path to PATH");
2311 cmd.env("PATH", new_path);
2312 }
2313
2314 cmd.env_remove("CARGO");
2317
2318 cmd.env("RUSTC_BOOTSTRAP", "1");
2319 cmd.env("RUSTC_FORCE_RUSTC_VERSION", "compiletest");
2322 cmd.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
2323 builder.add_rust_test_threads(&mut cmd);
2324
2325 if builder.config.sanitizers_enabled(target) {
2326 cmd.env("RUSTC_SANITIZER_SUPPORT", "1");
2327 }
2328
2329 if builder.config.profiler_enabled(target) {
2330 cmd.arg("--profiler-runtime");
2331 }
2332
2333 cmd.env("RUST_TEST_TMPDIR", builder.tempdir());
2334
2335 if builder.config.cmd.rustfix_coverage() {
2336 cmd.arg("--rustfix-coverage");
2337 }
2338
2339 cmd.arg("--channel").arg(&builder.config.channel);
2340
2341 if !builder.config.omit_git_hash {
2342 cmd.arg("--git-hash");
2343 }
2344
2345 let git_config = builder.config.git_config();
2346 cmd.arg("--nightly-branch").arg(git_config.nightly_branch);
2347 cmd.arg("--git-merge-commit-email").arg(git_config.git_merge_commit_email);
2348 cmd.force_coloring_in_ci();
2349
2350 #[cfg(feature = "build-metrics")]
2351 builder.metrics.begin_test_suite(
2352 build_helper::metrics::TestSuiteMetadata::Compiletest {
2353 suite: suite.into(),
2354 mode: mode.into(),
2355 compare_mode: None,
2356 target: self.target.triple.to_string(),
2357 host: self.test_compiler.host.triple.to_string(),
2358 stage: self.test_compiler.stage,
2359 },
2360 builder,
2361 );
2362
2363 let _group = builder.msg_test(
2364 format!("with compiletest suite={suite} mode={mode}"),
2365 target,
2366 test_compiler.stage,
2367 );
2368 try_run_tests(builder, &mut cmd, false);
2369
2370 if let Some(compare_mode) = compare_mode {
2371 cmd.arg("--compare-mode").arg(compare_mode);
2372
2373 #[cfg(feature = "build-metrics")]
2374 builder.metrics.begin_test_suite(
2375 build_helper::metrics::TestSuiteMetadata::Compiletest {
2376 suite: suite.into(),
2377 mode: mode.into(),
2378 compare_mode: Some(compare_mode.into()),
2379 target: self.target.triple.to_string(),
2380 host: self.test_compiler.host.triple.to_string(),
2381 stage: self.test_compiler.stage,
2382 },
2383 builder,
2384 );
2385
2386 builder.info(&format!(
2387 "Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
2388 suite, mode, compare_mode, &test_compiler.host, target
2389 ));
2390 let _time = helpers::timeit(builder);
2391 try_run_tests(builder, &mut cmd, false);
2392 }
2393 }
2394
2395 fn metadata(&self) -> Option<StepMetadata> {
2396 Some(
2397 StepMetadata::test(&format!("compiletest-{}", self.suite), self.target)
2398 .stage(self.test_compiler.stage),
2399 )
2400 }
2401}
2402
2403#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2405struct BookTest {
2406 test_compiler: Compiler,
2407 path: PathBuf,
2408 name: &'static str,
2409 is_ext_doc: bool,
2410 dependencies: Vec<&'static str>,
2411}
2412
2413impl Step for BookTest {
2414 type Output = ();
2415 const IS_HOST: bool = true;
2416
2417 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2418 run.never()
2419 }
2420
2421 fn run(self, builder: &Builder<'_>) {
2422 if self.is_ext_doc {
2432 self.run_ext_doc(builder);
2433 } else {
2434 self.run_local_doc(builder);
2435 }
2436 }
2437}
2438
2439impl BookTest {
2440 fn run_ext_doc(self, builder: &Builder<'_>) {
2443 let test_compiler = self.test_compiler;
2444
2445 builder.std(test_compiler, test_compiler.host);
2446
2447 let mut rustdoc_path = builder.rustdoc_for_compiler(test_compiler);
2450 rustdoc_path.pop();
2451 let old_path = env::var_os("PATH").unwrap_or_default();
2452 let new_path = env::join_paths(iter::once(rustdoc_path).chain(env::split_paths(&old_path)))
2453 .expect("could not add rustdoc to PATH");
2454
2455 let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
2456 let path = builder.src.join(&self.path);
2457 rustbook_cmd.env("RUSTC_BOOTSTRAP", "1");
2459 rustbook_cmd.env("PATH", new_path).arg("test").arg(path);
2460
2461 let libs = if !self.dependencies.is_empty() {
2466 let mut lib_paths = vec![];
2467 for dep in self.dependencies {
2468 let mode = Mode::ToolRustcPrivate;
2469 let target = builder.config.host_target;
2470 let cargo = tool::prepare_tool_cargo(
2471 builder,
2472 test_compiler,
2473 mode,
2474 target,
2475 Kind::Build,
2476 dep,
2477 SourceType::Submodule,
2478 &[],
2479 );
2480
2481 let stamp = BuildStamp::new(&builder.cargo_out(test_compiler, mode, target))
2482 .with_prefix(PathBuf::from(dep).file_name().and_then(|v| v.to_str()).unwrap());
2483
2484 let output_paths = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false);
2485 let directories = output_paths
2486 .into_iter()
2487 .filter_map(|p| p.parent().map(ToOwned::to_owned))
2488 .fold(HashSet::new(), |mut set, dir| {
2489 set.insert(dir);
2490 set
2491 });
2492
2493 lib_paths.extend(directories);
2494 }
2495 lib_paths
2496 } else {
2497 vec![]
2498 };
2499
2500 if !libs.is_empty() {
2501 let paths = libs
2502 .into_iter()
2503 .map(|path| path.into_os_string())
2504 .collect::<Vec<OsString>>()
2505 .join(OsStr::new(","));
2506 rustbook_cmd.args([OsString::from("--library-path"), paths]);
2507 }
2508
2509 builder.add_rust_test_threads(&mut rustbook_cmd);
2510 let _guard = builder.msg_test(
2511 format_args!("mdbook {}", self.path.display()),
2512 test_compiler.host,
2513 test_compiler.stage,
2514 );
2515 let _time = helpers::timeit(builder);
2516 let toolstate = if rustbook_cmd.delay_failure().run(builder) {
2517 ToolState::TestPass
2518 } else {
2519 ToolState::TestFail
2520 };
2521 builder.save_toolstate(self.name, toolstate);
2522 }
2523
2524 fn run_local_doc(self, builder: &Builder<'_>) {
2526 let test_compiler = self.test_compiler;
2527 let host = self.test_compiler.host;
2528
2529 builder.std(test_compiler, host);
2530
2531 let _guard = builder.msg_test(
2532 format!("book {}", self.name),
2533 test_compiler.host,
2534 test_compiler.stage,
2535 );
2536
2537 let mut stack = vec![builder.src.join(self.path)];
2540 let _time = helpers::timeit(builder);
2541 let mut files = Vec::new();
2542 while let Some(p) = stack.pop() {
2543 if p.is_dir() {
2544 stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
2545 continue;
2546 }
2547
2548 if p.extension().and_then(|s| s.to_str()) != Some("md") {
2549 continue;
2550 }
2551
2552 files.push(p);
2553 }
2554
2555 files.sort();
2556
2557 for file in files {
2558 markdown_test(builder, test_compiler, &file);
2559 }
2560 }
2561}
2562
2563macro_rules! test_book {
2564 ($(
2565 $name:ident, $path:expr, $book_name:expr,
2566 default=$default:expr
2567 $(,submodules = $submodules:expr)?
2568 $(,dependencies=$dependencies:expr)?
2569 ;
2570 )+) => {
2571 $(
2572 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
2573 pub struct $name {
2574 test_compiler: Compiler,
2575 }
2576
2577 impl Step for $name {
2578 type Output = ();
2579 const DEFAULT: bool = $default;
2580 const IS_HOST: bool = true;
2581
2582 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2583 run.path($path)
2584 }
2585
2586 fn make_run(run: RunConfig<'_>) {
2587 run.builder.ensure($name {
2588 test_compiler: run.builder.compiler(run.builder.top_stage, run.target),
2589 });
2590 }
2591
2592 fn run(self, builder: &Builder<'_>) {
2593 $(
2594 for submodule in $submodules {
2595 builder.require_submodule(submodule, None);
2596 }
2597 )*
2598
2599 let dependencies = vec![];
2600 $(
2601 let mut dependencies = dependencies;
2602 for dep in $dependencies {
2603 dependencies.push(dep);
2604 }
2605 )?
2606
2607 builder.ensure(BookTest {
2608 test_compiler: self.test_compiler,
2609 path: PathBuf::from($path),
2610 name: $book_name,
2611 is_ext_doc: !$default,
2612 dependencies,
2613 });
2614 }
2615 }
2616 )+
2617 }
2618}
2619
2620test_book!(
2621 Nomicon, "src/doc/nomicon", "nomicon", default=false, submodules=["src/doc/nomicon"];
2622 Reference, "src/doc/reference", "reference", default=false, submodules=["src/doc/reference"];
2623 RustdocBook, "src/doc/rustdoc", "rustdoc", default=true;
2624 RustcBook, "src/doc/rustc", "rustc", default=true;
2625 RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false, submodules=["src/doc/rust-by-example"];
2626 EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false, submodules=["src/doc/embedded-book"];
2627 TheBook, "src/doc/book", "book", default=false, submodules=["src/doc/book"], dependencies=["src/doc/book/packages/trpl"];
2628 UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
2629 EditionGuide, "src/doc/edition-guide", "edition-guide", default=false, submodules=["src/doc/edition-guide"];
2630);
2631
2632#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2633pub struct ErrorIndex {
2634 compilers: RustcPrivateCompilers,
2635}
2636
2637impl Step for ErrorIndex {
2638 type Output = ();
2639 const DEFAULT: bool = true;
2640 const IS_HOST: bool = true;
2641
2642 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2643 run.path("src/tools/error_index_generator").alias("error-index")
2646 }
2647
2648 fn make_run(run: RunConfig<'_>) {
2649 let compilers = RustcPrivateCompilers::new(
2653 run.builder,
2654 run.builder.top_stage,
2655 run.builder.config.host_target,
2656 );
2657 run.builder.ensure(ErrorIndex { compilers });
2658 }
2659
2660 fn run(self, builder: &Builder<'_>) {
2667 let target_compiler = self.compilers.target_compiler();
2669
2670 let dir = testdir(builder, target_compiler.host);
2671 t!(fs::create_dir_all(&dir));
2672 let output = dir.join("error-index.md");
2673
2674 let mut tool = tool::ErrorIndex::command(builder, self.compilers);
2675 tool.arg("markdown").arg(&output);
2676
2677 let guard = builder.msg_test("error-index", target_compiler.host, target_compiler.stage);
2678 let _time = helpers::timeit(builder);
2679 tool.run_capture(builder);
2680 drop(guard);
2681 builder.std(target_compiler, target_compiler.host);
2684 markdown_test(builder, target_compiler, &output);
2685 }
2686}
2687
2688fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool {
2689 if let Ok(contents) = fs::read_to_string(markdown)
2690 && !contents.contains("```")
2691 {
2692 return true;
2693 }
2694
2695 builder.do_if_verbose(|| println!("doc tests for: {}", markdown.display()));
2696 let mut cmd = builder.rustdoc_cmd(compiler);
2697 builder.add_rust_test_threads(&mut cmd);
2698 cmd.arg("-Z");
2700 cmd.arg("unstable-options");
2701 cmd.arg("--test");
2702 cmd.arg(markdown);
2703 cmd.env("RUSTC_BOOTSTRAP", "1");
2704
2705 let test_args = builder.config.test_args().join(" ");
2706 cmd.arg("--test-args").arg(test_args);
2707
2708 cmd = cmd.delay_failure();
2709 if !builder.config.verbose_tests {
2710 cmd.run_capture(builder).is_success()
2711 } else {
2712 cmd.run(builder)
2713 }
2714}
2715
2716#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2721pub struct CrateLibrustc {
2722 build_compiler: Compiler,
2724 target: TargetSelection,
2725 crates: Vec<String>,
2726}
2727
2728impl Step for CrateLibrustc {
2729 type Output = ();
2730 const DEFAULT: bool = true;
2731 const IS_HOST: bool = true;
2732
2733 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2734 run.crate_or_deps("rustc-main").path("compiler")
2735 }
2736
2737 fn make_run(run: RunConfig<'_>) {
2738 let builder = run.builder;
2739 let host = run.build_triple();
2740 let build_compiler = builder.compiler(builder.top_stage - 1, host);
2741 let crates = run.make_run_crates(Alias::Compiler);
2742
2743 builder.ensure(CrateLibrustc { build_compiler, target: run.target, crates });
2744 }
2745
2746 fn run(self, builder: &Builder<'_>) {
2747 builder.std(self.build_compiler, self.target);
2748
2749 builder.ensure(Crate {
2751 build_compiler: self.build_compiler,
2752 target: self.target,
2753 mode: Mode::Rustc,
2754 crates: self.crates,
2755 });
2756 }
2757
2758 fn metadata(&self) -> Option<StepMetadata> {
2759 Some(StepMetadata::test("CrateLibrustc", self.target).built_by(self.build_compiler))
2760 }
2761}
2762
2763fn run_cargo_test<'a>(
2767 cargo: builder::Cargo,
2768 libtest_args: &[&str],
2769 crates: &[String],
2770 description: impl Into<Option<&'a str>>,
2771 target: TargetSelection,
2772 builder: &Builder<'_>,
2773) -> bool {
2774 let compiler = cargo.compiler();
2775 let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, target, builder);
2776 let _time = helpers::timeit(builder);
2777 let _group =
2778 description.into().and_then(|what| builder.msg_test(what, target, compiler.stage + 1));
2779
2780 #[cfg(feature = "build-metrics")]
2781 builder.metrics.begin_test_suite(
2782 build_helper::metrics::TestSuiteMetadata::CargoPackage {
2783 crates: crates.iter().map(|c| c.to_string()).collect(),
2784 target: target.triple.to_string(),
2785 host: compiler.host.triple.to_string(),
2786 stage: compiler.stage,
2787 },
2788 builder,
2789 );
2790 add_flags_and_try_run_tests(builder, &mut cargo)
2791}
2792
2793fn prepare_cargo_test(
2795 cargo: builder::Cargo,
2796 libtest_args: &[&str],
2797 crates: &[String],
2798 target: TargetSelection,
2799 builder: &Builder<'_>,
2800) -> BootstrapCommand {
2801 let compiler = cargo.compiler();
2802 let mut cargo: BootstrapCommand = cargo.into();
2803
2804 if builder.config.cmd.bless() && !cargo.get_envs().any(|v| v.0 == "RUSTC_BLESS") {
2808 cargo.env("RUSTC_BLESS", "Gesundheit");
2809 }
2810
2811 if builder.kind == Kind::Test && !builder.fail_fast {
2815 cargo.arg("--no-fail-fast");
2816 }
2817
2818 if builder.config.json_output {
2819 cargo.arg("--message-format=json");
2820 }
2821
2822 match builder.doc_tests {
2823 DocTests::Only => {
2824 cargo.arg("--doc");
2825 }
2826 DocTests::No => {
2827 cargo.args(["--bins", "--examples", "--tests", "--benches"]);
2828 }
2829 DocTests::Yes => {}
2830 }
2831
2832 for krate in crates {
2833 cargo.arg("-p").arg(krate);
2834 }
2835
2836 cargo.arg("--").args(builder.config.test_args()).args(libtest_args);
2837 if !builder.config.verbose_tests {
2838 cargo.arg("--quiet");
2839 }
2840
2841 if builder.kind != Kind::Miri {
2850 let mut dylib_paths = builder.rustc_lib_paths(compiler);
2851 dylib_paths.push(builder.sysroot_target_libdir(compiler, target));
2852 helpers::add_dylib_path(dylib_paths, &mut cargo);
2853 }
2854
2855 if builder.remote_tested(target) {
2856 cargo.env(
2857 format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
2858 format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
2859 );
2860 } else if let Some(tool) = builder.runner(target) {
2861 cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), tool);
2862 }
2863
2864 cargo
2865}
2866
2867#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2875pub struct Crate {
2876 build_compiler: Compiler,
2878 target: TargetSelection,
2879 mode: Mode,
2880 crates: Vec<String>,
2881}
2882
2883impl Step for Crate {
2884 type Output = ();
2885 const DEFAULT: bool = true;
2886
2887 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2888 run.crate_or_deps("sysroot").crate_or_deps("coretests").crate_or_deps("alloctests")
2889 }
2890
2891 fn make_run(run: RunConfig<'_>) {
2892 let builder = run.builder;
2893 let host = run.build_triple();
2894 let build_compiler = builder.compiler(builder.top_stage, host);
2895 let crates = run
2896 .paths
2897 .iter()
2898 .map(|p| builder.crate_paths[&p.assert_single_path().path].clone())
2899 .collect();
2900
2901 builder.ensure(Crate { build_compiler, target: run.target, mode: Mode::Std, crates });
2902 }
2903
2904 fn run(self, builder: &Builder<'_>) {
2913 let build_compiler = self.build_compiler;
2914 let target = self.target;
2915 let mode = self.mode;
2916
2917 builder.ensure(Std::new(build_compiler, build_compiler.host).force_recompile(true));
2920
2921 let mut cargo = if builder.kind == Kind::Miri {
2922 if builder.top_stage == 0 {
2923 eprintln!("ERROR: `x.py miri` requires stage 1 or higher");
2924 std::process::exit(1);
2925 }
2926
2927 let mut cargo = builder::Cargo::new(
2930 builder,
2931 build_compiler,
2932 mode,
2933 SourceType::InTree,
2934 target,
2935 Kind::MiriTest,
2936 );
2937 cargo.env("MIRI_REPLACE_LIBRS_IF_NOT_TEST", "1");
2949 cargo.rustflag("-Zforce-unstable-if-unmarked");
2953 cargo
2954 } else {
2955 if !builder.config.is_host_target(target) {
2957 builder.ensure(compile::Std::new(build_compiler, target).force_recompile(true));
2958 builder.ensure(RemoteCopyLibs { build_compiler, target });
2959 }
2960
2961 builder::Cargo::new(
2963 builder,
2964 build_compiler,
2965 mode,
2966 SourceType::InTree,
2967 target,
2968 builder.kind,
2969 )
2970 };
2971
2972 match mode {
2973 Mode::Std => {
2974 if builder.kind == Kind::Miri {
2975 cargo
2981 .arg("--manifest-path")
2982 .arg(builder.src.join("library/sysroot/Cargo.toml"));
2983 } else {
2984 compile::std_cargo(builder, target, &mut cargo, &[]);
2985 }
2986 }
2987 Mode::Rustc => {
2988 compile::rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
2989 }
2990 _ => panic!("can only test libraries"),
2991 };
2992
2993 let mut crates = self.crates.clone();
2994 if crates.iter().any(|crate_| crate_ == "core") {
2999 crates.push("coretests".to_owned());
3000 }
3001 if crates.iter().any(|crate_| crate_ == "alloc") {
3002 crates.push("alloctests".to_owned());
3003 }
3004
3005 run_cargo_test(cargo, &[], &crates, &*crate_description(&self.crates), target, builder);
3006 }
3007}
3008
3009#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3012pub struct CrateRustdoc {
3013 host: TargetSelection,
3014}
3015
3016impl Step for CrateRustdoc {
3017 type Output = ();
3018 const DEFAULT: bool = true;
3019 const IS_HOST: bool = true;
3020
3021 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3022 run.paths(&["src/librustdoc", "src/tools/rustdoc"])
3023 }
3024
3025 fn make_run(run: RunConfig<'_>) {
3026 let builder = run.builder;
3027
3028 builder.ensure(CrateRustdoc { host: run.target });
3029 }
3030
3031 fn run(self, builder: &Builder<'_>) {
3032 let target = self.host;
3033
3034 let compiler = if builder.download_rustc() {
3035 builder.compiler(builder.top_stage, target)
3036 } else {
3037 builder.compiler_for(builder.top_stage, target, target)
3042 };
3043 builder.std(compiler, target);
3048 builder.ensure(compile::Rustc::new(compiler, target));
3049
3050 let mut cargo = tool::prepare_tool_cargo(
3051 builder,
3052 compiler,
3053 Mode::ToolRustcPrivate,
3054 target,
3055 builder.kind,
3056 "src/tools/rustdoc",
3057 SourceType::InTree,
3058 &[],
3059 );
3060 if self.host.contains("musl") {
3061 cargo.arg("'-Ctarget-feature=-crt-static'");
3062 }
3063
3064 let libdir = if builder.download_rustc() {
3091 builder.rustc_libdir(compiler)
3092 } else {
3093 builder.sysroot_target_libdir(compiler, target).to_path_buf()
3094 };
3095 let mut dylib_path = dylib_path();
3096 dylib_path.insert(0, PathBuf::from(&*libdir));
3097 cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
3098
3099 run_cargo_test(cargo, &[], &["rustdoc:0.0.0".to_string()], "rustdoc", target, builder);
3100 }
3101}
3102
3103#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3104pub struct CrateRustdocJsonTypes {
3105 build_compiler: Compiler,
3106 target: TargetSelection,
3107}
3108
3109impl Step for CrateRustdocJsonTypes {
3110 type Output = ();
3111 const DEFAULT: bool = true;
3112 const IS_HOST: bool = true;
3113
3114 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3115 run.path("src/rustdoc-json-types")
3116 }
3117
3118 fn make_run(run: RunConfig<'_>) {
3119 let builder = run.builder;
3120
3121 builder.ensure(CrateRustdocJsonTypes {
3122 build_compiler: get_tool_target_compiler(
3123 builder,
3124 ToolTargetBuildMode::Build(run.target),
3125 ),
3126 target: run.target,
3127 });
3128 }
3129
3130 fn run(self, builder: &Builder<'_>) {
3131 let target = self.target;
3132
3133 let cargo = tool::prepare_tool_cargo(
3134 builder,
3135 self.build_compiler,
3136 Mode::ToolTarget,
3137 target,
3138 builder.kind,
3139 "src/rustdoc-json-types",
3140 SourceType::InTree,
3141 &[],
3142 );
3143
3144 let libtest_args = if target.contains("musl") {
3146 ["'-Ctarget-feature=-crt-static'"].as_slice()
3147 } else {
3148 &[]
3149 };
3150
3151 run_cargo_test(
3152 cargo,
3153 libtest_args,
3154 &["rustdoc-json-types".to_string()],
3155 "rustdoc-json-types",
3156 target,
3157 builder,
3158 );
3159 }
3160}
3161
3162#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3172pub struct RemoteCopyLibs {
3173 build_compiler: Compiler,
3174 target: TargetSelection,
3175}
3176
3177impl Step for RemoteCopyLibs {
3178 type Output = ();
3179
3180 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3181 run.never()
3182 }
3183
3184 fn run(self, builder: &Builder<'_>) {
3185 let build_compiler = self.build_compiler;
3186 let target = self.target;
3187 if !builder.remote_tested(target) {
3188 return;
3189 }
3190
3191 builder.std(build_compiler, target);
3192
3193 builder.info(&format!("REMOTE copy libs to emulator ({target})"));
3194
3195 let remote_test_server = builder.ensure(tool::RemoteTestServer { build_compiler, target });
3196
3197 let tool = builder.tool_exe(Tool::RemoteTestClient);
3199 let mut cmd = command(&tool);
3200 cmd.arg("spawn-emulator")
3201 .arg(target.triple)
3202 .arg(&remote_test_server.tool_path)
3203 .arg(builder.tempdir());
3204 if let Some(rootfs) = builder.qemu_rootfs(target) {
3205 cmd.arg(rootfs);
3206 }
3207 cmd.run(builder);
3208
3209 for f in t!(builder.sysroot_target_libdir(build_compiler, target).read_dir()) {
3211 let f = t!(f);
3212 if helpers::is_dylib(&f.path()) {
3213 command(&tool).arg("push").arg(f.path()).run(builder);
3214 }
3215 }
3216 }
3217}
3218
3219#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3220pub struct Distcheck;
3221
3222impl Step for Distcheck {
3223 type Output = ();
3224
3225 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3226 run.alias("distcheck")
3227 }
3228
3229 fn make_run(run: RunConfig<'_>) {
3230 run.builder.ensure(Distcheck);
3231 }
3232
3233 fn run(self, builder: &Builder<'_>) {
3243 let root_dir = std::env::temp_dir().join("distcheck");
3246
3247 distcheck_plain_source_tarball(builder, &root_dir.join("distcheck-rustc-src"));
3248 distcheck_rust_src(builder, &root_dir.join("distcheck-rust-src"));
3249 distcheck_rustc_dev(builder, &root_dir.join("distcheck-rustc-dev"));
3250 }
3251}
3252
3253fn distcheck_plain_source_tarball(builder: &Builder<'_>, plain_src_dir: &Path) {
3255 builder.info("Distcheck plain source tarball");
3256 let plain_src_tarball = builder.ensure(dist::PlainSourceTarball);
3257 builder.clear_dir(plain_src_dir);
3258
3259 let configure_args: Vec<String> = std::env::var("DISTCHECK_CONFIGURE_ARGS")
3260 .map(|args| args.split(" ").map(|s| s.to_string()).collect::<Vec<String>>())
3261 .unwrap_or_default();
3262
3263 command("tar")
3264 .arg("-xf")
3265 .arg(plain_src_tarball.tarball())
3266 .arg("--strip-components=1")
3267 .current_dir(plain_src_dir)
3268 .run(builder);
3269 command("./configure")
3270 .arg("--set")
3271 .arg("rust.omit-git-hash=false")
3272 .args(&configure_args)
3273 .arg("--enable-vendor")
3274 .current_dir(plain_src_dir)
3275 .run(builder);
3276 command(helpers::make(&builder.config.host_target.triple))
3277 .arg("check")
3278 .env("GITHUB_ACTIONS", "0")
3281 .current_dir(plain_src_dir)
3282 .run(builder);
3283 builder.remove_dir(plain_src_dir);
3285}
3286
3287fn distcheck_rust_src(builder: &Builder<'_>, src_dir: &Path) {
3289 builder.info("Distcheck rust-src");
3290 let src_tarball = builder.ensure(dist::Src);
3291 builder.clear_dir(src_dir);
3292
3293 command("tar")
3294 .arg("-xf")
3295 .arg(src_tarball.tarball())
3296 .arg("--strip-components=1")
3297 .current_dir(src_dir)
3298 .run(builder);
3299
3300 let toml = src_dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml");
3301 command(&builder.initial_cargo)
3302 .env("RUSTC_BOOTSTRAP", "1")
3305 .arg("generate-lockfile")
3306 .arg("--manifest-path")
3307 .arg(&toml)
3308 .current_dir(src_dir)
3309 .run(builder);
3310 builder.remove_dir(src_dir);
3312}
3313
3314fn distcheck_rustc_dev(builder: &Builder<'_>, dir: &Path) {
3316 builder.info("Distcheck rustc-dev");
3317 let tarball = builder.ensure(dist::RustcDev::new(builder, builder.host_target)).unwrap();
3318 builder.clear_dir(dir);
3319
3320 command("tar")
3321 .arg("-xf")
3322 .arg(tarball.tarball())
3323 .arg("--strip-components=1")
3324 .current_dir(dir)
3325 .run(builder);
3326
3327 command(&builder.initial_cargo)
3328 .arg("metadata")
3329 .arg("--manifest-path")
3330 .arg("rustc-dev/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml")
3331 .env("RUSTC_BOOTSTRAP", "1")
3332 .env("RUSTC", &builder.initial_rustc)
3334 .current_dir(dir)
3335 .run(builder);
3336 builder.remove_dir(dir);
3338}
3339
3340#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3342pub(crate) struct BootstrapPy;
3343
3344impl Step for BootstrapPy {
3345 type Output = ();
3346 const DEFAULT: bool = true;
3347 const IS_HOST: bool = true;
3348
3349 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3350 let is_ci = run.builder.config.is_running_on_ci;
3354 run.alias("bootstrap-py").default_condition(is_ci)
3355 }
3356
3357 fn make_run(run: RunConfig<'_>) {
3358 run.builder.ensure(BootstrapPy)
3359 }
3360
3361 fn run(self, builder: &Builder<'_>) -> Self::Output {
3362 let mut check_bootstrap = command(builder.python());
3363 check_bootstrap
3364 .args(["-m", "unittest", "bootstrap_test.py"])
3365 .args(builder.config.test_args())
3367 .env("BUILD_DIR", &builder.out)
3368 .env("BUILD_PLATFORM", builder.build.host_target.triple)
3369 .env("BOOTSTRAP_TEST_RUSTC_BIN", &builder.initial_rustc)
3370 .env("BOOTSTRAP_TEST_CARGO_BIN", &builder.initial_cargo)
3371 .current_dir(builder.src.join("src/bootstrap/"));
3372 check_bootstrap.delay_failure().run(builder);
3373 }
3374}
3375
3376#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3377pub struct Bootstrap;
3378
3379impl Step for Bootstrap {
3380 type Output = ();
3381 const DEFAULT: bool = true;
3382 const IS_HOST: bool = true;
3383
3384 fn run(self, builder: &Builder<'_>) {
3386 let host = builder.config.host_target;
3387 let build_compiler = builder.compiler(0, host);
3388
3389 builder.build.require_submodule("src/tools/cargo", None);
3391
3392 let mut cargo = tool::prepare_tool_cargo(
3393 builder,
3394 build_compiler,
3395 Mode::ToolBootstrap,
3396 host,
3397 Kind::Test,
3398 "src/bootstrap",
3399 SourceType::InTree,
3400 &[],
3401 );
3402
3403 cargo.release_build(false);
3404
3405 cargo
3406 .rustflag("-Cdebuginfo=2")
3407 .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
3408 .env("INSTA_WORKSPACE_ROOT", &builder.src)
3410 .env("RUSTC_BOOTSTRAP", "1");
3411
3412 run_cargo_test(cargo, &[], &[], None, host, builder);
3413 }
3414
3415 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3416 let runs_on_ci = run.builder.config.is_running_on_ci;
3420 run.path("src/bootstrap").default_condition(runs_on_ci)
3421 }
3422
3423 fn make_run(run: RunConfig<'_>) {
3424 run.builder.ensure(Bootstrap);
3425 }
3426}
3427
3428fn get_compiler_to_test(builder: &Builder<'_>, target: TargetSelection) -> Compiler {
3429 builder.compiler(builder.top_stage, target)
3430}
3431
3432#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3435pub struct TierCheck {
3436 test_compiler: Compiler,
3437}
3438
3439impl Step for TierCheck {
3440 type Output = ();
3441 const DEFAULT: bool = true;
3442 const IS_HOST: bool = true;
3443
3444 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3445 run.path("src/tools/tier-check")
3446 }
3447
3448 fn make_run(run: RunConfig<'_>) {
3449 run.builder
3450 .ensure(TierCheck { test_compiler: get_compiler_to_test(run.builder, run.target) });
3451 }
3452
3453 fn run(self, builder: &Builder<'_>) {
3454 let tool_build_compiler = builder.compiler(0, builder.host_target);
3455
3456 let mut cargo = tool::prepare_tool_cargo(
3457 builder,
3458 tool_build_compiler,
3459 Mode::ToolBootstrap,
3460 tool_build_compiler.host,
3461 Kind::Run,
3462 "src/tools/tier-check",
3463 SourceType::InTree,
3464 &[],
3465 );
3466 cargo.arg(builder.src.join("src/doc/rustc/src/platform-support.md"));
3467 cargo.arg(builder.rustc(self.test_compiler));
3468
3469 let _guard = builder.msg_test(
3470 "platform support check",
3471 self.test_compiler.host,
3472 self.test_compiler.stage,
3473 );
3474 BootstrapCommand::from(cargo).delay_failure().run(builder);
3475 }
3476
3477 fn metadata(&self) -> Option<StepMetadata> {
3478 Some(StepMetadata::test("tier-check", self.test_compiler.host))
3479 }
3480}
3481
3482#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3483pub struct LintDocs {
3484 build_compiler: Compiler,
3485 target: TargetSelection,
3486}
3487
3488impl Step for LintDocs {
3489 type Output = ();
3490 const DEFAULT: bool = true;
3491 const IS_HOST: bool = true;
3492
3493 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3494 let stage = run.builder.top_stage;
3495 run.path("src/tools/lint-docs").default_condition(stage > 1)
3498 }
3499
3500 fn make_run(run: RunConfig<'_>) {
3501 if run.builder.top_stage < 2 {
3502 eprintln!("WARNING: lint-docs tests might not work below stage 2");
3503 }
3504
3505 run.builder.ensure(LintDocs {
3506 build_compiler: prepare_doc_compiler(
3507 run.builder,
3508 run.builder.config.host_target,
3509 run.builder.top_stage,
3510 ),
3511 target: run.target,
3512 });
3513 }
3514
3515 fn run(self, builder: &Builder<'_>) {
3518 builder.ensure(crate::core::build_steps::doc::RustcBook::validate(
3519 self.build_compiler,
3520 self.target,
3521 ));
3522 }
3523
3524 fn metadata(&self) -> Option<StepMetadata> {
3525 Some(StepMetadata::test("lint-docs", self.target).built_by(self.build_compiler))
3526 }
3527}
3528
3529#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3530pub struct RustInstaller;
3531
3532impl Step for RustInstaller {
3533 type Output = ();
3534 const IS_HOST: bool = true;
3535 const DEFAULT: bool = true;
3536
3537 fn run(self, builder: &Builder<'_>) {
3539 let bootstrap_host = builder.config.host_target;
3540 let build_compiler = builder.compiler(0, bootstrap_host);
3541 let cargo = tool::prepare_tool_cargo(
3542 builder,
3543 build_compiler,
3544 Mode::ToolBootstrap,
3545 bootstrap_host,
3546 Kind::Test,
3547 "src/tools/rust-installer",
3548 SourceType::InTree,
3549 &[],
3550 );
3551
3552 let _guard = builder.msg_test("rust-installer", bootstrap_host, 1);
3553 run_cargo_test(cargo, &[], &[], None, bootstrap_host, builder);
3554
3555 if bootstrap_host != "x86_64-unknown-linux-gnu" {
3559 return;
3560 }
3561
3562 let mut cmd = command(builder.src.join("src/tools/rust-installer/test.sh"));
3563 let tmpdir = testdir(builder, build_compiler.host).join("rust-installer");
3564 let _ = std::fs::remove_dir_all(&tmpdir);
3565 let _ = std::fs::create_dir_all(&tmpdir);
3566 cmd.current_dir(&tmpdir);
3567 cmd.env("CARGO_TARGET_DIR", tmpdir.join("cargo-target"));
3568 cmd.env("CARGO", &builder.initial_cargo);
3569 cmd.env("RUSTC", &builder.initial_rustc);
3570 cmd.env("TMP_DIR", &tmpdir);
3571 cmd.delay_failure().run(builder);
3572 }
3573
3574 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3575 run.path("src/tools/rust-installer")
3576 }
3577
3578 fn make_run(run: RunConfig<'_>) {
3579 run.builder.ensure(Self);
3580 }
3581}
3582
3583#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3584pub struct TestHelpers {
3585 pub target: TargetSelection,
3586}
3587
3588impl Step for TestHelpers {
3589 type Output = ();
3590
3591 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3592 run.path("tests/auxiliary/rust_test_helpers.c")
3593 }
3594
3595 fn make_run(run: RunConfig<'_>) {
3596 run.builder.ensure(TestHelpers { target: run.target })
3597 }
3598
3599 fn run(self, builder: &Builder<'_>) {
3602 if builder.config.dry_run() {
3603 return;
3604 }
3605 let target = if self.target == "x86_64-fortanix-unknown-sgx" {
3609 TargetSelection::from_user("x86_64-unknown-linux-gnu")
3610 } else {
3611 self.target
3612 };
3613 let dst = builder.test_helpers_out(target);
3614 let src = builder.src.join("tests/auxiliary/rust_test_helpers.c");
3615 if up_to_date(&src, &dst.join("librust_test_helpers.a")) {
3616 return;
3617 }
3618
3619 let _guard = builder.msg_unstaged(Kind::Build, "test helpers", target);
3620 t!(fs::create_dir_all(&dst));
3621 let mut cfg = cc::Build::new();
3622
3623 if !target.is_msvc() {
3627 if let Some(ar) = builder.ar(target) {
3628 cfg.archiver(ar);
3629 }
3630 cfg.compiler(builder.cc(target));
3631 }
3632 cfg.cargo_metadata(false)
3633 .out_dir(&dst)
3634 .target(&target.triple)
3635 .host(&builder.config.host_target.triple)
3636 .opt_level(0)
3637 .warnings(false)
3638 .debug(false)
3639 .file(builder.src.join("tests/auxiliary/rust_test_helpers.c"))
3640 .compile("rust_test_helpers");
3641 }
3642}
3643
3644#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3645pub struct CodegenCranelift {
3646 compilers: RustcPrivateCompilers,
3647 target: TargetSelection,
3648}
3649
3650impl Step for CodegenCranelift {
3651 type Output = ();
3652 const DEFAULT: bool = true;
3653 const IS_HOST: bool = true;
3654
3655 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3656 run.paths(&["compiler/rustc_codegen_cranelift"])
3657 }
3658
3659 fn make_run(run: RunConfig<'_>) {
3660 let builder = run.builder;
3661 let host = run.build_triple();
3662 let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, host);
3663
3664 if builder.doc_tests == DocTests::Only {
3665 return;
3666 }
3667
3668 if builder.download_rustc() {
3669 builder.info("CI rustc uses the default codegen backend. skipping");
3670 return;
3671 }
3672
3673 if !target_supports_cranelift_backend(run.target) {
3674 builder.info("target not supported by rustc_codegen_cranelift. skipping");
3675 return;
3676 }
3677
3678 if builder.remote_tested(run.target) {
3679 builder.info("remote testing is not supported by rustc_codegen_cranelift. skipping");
3680 return;
3681 }
3682
3683 if !builder
3684 .config
3685 .enabled_codegen_backends(run.target)
3686 .contains(&CodegenBackendKind::Cranelift)
3687 {
3688 builder.info("cranelift not in rust.codegen-backends. skipping");
3689 return;
3690 }
3691
3692 builder.ensure(CodegenCranelift { compilers, target: run.target });
3693 }
3694
3695 fn run(self, builder: &Builder<'_>) {
3696 let compilers = self.compilers;
3697 let build_compiler = compilers.build_compiler();
3698
3699 let target_compiler = compilers.target_compiler();
3702 let target = self.target;
3703
3704 builder.std(target_compiler, target);
3705
3706 let mut cargo = builder::Cargo::new(
3707 builder,
3708 target_compiler,
3709 Mode::Codegen, SourceType::InTree,
3711 target,
3712 Kind::Run,
3713 );
3714
3715 cargo.current_dir(&builder.src.join("compiler/rustc_codegen_cranelift"));
3716 cargo
3717 .arg("--manifest-path")
3718 .arg(builder.src.join("compiler/rustc_codegen_cranelift/build_system/Cargo.toml"));
3719 compile::rustc_cargo_env(builder, &mut cargo, target);
3720
3721 cargo.env("CARGO_BUILD_INCREMENTAL", "false");
3723
3724 let _guard = builder.msg_test(
3725 "rustc_codegen_cranelift",
3726 target_compiler.host,
3727 target_compiler.stage,
3728 );
3729
3730 let download_dir = builder.out.join("cg_clif_download");
3732
3733 cargo
3734 .arg("--")
3735 .arg("test")
3736 .arg("--download-dir")
3737 .arg(&download_dir)
3738 .arg("--out-dir")
3739 .arg(builder.stage_out(build_compiler, Mode::Codegen).join("cg_clif"))
3740 .arg("--no-unstable-features")
3741 .arg("--use-backend")
3742 .arg("cranelift")
3743 .arg("--sysroot")
3745 .arg("llvm")
3746 .arg("--skip-test")
3749 .arg("testsuite.extended_sysroot");
3750
3751 cargo.into_cmd().run(builder);
3752 }
3753
3754 fn metadata(&self) -> Option<StepMetadata> {
3755 Some(
3756 StepMetadata::test("rustc_codegen_cranelift", self.target)
3757 .built_by(self.compilers.build_compiler()),
3758 )
3759 }
3760}
3761
3762#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3763pub struct CodegenGCC {
3764 compilers: RustcPrivateCompilers,
3765 target: TargetSelection,
3766}
3767
3768impl Step for CodegenGCC {
3769 type Output = ();
3770 const DEFAULT: bool = true;
3771 const IS_HOST: bool = true;
3772
3773 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3774 run.paths(&["compiler/rustc_codegen_gcc"])
3775 }
3776
3777 fn make_run(run: RunConfig<'_>) {
3778 let builder = run.builder;
3779 let host = run.build_triple();
3780 let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, host);
3781
3782 if builder.doc_tests == DocTests::Only {
3783 return;
3784 }
3785
3786 if builder.download_rustc() {
3787 builder.info("CI rustc uses the default codegen backend. skipping");
3788 return;
3789 }
3790
3791 let triple = run.target.triple;
3792 let target_supported =
3793 if triple.contains("linux") { triple.contains("x86_64") } else { false };
3794 if !target_supported {
3795 builder.info("target not supported by rustc_codegen_gcc. skipping");
3796 return;
3797 }
3798
3799 if builder.remote_tested(run.target) {
3800 builder.info("remote testing is not supported by rustc_codegen_gcc. skipping");
3801 return;
3802 }
3803
3804 if !builder.config.enabled_codegen_backends(run.target).contains(&CodegenBackendKind::Gcc) {
3805 builder.info("gcc not in rust.codegen-backends. skipping");
3806 return;
3807 }
3808
3809 builder.ensure(CodegenGCC { compilers, target: run.target });
3810 }
3811
3812 fn run(self, builder: &Builder<'_>) {
3813 let compilers = self.compilers;
3814 let target = self.target;
3815
3816 let gcc = builder.ensure(Gcc { target });
3817
3818 builder.ensure(
3819 compile::Std::new(compilers.build_compiler(), target)
3820 .extra_rust_args(&["-Csymbol-mangling-version=v0", "-Cpanic=abort"]),
3821 );
3822
3823 let _guard = builder.msg_test(
3824 "rustc_codegen_gcc",
3825 compilers.target(),
3826 compilers.target_compiler().stage,
3827 );
3828
3829 let mut cargo = builder::Cargo::new(
3830 builder,
3831 compilers.build_compiler(),
3832 Mode::Codegen, SourceType::InTree,
3834 target,
3835 Kind::Run,
3836 );
3837
3838 cargo.current_dir(&builder.src.join("compiler/rustc_codegen_gcc"));
3839 cargo
3840 .arg("--manifest-path")
3841 .arg(builder.src.join("compiler/rustc_codegen_gcc/build_system/Cargo.toml"));
3842 compile::rustc_cargo_env(builder, &mut cargo, target);
3843 add_cg_gcc_cargo_flags(&mut cargo, &gcc);
3844
3845 cargo.env("CARGO_BUILD_INCREMENTAL", "false");
3847 cargo.rustflag("-Cpanic=abort");
3848
3849 cargo
3850 .env("CG_RUSTFLAGS", "-Alinker-messages")
3852 .arg("--")
3853 .arg("test")
3854 .arg("--use-backend")
3855 .arg("gcc")
3856 .arg("--gcc-path")
3857 .arg(gcc.libgccjit.parent().unwrap())
3858 .arg("--out-dir")
3859 .arg(builder.stage_out(compilers.build_compiler(), Mode::Codegen).join("cg_gcc"))
3860 .arg("--release")
3861 .arg("--mini-tests")
3862 .arg("--std-tests");
3863 cargo.args(builder.config.test_args());
3864
3865 cargo.into_cmd().run(builder);
3866 }
3867
3868 fn metadata(&self) -> Option<StepMetadata> {
3869 Some(
3870 StepMetadata::test("rustc_codegen_gcc", self.target)
3871 .built_by(self.compilers.build_compiler()),
3872 )
3873 }
3874}
3875
3876#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3881pub struct TestFloatParse {
3882 build_compiler: Compiler,
3891 target: TargetSelection,
3893}
3894
3895impl Step for TestFloatParse {
3896 type Output = ();
3897 const IS_HOST: bool = true;
3898 const DEFAULT: bool = true;
3899
3900 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3901 run.path("src/tools/test-float-parse")
3902 }
3903
3904 fn make_run(run: RunConfig<'_>) {
3905 run.builder.ensure(Self {
3906 build_compiler: get_compiler_to_test(run.builder, run.target),
3907 target: run.target,
3908 });
3909 }
3910
3911 fn run(self, builder: &Builder<'_>) {
3912 let build_compiler = self.build_compiler;
3913 let target = self.target;
3914
3915 builder.std(build_compiler, target);
3917 builder.std(build_compiler, builder.host_target);
3918
3919 let mut cargo_test = tool::prepare_tool_cargo(
3921 builder,
3922 build_compiler,
3923 Mode::ToolStd,
3924 target,
3925 Kind::Test,
3926 "src/tools/test-float-parse",
3927 SourceType::InTree,
3928 &[],
3929 );
3930 cargo_test.allow_features(TEST_FLOAT_PARSE_ALLOW_FEATURES);
3931
3932 run_cargo_test(cargo_test, &[], &[], "test-float-parse", target, builder);
3933
3934 let mut cargo_run = tool::prepare_tool_cargo(
3936 builder,
3937 build_compiler,
3938 Mode::ToolStd,
3939 target,
3940 Kind::Run,
3941 "src/tools/test-float-parse",
3942 SourceType::InTree,
3943 &[],
3944 );
3945 cargo_run.allow_features(TEST_FLOAT_PARSE_ALLOW_FEATURES);
3946
3947 if !matches!(env::var("FLOAT_PARSE_TESTS_NO_SKIP_HUGE").as_deref(), Ok("1") | Ok("true")) {
3948 cargo_run.args(["--", "--skip-huge"]);
3949 }
3950
3951 cargo_run.into_cmd().run(builder);
3952 }
3953}
3954
3955#[derive(Debug, Clone, Hash, PartialEq, Eq)]
3959pub struct CollectLicenseMetadata;
3960
3961impl Step for CollectLicenseMetadata {
3962 type Output = PathBuf;
3963 const IS_HOST: bool = true;
3964
3965 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3966 run.path("src/tools/collect-license-metadata")
3967 }
3968
3969 fn make_run(run: RunConfig<'_>) {
3970 run.builder.ensure(CollectLicenseMetadata);
3971 }
3972
3973 fn run(self, builder: &Builder<'_>) -> Self::Output {
3974 let Some(reuse) = &builder.config.reuse else {
3975 panic!("REUSE is required to collect the license metadata");
3976 };
3977
3978 let dest = builder.src.join("license-metadata.json");
3979
3980 let mut cmd = builder.tool_cmd(Tool::CollectLicenseMetadata);
3981 cmd.env("REUSE_EXE", reuse);
3982 cmd.env("DEST", &dest);
3983 cmd.env("ONLY_CHECK", "1");
3984 cmd.run(builder);
3985
3986 dest
3987 }
3988}