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