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