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