1use std::collections::HashSet;
7use std::env::split_paths;
8use std::ffi::{OsStr, OsString};
9use std::path::{Path, PathBuf};
10use std::{env, fs, iter};
11
12use build_helper::exit;
13#[cfg(feature = "tracing")]
14use tracing::instrument;
15
16use crate::core::build_steps::compile::{Std, run_cargo};
17use crate::core::build_steps::doc::DocumentationFormat;
18use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags};
19use crate::core::build_steps::llvm::get_llvm_version;
20use crate::core::build_steps::run::get_completion_paths;
21use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
22use crate::core::build_steps::tool::{
23 self, COMPILETEST_ALLOW_FEATURES, RustcPrivateCompilers, SourceType, Tool, ToolTargetBuildMode,
24 get_tool_target_compiler,
25};
26use crate::core::build_steps::toolstate::ToolState;
27use crate::core::build_steps::{compile, dist, llvm};
28use crate::core::builder::{
29 self, Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step, StepMetadata,
30 crate_description,
31};
32use crate::core::config::TargetSelection;
33use crate::core::config::flags::{Subcommand, get_completion};
34use crate::utils::build_stamp::{self, BuildStamp};
35use crate::utils::exec::{BootstrapCommand, command};
36use crate::utils::helpers::{
37 self, LldThreads, add_dylib_path, add_rustdoc_cargo_linker_args, dylib_path, dylib_path_var,
38 linker_args, linker_flags, t, target_supports_cranelift_backend, up_to_date,
39};
40use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests};
41use crate::{CLang, CodegenBackendKind, DocTests, GitRepo, Mode, PathSet, debug, envify};
42
43const ADB_TEST_DIR: &str = "/data/local/tmp/work";
44
45#[derive(Debug, Clone, PartialEq, Eq, Hash)]
47pub struct CrateBootstrap {
48 path: PathBuf,
49 host: TargetSelection,
50}
51
52impl Step for CrateBootstrap {
53 type Output = ();
54 const ONLY_HOSTS: bool = true;
55 const DEFAULT: bool = true;
56
57 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
58 run.path("src/tools/jsondoclint")
63 .path("src/tools/replace-version-placeholder")
64 .path("src/tools/coverage-dump")
65 .alias("tidyselftest")
68 }
69
70 fn make_run(run: RunConfig<'_>) {
71 for path in run.paths {
74 let path = path.assert_single_path().path.clone();
75 run.builder.ensure(CrateBootstrap { host: run.target, path });
76 }
77 }
78
79 fn run(self, builder: &Builder<'_>) {
80 let bootstrap_host = builder.config.host_target;
81 let compiler = builder.compiler(0, bootstrap_host);
82 let mut path = self.path.to_str().unwrap();
83
84 if path == "tidyselftest" {
86 path = "src/tools/tidy";
87 }
88
89 let cargo = tool::prepare_tool_cargo(
90 builder,
91 compiler,
92 Mode::ToolBootstrap,
93 bootstrap_host,
94 Kind::Test,
95 path,
96 SourceType::InTree,
97 &[],
98 );
99
100 let crate_name = path.rsplit_once('/').unwrap().1;
101 run_cargo_test(cargo, &[], &[], crate_name, bootstrap_host, builder);
102 }
103}
104
105#[derive(Debug, Clone, PartialEq, Eq, Hash)]
106pub struct Linkcheck {
107 host: TargetSelection,
108}
109
110impl Step for Linkcheck {
111 type Output = ();
112 const ONLY_HOSTS: bool = true;
113 const DEFAULT: bool = true;
114
115 fn run(self, builder: &Builder<'_>) {
120 let host = self.host;
121 let hosts = &builder.hosts;
122 let targets = &builder.targets;
123
124 if (hosts != targets) && !hosts.is_empty() && !targets.is_empty() {
129 panic!(
130 "Linkcheck currently does not support builds with different hosts and targets.
131You can skip linkcheck with --skip src/tools/linkchecker"
132 );
133 }
134
135 builder.info(&format!("Linkcheck ({host})"));
136
137 let bootstrap_host = builder.config.host_target;
139 let compiler = builder.compiler(0, bootstrap_host);
140
141 let cargo = tool::prepare_tool_cargo(
142 builder,
143 compiler,
144 Mode::ToolBootstrap,
145 bootstrap_host,
146 Kind::Test,
147 "src/tools/linkchecker",
148 SourceType::InTree,
149 &[],
150 );
151 run_cargo_test(cargo, &[], &[], "linkchecker self tests", bootstrap_host, builder);
152
153 if builder.doc_tests == DocTests::No {
154 return;
155 }
156
157 builder.default_doc(&[]);
159
160 let linkchecker = builder.tool_cmd(Tool::Linkchecker);
162
163 let _guard = builder.msg(Kind::Test, "Linkcheck", None, compiler, bootstrap_host);
165 let _time = helpers::timeit(builder);
166 linkchecker.delay_failure().arg(builder.out.join(host).join("doc")).run(builder);
167 }
168
169 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
170 let builder = run.builder;
171 let run = run.path("src/tools/linkchecker");
172 run.default_condition(builder.config.docs)
173 }
174
175 fn make_run(run: RunConfig<'_>) {
176 run.builder.ensure(Linkcheck { host: run.target });
177 }
178}
179
180fn check_if_tidy_is_installed(builder: &Builder<'_>) -> bool {
181 command("tidy").allow_failure().arg("--version").run_capture_stdout(builder).is_success()
182}
183
184#[derive(Debug, Clone, PartialEq, Eq, Hash)]
185pub struct HtmlCheck {
186 target: TargetSelection,
187}
188
189impl Step for HtmlCheck {
190 type Output = ();
191 const DEFAULT: bool = true;
192 const ONLY_HOSTS: bool = true;
193
194 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
195 let builder = run.builder;
196 let run = run.path("src/tools/html-checker");
197 run.lazy_default_condition(Box::new(|| check_if_tidy_is_installed(builder)))
198 }
199
200 fn make_run(run: RunConfig<'_>) {
201 run.builder.ensure(HtmlCheck { target: run.target });
202 }
203
204 fn run(self, builder: &Builder<'_>) {
205 if !check_if_tidy_is_installed(builder) {
206 eprintln!("not running HTML-check tool because `tidy` is missing");
207 eprintln!(
208 "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."
209 );
210 panic!("Cannot run html-check tests");
211 }
212 builder.default_doc(&[]);
214 builder.ensure(crate::core::build_steps::doc::Rustc::for_stage(
215 builder,
216 builder.top_stage,
217 self.target,
218 ));
219
220 builder
221 .tool_cmd(Tool::HtmlChecker)
222 .delay_failure()
223 .arg(builder.doc_out(self.target))
224 .run(builder);
225 }
226}
227
228#[derive(Debug, Clone, PartialEq, Eq, Hash)]
232pub struct Cargotest {
233 build_compiler: Compiler,
234 host: TargetSelection,
235}
236
237impl Step for Cargotest {
238 type Output = ();
239 const ONLY_HOSTS: bool = true;
240
241 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
242 run.path("src/tools/cargotest")
243 }
244
245 fn make_run(run: RunConfig<'_>) {
246 if run.builder.top_stage == 0 {
247 eprintln!(
248 "ERROR: running cargotest with stage 0 is currently unsupported. Use at least stage 1."
249 );
250 exit!(1);
251 }
252 run.builder.ensure(Cargotest {
256 build_compiler: run.builder.compiler(run.builder.top_stage - 1, run.target),
257 host: run.target,
258 });
259 }
260
261 fn run(self, builder: &Builder<'_>) {
266 let cargo =
276 builder.ensure(tool::Cargo::from_build_compiler(self.build_compiler, self.host));
277 let tested_compiler = builder.compiler(self.build_compiler.stage + 1, self.host);
278 builder.std(tested_compiler, self.host);
279
280 let out_dir = builder.out.join("ct");
284 t!(fs::create_dir_all(&out_dir));
285
286 let _time = helpers::timeit(builder);
287 let mut cmd = builder.tool_cmd(Tool::CargoTest);
288 cmd.arg(&cargo.tool_path)
289 .arg(&out_dir)
290 .args(builder.config.test_args())
291 .env("RUSTC", builder.rustc(tested_compiler))
292 .env("RUSTDOC", builder.rustdoc_for_compiler(tested_compiler));
293 add_rustdoc_cargo_linker_args(&mut cmd, builder, tested_compiler.host, LldThreads::No);
294 cmd.delay_failure().run(builder);
295 }
296
297 fn metadata(&self) -> Option<StepMetadata> {
298 Some(StepMetadata::test("cargotest", self.host).stage(self.build_compiler.stage + 1))
299 }
300}
301
302#[derive(Debug, Clone, PartialEq, Eq, Hash)]
305pub struct Cargo {
306 build_compiler: Compiler,
307 host: TargetSelection,
308}
309
310impl Cargo {
311 const CRATE_PATH: &str = "src/tools/cargo";
312}
313
314impl Step for Cargo {
315 type Output = ();
316 const ONLY_HOSTS: bool = true;
317
318 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
319 run.path(Self::CRATE_PATH)
320 }
321
322 fn make_run(run: RunConfig<'_>) {
323 run.builder.ensure(Cargo {
324 build_compiler: get_tool_target_compiler(
325 run.builder,
326 ToolTargetBuildMode::Build(run.target),
327 ),
328 host: run.target,
329 });
330 }
331
332 fn run(self, builder: &Builder<'_>) {
334 builder.ensure(tool::Cargo::from_build_compiler(self.build_compiler, self.host));
338
339 let tested_compiler = builder.compiler(self.build_compiler.stage + 1, self.host);
340 builder.std(tested_compiler, self.host);
341 builder.rustdoc_for_compiler(tested_compiler);
345
346 let cargo = tool::prepare_tool_cargo(
347 builder,
348 self.build_compiler,
349 Mode::ToolTarget,
350 self.host,
351 Kind::Test,
352 Self::CRATE_PATH,
353 SourceType::Submodule,
354 &[],
355 );
356
357 let mut cargo = prepare_cargo_test(cargo, &[], &[], self.host, builder);
359
360 cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
363 cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1");
366
367 cargo.env("PATH", bin_path_for_cargo(builder, tested_compiler));
371
372 let mut existing_dylib_paths = cargo
377 .get_envs()
378 .find(|(k, _)| *k == OsStr::new(dylib_path_var()))
379 .and_then(|(_, v)| v)
380 .map(|value| split_paths(value).collect::<Vec<PathBuf>>())
381 .unwrap_or_default();
382 existing_dylib_paths.insert(0, builder.rustc_libdir(tested_compiler));
383 add_dylib_path(existing_dylib_paths, &mut cargo);
384
385 cargo.env("CARGO_RUSTC_CURRENT_DIR", builder.src.display().to_string());
389
390 #[cfg(feature = "build-metrics")]
391 builder.metrics.begin_test_suite(
392 build_helper::metrics::TestSuiteMetadata::CargoPackage {
393 crates: vec!["cargo".into()],
394 target: self.host.triple.to_string(),
395 host: self.host.triple.to_string(),
396 stage: self.build_compiler.stage + 1,
397 },
398 builder,
399 );
400
401 let _time = helpers::timeit(builder);
402 add_flags_and_try_run_tests(builder, &mut cargo);
403 }
404}
405
406#[derive(Debug, Clone, PartialEq, Eq, Hash)]
407pub struct RustAnalyzer {
408 compilers: RustcPrivateCompilers,
409}
410
411impl Step for RustAnalyzer {
412 type Output = ();
413 const ONLY_HOSTS: bool = true;
414 const DEFAULT: bool = true;
415
416 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
417 run.path("src/tools/rust-analyzer")
418 }
419
420 fn make_run(run: RunConfig<'_>) {
421 run.builder.ensure(Self {
422 compilers: RustcPrivateCompilers::new(
423 run.builder,
424 run.builder.top_stage,
425 run.builder.host_target,
426 ),
427 });
428 }
429
430 fn run(self, builder: &Builder<'_>) {
432 let host = self.compilers.target();
433
434 let workspace_path = "src/tools/rust-analyzer";
435 let crate_path = "src/tools/rust-analyzer/crates/proc-macro-srv";
438 let mut cargo = tool::prepare_tool_cargo(
439 builder,
440 self.compilers.build_compiler(),
441 Mode::ToolRustc,
442 host,
443 Kind::Test,
444 crate_path,
445 SourceType::InTree,
446 &["in-rust-tree".to_owned()],
447 );
448 cargo.allow_features(tool::RustAnalyzer::ALLOW_FEATURES);
449
450 let dir = builder.src.join(workspace_path);
451 cargo.env("CARGO_WORKSPACE_DIR", &dir);
454
455 cargo.env("SKIP_SLOW_TESTS", "1");
458
459 cargo.add_rustc_lib_path(builder);
460 run_cargo_test(cargo, &[], &[], "rust-analyzer", host, builder);
461 }
462}
463
464#[derive(Debug, Clone, PartialEq, Eq, Hash)]
466pub struct Rustfmt {
467 compilers: RustcPrivateCompilers,
468}
469
470impl Step for Rustfmt {
471 type Output = ();
472 const ONLY_HOSTS: bool = true;
473
474 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
475 run.path("src/tools/rustfmt")
476 }
477
478 fn make_run(run: RunConfig<'_>) {
479 run.builder.ensure(Rustfmt {
480 compilers: RustcPrivateCompilers::new(
481 run.builder,
482 run.builder.top_stage,
483 run.builder.host_target,
484 ),
485 });
486 }
487
488 fn run(self, builder: &Builder<'_>) {
490 let tool_result = builder.ensure(tool::Rustfmt::from_compilers(self.compilers));
491 let build_compiler = tool_result.build_compiler;
492 let target = self.compilers.target();
493
494 let mut cargo = tool::prepare_tool_cargo(
495 builder,
496 build_compiler,
497 Mode::ToolRustc,
498 target,
499 Kind::Test,
500 "src/tools/rustfmt",
501 SourceType::InTree,
502 &[],
503 );
504
505 let dir = testdir(builder, target);
506 t!(fs::create_dir_all(&dir));
507 cargo.env("RUSTFMT_TEST_DIR", dir);
508
509 cargo.add_rustc_lib_path(builder);
510
511 run_cargo_test(cargo, &[], &[], "rustfmt", target, builder);
512 }
513}
514
515#[derive(Debug, Clone, PartialEq, Eq, Hash)]
516pub struct Miri {
517 target: TargetSelection,
518}
519
520impl Miri {
521 pub fn build_miri_sysroot(
523 builder: &Builder<'_>,
524 compiler: Compiler,
525 target: TargetSelection,
526 ) -> PathBuf {
527 let miri_sysroot = builder.out.join(compiler.host).join("miri-sysroot");
528 let mut cargo = builder::Cargo::new(
529 builder,
530 compiler,
531 Mode::Std,
532 SourceType::Submodule,
533 target,
534 Kind::MiriSetup,
535 );
536
537 cargo.env("MIRI_LIB_SRC", builder.src.join("library"));
539 cargo.env("MIRI_SYSROOT", &miri_sysroot);
541
542 let mut cargo = BootstrapCommand::from(cargo);
543 let _guard = builder.msg(Kind::Build, "miri sysroot", Mode::ToolRustc, compiler, target);
544 cargo.run(builder);
545
546 cargo.arg("--print-sysroot");
552
553 builder.verbose(|| println!("running: {cargo:?}"));
554 let stdout = cargo.run_capture_stdout(builder).stdout();
555 let sysroot = stdout.trim_end();
557 builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
558 PathBuf::from(sysroot)
559 }
560}
561
562impl Step for Miri {
563 type Output = ();
564 const ONLY_HOSTS: bool = false;
565
566 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
567 run.path("src/tools/miri")
568 }
569
570 fn make_run(run: RunConfig<'_>) {
571 run.builder.ensure(Miri { target: run.target });
572 }
573
574 fn run(self, builder: &Builder<'_>) {
576 let host = builder.build.host_target;
577 let target = self.target;
578 let stage = builder.top_stage;
579 if stage == 0 {
580 eprintln!("miri cannot be tested at stage 0");
581 std::process::exit(1);
582 }
583
584 let compilers = RustcPrivateCompilers::new(builder, stage, host);
586
587 let miri = builder.ensure(tool::Miri::from_compilers(compilers));
589 builder.ensure(tool::CargoMiri::from_compilers(compilers));
591
592 let target_compiler = compilers.target_compiler();
593
594 let miri_sysroot = Miri::build_miri_sysroot(builder, target_compiler, target);
597 builder.std(target_compiler, host);
598 let host_sysroot = builder.sysroot(target_compiler);
599
600 if !builder.config.dry_run() {
603 let ui_test_dep_dir = builder
606 .stage_out(miri.build_compiler, Mode::ToolStd)
607 .join(host)
608 .join("tmp")
609 .join("miri_ui");
610 build_stamp::clear_if_dirty(builder, &ui_test_dep_dir, &miri_sysroot);
614 }
615
616 let mut cargo = tool::prepare_tool_cargo(
619 builder,
620 miri.build_compiler,
621 Mode::ToolRustc,
622 host,
623 Kind::Test,
624 "src/tools/miri",
625 SourceType::InTree,
626 &[],
627 );
628
629 cargo.add_rustc_lib_path(builder);
630
631 let mut cargo = prepare_cargo_test(cargo, &[], &[], host, builder);
634
635 cargo.env("MIRI_SYSROOT", &miri_sysroot);
637 cargo.env("MIRI_HOST_SYSROOT", &host_sysroot);
638 cargo.env("MIRI", &miri.tool_path);
639
640 cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg());
642
643 {
644 let _guard =
645 builder.msg(Kind::Test, "miri", Mode::ToolRustc, miri.build_compiler, target);
646 let _time = helpers::timeit(builder);
647 cargo.run(builder);
648 }
649
650 if builder.config.test_args().is_empty() {
652 cargo.env("MIRIFLAGS", "-O -Zmir-opt-level=4 -Cdebug-assertions=yes");
653 cargo.env("MIRI_SKIP_UI_CHECKS", "1");
655 cargo.env_remove("RUSTC_BLESS");
657 cargo.args(["tests/pass", "tests/panic"]);
659
660 {
661 let _guard = builder.msg(
662 Kind::Test,
663 "miri (mir-opt-level 4)",
664 Mode::ToolRustc,
665 miri.build_compiler,
666 target,
667 );
668 let _time = helpers::timeit(builder);
669 cargo.run(builder);
670 }
671 }
672 }
673}
674
675#[derive(Debug, Clone, PartialEq, Eq, Hash)]
678pub struct CargoMiri {
679 target: TargetSelection,
680}
681
682impl Step for CargoMiri {
683 type Output = ();
684 const ONLY_HOSTS: bool = false;
685
686 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
687 run.path("src/tools/miri/cargo-miri")
688 }
689
690 fn make_run(run: RunConfig<'_>) {
691 run.builder.ensure(CargoMiri { target: run.target });
692 }
693
694 fn run(self, builder: &Builder<'_>) {
696 let host = builder.build.host_target;
697 let target = self.target;
698 let stage = builder.top_stage;
699 if stage == 0 {
700 eprintln!("cargo-miri cannot be tested at stage 0");
701 std::process::exit(1);
702 }
703
704 let build_compiler = builder.compiler(stage, host);
706
707 let mut cargo = tool::prepare_tool_cargo(
712 builder,
713 build_compiler,
714 Mode::ToolStd, target,
716 Kind::MiriTest,
717 "src/tools/miri/test-cargo-miri",
718 SourceType::Submodule,
719 &[],
720 );
721
722 match builder.doc_tests {
725 DocTests::Yes => {}
726 DocTests::No => {
727 cargo.args(["--lib", "--bins", "--examples", "--tests", "--benches"]);
728 }
729 DocTests::Only => {
730 cargo.arg("--doc");
731 }
732 }
733 cargo.arg("--").args(builder.config.test_args());
734
735 let mut cargo = BootstrapCommand::from(cargo);
737 {
738 let _guard =
739 builder.msg(Kind::Test, "cargo-miri", Mode::ToolRustc, (host, stage), target);
740 let _time = helpers::timeit(builder);
741 cargo.run(builder);
742 }
743 }
744}
745
746#[derive(Debug, Clone, PartialEq, Eq, Hash)]
747pub struct CompiletestTest {
748 host: TargetSelection,
749}
750
751impl Step for CompiletestTest {
752 type Output = ();
753
754 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
755 run.path("src/tools/compiletest")
756 }
757
758 fn make_run(run: RunConfig<'_>) {
759 run.builder.ensure(CompiletestTest { host: run.target });
760 }
761
762 #[cfg_attr(
764 feature = "tracing",
765 instrument(level = "debug", name = "CompiletestTest::run", skip_all)
766 )]
767 fn run(self, builder: &Builder<'_>) {
768 let host = self.host;
769
770 if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 {
771 eprintln!("\
772ERROR: `--stage 0` runs compiletest self-tests against the stage0 (precompiled) compiler, not the in-tree compiler, and will almost always cause tests to fail
773NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `--set build.compiletest-allow-stage0=true`."
774 );
775 crate::exit!(1);
776 }
777
778 let compiler = builder.compiler(builder.top_stage, host);
779 debug!(?compiler);
780
781 builder.std(compiler, host);
784 let mut cargo = tool::prepare_tool_cargo(
785 builder,
786 compiler,
787 Mode::ToolStd,
790 host,
791 Kind::Test,
792 "src/tools/compiletest",
793 SourceType::InTree,
794 &[],
795 );
796
797 cargo.env("TEST_RUSTC", builder.rustc(compiler));
801
802 cargo.allow_features(COMPILETEST_ALLOW_FEATURES);
803 run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder);
804 }
805}
806
807#[derive(Debug, Clone, PartialEq, Eq, Hash)]
808pub struct Clippy {
809 compilers: RustcPrivateCompilers,
810}
811
812impl Step for Clippy {
813 type Output = ();
814 const ONLY_HOSTS: bool = true;
815 const DEFAULT: bool = false;
816
817 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
818 run.suite_path("src/tools/clippy/tests").path("src/tools/clippy")
819 }
820
821 fn make_run(run: RunConfig<'_>) {
822 run.builder.ensure(Clippy {
823 compilers: RustcPrivateCompilers::new(
824 run.builder,
825 run.builder.top_stage,
826 run.builder.host_target,
827 ),
828 });
829 }
830
831 fn run(self, builder: &Builder<'_>) {
833 let target = self.compilers.target();
834
835 let compilers = self.compilers;
839 let target_compiler = compilers.target_compiler();
840
841 let tool_result = builder.ensure(tool::Clippy::from_compilers(compilers));
842 let build_compiler = tool_result.build_compiler;
843 let mut cargo = tool::prepare_tool_cargo(
844 builder,
845 build_compiler,
846 Mode::ToolRustc,
847 target,
848 Kind::Test,
849 "src/tools/clippy",
850 SourceType::InTree,
851 &[],
852 );
853
854 cargo.env("RUSTC_TEST_SUITE", builder.rustc(build_compiler));
855 cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(build_compiler));
856 let host_libs =
857 builder.stage_out(build_compiler, Mode::ToolRustc).join(builder.cargo_dir());
858 cargo.env("HOST_LIBS", host_libs);
859
860 builder.std(target_compiler, target);
862 cargo.env("TEST_SYSROOT", builder.sysroot(target_compiler));
863 cargo.env("TEST_RUSTC", builder.rustc(target_compiler));
864 cargo.env("TEST_RUSTC_LIB", builder.rustc_libdir(target_compiler));
865
866 'partially_test: {
868 let paths = &builder.config.paths[..];
869 let mut test_names = Vec::new();
870 for path in paths {
871 if let Some(path) =
872 helpers::is_valid_test_suite_arg(path, "src/tools/clippy/tests", builder)
873 {
874 test_names.push(path);
875 } else if path.ends_with("src/tools/clippy") {
876 break 'partially_test;
878 }
879 }
880 cargo.env("TESTNAME", test_names.join(","));
881 }
882
883 cargo.add_rustc_lib_path(builder);
884 let cargo = prepare_cargo_test(cargo, &[], &[], target, builder);
885
886 let _guard = builder.msg(Kind::Test, "clippy", Mode::ToolRustc, build_compiler, target);
887
888 if cargo.allow_failure().run(builder) {
890 return;
892 }
893
894 if !builder.config.cmd.bless() {
895 crate::exit!(1);
896 }
897 }
898}
899
900fn bin_path_for_cargo(builder: &Builder<'_>, compiler: Compiler) -> OsString {
901 let path = builder.sysroot(compiler).join("bin");
902 let old_path = env::var_os("PATH").unwrap_or_default();
903 env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("")
904}
905
906#[derive(Debug, Clone, Hash, PartialEq, Eq)]
907pub struct RustdocTheme {
908 pub compiler: Compiler,
909}
910
911impl Step for RustdocTheme {
912 type Output = ();
913 const DEFAULT: bool = true;
914 const ONLY_HOSTS: bool = true;
915
916 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
917 run.path("src/tools/rustdoc-themes")
918 }
919
920 fn make_run(run: RunConfig<'_>) {
921 let compiler = run.builder.compiler(run.builder.top_stage, run.target);
922
923 run.builder.ensure(RustdocTheme { compiler });
924 }
925
926 fn run(self, builder: &Builder<'_>) {
927 let rustdoc = builder.bootstrap_out.join("rustdoc");
928 let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
929 cmd.arg(rustdoc.to_str().unwrap())
930 .arg(builder.src.join("src/librustdoc/html/static/css/rustdoc.css").to_str().unwrap())
931 .env("RUSTC_STAGE", self.compiler.stage.to_string())
932 .env("RUSTC_SYSROOT", builder.sysroot(self.compiler))
933 .env("RUSTDOC_LIBDIR", builder.sysroot_target_libdir(self.compiler, self.compiler.host))
934 .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
935 .env("RUSTDOC_REAL", builder.rustdoc_for_compiler(self.compiler))
936 .env("RUSTC_BOOTSTRAP", "1");
937 cmd.args(linker_args(builder, self.compiler.host, LldThreads::No));
938
939 cmd.delay_failure().run(builder);
940 }
941}
942
943#[derive(Debug, Clone, Hash, PartialEq, Eq)]
944pub struct RustdocJSStd {
945 pub target: TargetSelection,
946}
947
948impl Step for RustdocJSStd {
949 type Output = ();
950 const DEFAULT: bool = true;
951 const ONLY_HOSTS: bool = true;
952
953 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
954 let default = run.builder.config.nodejs.is_some();
955 run.suite_path("tests/rustdoc-js-std").default_condition(default)
956 }
957
958 fn make_run(run: RunConfig<'_>) {
959 run.builder.ensure(RustdocJSStd { target: run.target });
960 }
961
962 fn run(self, builder: &Builder<'_>) {
963 let nodejs =
964 builder.config.nodejs.as_ref().expect("need nodejs to run rustdoc-js-std tests");
965 let mut command = command(nodejs);
966 command
967 .arg(builder.src.join("src/tools/rustdoc-js/tester.js"))
968 .arg("--crate-name")
969 .arg("std")
970 .arg("--resource-suffix")
971 .arg(&builder.version)
972 .arg("--doc-folder")
973 .arg(builder.doc_out(self.target))
974 .arg("--test-folder")
975 .arg(builder.src.join("tests/rustdoc-js-std"));
976 for path in &builder.paths {
977 if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder)
978 {
979 if !p.ends_with(".js") {
980 eprintln!("A non-js file was given: `{}`", path.display());
981 panic!("Cannot run rustdoc-js-std tests");
982 }
983 command.arg("--test-file").arg(path);
984 }
985 }
986 builder.ensure(crate::core::build_steps::doc::Std::from_build_compiler(
987 builder.compiler(builder.top_stage, builder.host_target),
988 self.target,
989 DocumentationFormat::Html,
990 ));
991 let _guard = builder.msg(
992 Kind::Test,
993 "rustdoc-js-std",
994 None,
995 (builder.config.host_target, builder.top_stage),
996 self.target,
997 );
998 command.run(builder);
999 }
1000}
1001
1002#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1003pub struct RustdocJSNotStd {
1004 pub target: TargetSelection,
1005 pub compiler: Compiler,
1006}
1007
1008impl Step for RustdocJSNotStd {
1009 type Output = ();
1010 const DEFAULT: bool = true;
1011 const ONLY_HOSTS: bool = true;
1012
1013 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1014 let default = run.builder.config.nodejs.is_some();
1015 run.suite_path("tests/rustdoc-js").default_condition(default)
1016 }
1017
1018 fn make_run(run: RunConfig<'_>) {
1019 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1020 run.builder.ensure(RustdocJSNotStd { target: run.target, compiler });
1021 }
1022
1023 fn run(self, builder: &Builder<'_>) {
1024 builder.ensure(Compiletest {
1025 compiler: self.compiler,
1026 target: self.target,
1027 mode: "rustdoc-js",
1028 suite: "rustdoc-js",
1029 path: "tests/rustdoc-js",
1030 compare_mode: None,
1031 });
1032 }
1033}
1034
1035fn get_browser_ui_test_version_inner(
1036 builder: &Builder<'_>,
1037 npm: &Path,
1038 global: bool,
1039) -> Option<String> {
1040 let mut command = command(npm);
1041 command.arg("list").arg("--parseable").arg("--long").arg("--depth=0");
1042 if global {
1043 command.arg("--global");
1044 }
1045 let lines = command.allow_failure().run_capture(builder).stdout();
1046 lines
1047 .lines()
1048 .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@"))
1049 .map(|v| v.to_owned())
1050}
1051
1052fn get_browser_ui_test_version(builder: &Builder<'_>, npm: &Path) -> Option<String> {
1053 get_browser_ui_test_version_inner(builder, npm, false)
1054 .or_else(|| get_browser_ui_test_version_inner(builder, npm, true))
1055}
1056
1057#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1058pub struct RustdocGUI {
1059 pub target: TargetSelection,
1060 pub compiler: Compiler,
1061}
1062
1063impl Step for RustdocGUI {
1064 type Output = ();
1065 const DEFAULT: bool = true;
1066 const ONLY_HOSTS: bool = true;
1067
1068 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1069 let builder = run.builder;
1070 let run = run.suite_path("tests/rustdoc-gui");
1071 run.lazy_default_condition(Box::new(move || {
1072 builder.config.nodejs.is_some()
1073 && builder.doc_tests != DocTests::Only
1074 && builder
1075 .config
1076 .npm
1077 .as_ref()
1078 .map(|p| get_browser_ui_test_version(builder, p).is_some())
1079 .unwrap_or(false)
1080 }))
1081 }
1082
1083 fn make_run(run: RunConfig<'_>) {
1084 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1085 run.builder.ensure(RustdocGUI { target: run.target, compiler });
1086 }
1087
1088 fn run(self, builder: &Builder<'_>) {
1089 builder.std(self.compiler, self.target);
1090
1091 let mut cmd = builder.tool_cmd(Tool::RustdocGUITest);
1092
1093 let out_dir = builder.test_out(self.target).join("rustdoc-gui");
1094 build_stamp::clear_if_dirty(
1095 builder,
1096 &out_dir,
1097 &builder.rustdoc_for_compiler(self.compiler),
1098 );
1099
1100 if let Some(src) = builder.config.src.to_str() {
1101 cmd.arg("--rust-src").arg(src);
1102 }
1103
1104 if let Some(out_dir) = out_dir.to_str() {
1105 cmd.arg("--out-dir").arg(out_dir);
1106 }
1107
1108 if let Some(initial_cargo) = builder.config.initial_cargo.to_str() {
1109 cmd.arg("--initial-cargo").arg(initial_cargo);
1110 }
1111
1112 cmd.arg("--jobs").arg(builder.jobs().to_string());
1113
1114 cmd.env("RUSTDOC", builder.rustdoc_for_compiler(self.compiler))
1115 .env("RUSTC", builder.rustc(self.compiler));
1116
1117 add_rustdoc_cargo_linker_args(&mut cmd, builder, self.compiler.host, LldThreads::No);
1118
1119 for path in &builder.paths {
1120 if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) {
1121 if !p.ends_with(".goml") {
1122 eprintln!("A non-goml file was given: `{}`", path.display());
1123 panic!("Cannot run rustdoc-gui tests");
1124 }
1125 if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
1126 cmd.arg("--goml-file").arg(name);
1127 }
1128 }
1129 }
1130
1131 for test_arg in builder.config.test_args() {
1132 cmd.arg("--test-arg").arg(test_arg);
1133 }
1134
1135 if let Some(ref nodejs) = builder.config.nodejs {
1136 cmd.arg("--nodejs").arg(nodejs);
1137 }
1138
1139 if let Some(ref npm) = builder.config.npm {
1140 cmd.arg("--npm").arg(npm);
1141 }
1142
1143 let _time = helpers::timeit(builder);
1144 let _guard = builder.msg(Kind::Test, "rustdoc-gui", None, self.compiler, self.target);
1145 try_run_tests(builder, &mut cmd, true);
1146 }
1147}
1148
1149#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1154pub struct Tidy;
1155
1156impl Step for Tidy {
1157 type Output = ();
1158 const DEFAULT: bool = true;
1159 const ONLY_HOSTS: bool = true;
1160
1161 fn run(self, builder: &Builder<'_>) {
1170 let mut cmd = builder.tool_cmd(Tool::Tidy);
1171 cmd.arg(&builder.src);
1172 cmd.arg(&builder.initial_cargo);
1173 cmd.arg(&builder.out);
1174 let jobs = builder.config.jobs.unwrap_or_else(|| {
1176 8 * std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32
1177 });
1178 cmd.arg(jobs.to_string());
1179 if let Some(npm) = &builder.config.npm {
1181 cmd.arg(npm);
1182 } else {
1183 cmd.arg("npm");
1184 }
1185 if builder.is_verbose() {
1186 cmd.arg("--verbose");
1187 }
1188 if builder.config.cmd.bless() {
1189 cmd.arg("--bless");
1190 }
1191 if let Some(s) =
1192 builder.config.cmd.extra_checks().or(builder.config.tidy_extra_checks.as_deref())
1193 {
1194 cmd.arg(format!("--extra-checks={s}"));
1195 }
1196 let mut args = std::env::args_os();
1197 if args.any(|arg| arg == OsStr::new("--")) {
1198 cmd.arg("--");
1199 cmd.args(args);
1200 }
1201
1202 if builder.config.channel == "dev" || builder.config.channel == "nightly" {
1203 if !builder.config.json_output {
1204 builder.info("fmt check");
1205 if builder.config.initial_rustfmt.is_none() {
1206 let inferred_rustfmt_dir = builder.initial_sysroot.join("bin");
1207 eprintln!(
1208 "\
1209ERROR: no `rustfmt` binary found in {PATH}
1210INFO: `rust.channel` is currently set to \"{CHAN}\"
1211HELP: if you are testing a beta branch, set `rust.channel` to \"beta\" in the `bootstrap.toml` file
1212HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to `x.py test`",
1213 PATH = inferred_rustfmt_dir.display(),
1214 CHAN = builder.config.channel,
1215 );
1216 crate::exit!(1);
1217 }
1218 let all = false;
1219 crate::core::build_steps::format::format(
1220 builder,
1221 !builder.config.cmd.bless(),
1222 all,
1223 &[],
1224 );
1225 } else {
1226 eprintln!(
1227 "WARNING: `--json-output` is not supported on rustfmt, formatting will be skipped"
1228 );
1229 }
1230 }
1231
1232 builder.info("tidy check");
1233 cmd.delay_failure().run(builder);
1234
1235 builder.info("x.py completions check");
1236 let completion_paths = get_completion_paths(builder);
1237 if builder.config.cmd.bless() {
1238 builder.ensure(crate::core::build_steps::run::GenerateCompletions);
1239 } else if completion_paths
1240 .into_iter()
1241 .any(|(shell, path)| get_completion(shell, &path).is_some())
1242 {
1243 eprintln!(
1244 "x.py completions were changed; run `x.py run generate-completions` to update them"
1245 );
1246 crate::exit!(1);
1247 }
1248 }
1249
1250 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1251 let default = run.builder.doc_tests != DocTests::Only;
1252 run.path("src/tools/tidy").default_condition(default)
1253 }
1254
1255 fn make_run(run: RunConfig<'_>) {
1256 run.builder.ensure(Tidy);
1257 }
1258
1259 fn metadata(&self) -> Option<StepMetadata> {
1260 Some(StepMetadata::test("tidy", TargetSelection::default()))
1261 }
1262}
1263
1264fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf {
1265 builder.out.join(host).join("test")
1266}
1267
1268macro_rules! test {
1270 (
1271 $( #[$attr:meta] )* $name:ident {
1273 path: $path:expr,
1274 mode: $mode:expr,
1275 suite: $suite:expr,
1276 default: $default:expr
1277 $( , only_hosts: $only_hosts:expr )? $( , compare_mode: $compare_mode:expr )? $( , )? }
1281 ) => {
1282 $( #[$attr] )*
1283 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
1284 pub struct $name {
1285 pub compiler: Compiler,
1286 pub target: TargetSelection,
1287 }
1288
1289 impl Step for $name {
1290 type Output = ();
1291 const DEFAULT: bool = $default;
1292 const ONLY_HOSTS: bool = (const {
1293 #[allow(unused_assignments, unused_mut)]
1294 let mut value = false;
1295 $( value = $only_hosts; )?
1296 value
1297 });
1298
1299 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1300 run.suite_path($path)
1301 }
1302
1303 fn make_run(run: RunConfig<'_>) {
1304 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1305
1306 run.builder.ensure($name { compiler, target: run.target });
1307 }
1308
1309 fn run(self, builder: &Builder<'_>) {
1310 builder.ensure(Compiletest {
1311 compiler: self.compiler,
1312 target: self.target,
1313 mode: $mode,
1314 suite: $suite,
1315 path: $path,
1316 compare_mode: (const {
1317 #[allow(unused_assignments, unused_mut)]
1318 let mut value = None;
1319 $( value = $compare_mode; )?
1320 value
1321 }),
1322 })
1323 }
1324
1325 fn metadata(&self) -> Option<StepMetadata> {
1326 Some(
1327 StepMetadata::test(stringify!($name), self.target)
1328 )
1329 }
1330 }
1331 };
1332}
1333
1334#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1337pub struct CrateRunMakeSupport {
1338 host: TargetSelection,
1339}
1340
1341impl Step for CrateRunMakeSupport {
1342 type Output = ();
1343 const ONLY_HOSTS: bool = true;
1344
1345 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1346 run.path("src/tools/run-make-support")
1347 }
1348
1349 fn make_run(run: RunConfig<'_>) {
1350 run.builder.ensure(CrateRunMakeSupport { host: run.target });
1351 }
1352
1353 fn run(self, builder: &Builder<'_>) {
1355 let host = self.host;
1356 let compiler = builder.compiler(0, host);
1357
1358 let mut cargo = tool::prepare_tool_cargo(
1359 builder,
1360 compiler,
1361 Mode::ToolBootstrap,
1362 host,
1363 Kind::Test,
1364 "src/tools/run-make-support",
1365 SourceType::InTree,
1366 &[],
1367 );
1368 cargo.allow_features("test");
1369 run_cargo_test(cargo, &[], &[], "run-make-support self test", host, builder);
1370 }
1371}
1372
1373#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1374pub struct CrateBuildHelper {
1375 host: TargetSelection,
1376}
1377
1378impl Step for CrateBuildHelper {
1379 type Output = ();
1380 const ONLY_HOSTS: bool = true;
1381
1382 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1383 run.path("src/build_helper")
1384 }
1385
1386 fn make_run(run: RunConfig<'_>) {
1387 run.builder.ensure(CrateBuildHelper { host: run.target });
1388 }
1389
1390 fn run(self, builder: &Builder<'_>) {
1392 let host = self.host;
1393 let compiler = builder.compiler(0, host);
1394
1395 let mut cargo = tool::prepare_tool_cargo(
1396 builder,
1397 compiler,
1398 Mode::ToolBootstrap,
1399 host,
1400 Kind::Test,
1401 "src/build_helper",
1402 SourceType::InTree,
1403 &[],
1404 );
1405 cargo.allow_features("test");
1406 run_cargo_test(cargo, &[], &[], "build_helper self test", host, builder);
1407 }
1408}
1409
1410test!(Ui { path: "tests/ui", mode: "ui", suite: "ui", default: true });
1411
1412test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes", default: true });
1413
1414test!(CodegenLlvm {
1415 path: "tests/codegen-llvm",
1416 mode: "codegen",
1417 suite: "codegen-llvm",
1418 default: true
1419});
1420
1421test!(CodegenUnits {
1422 path: "tests/codegen-units",
1423 mode: "codegen-units",
1424 suite: "codegen-units",
1425 default: true,
1426});
1427
1428test!(Incremental {
1429 path: "tests/incremental",
1430 mode: "incremental",
1431 suite: "incremental",
1432 default: true,
1433});
1434
1435test!(Debuginfo {
1436 path: "tests/debuginfo",
1437 mode: "debuginfo",
1438 suite: "debuginfo",
1439 default: true,
1440 compare_mode: Some("split-dwarf"),
1441});
1442
1443test!(UiFullDeps {
1444 path: "tests/ui-fulldeps",
1445 mode: "ui",
1446 suite: "ui-fulldeps",
1447 default: true,
1448 only_hosts: true,
1449});
1450
1451test!(Rustdoc {
1452 path: "tests/rustdoc",
1453 mode: "rustdoc",
1454 suite: "rustdoc",
1455 default: true,
1456 only_hosts: true,
1457});
1458test!(RustdocUi {
1459 path: "tests/rustdoc-ui",
1460 mode: "ui",
1461 suite: "rustdoc-ui",
1462 default: true,
1463 only_hosts: true,
1464});
1465
1466test!(RustdocJson {
1467 path: "tests/rustdoc-json",
1468 mode: "rustdoc-json",
1469 suite: "rustdoc-json",
1470 default: true,
1471 only_hosts: true,
1472});
1473
1474test!(Pretty {
1475 path: "tests/pretty",
1476 mode: "pretty",
1477 suite: "pretty",
1478 default: true,
1479 only_hosts: true,
1480});
1481
1482test!(RunMake { path: "tests/run-make", mode: "run-make", suite: "run-make", default: true });
1483
1484test!(AssemblyLlvm {
1485 path: "tests/assembly-llvm",
1486 mode: "assembly",
1487 suite: "assembly-llvm",
1488 default: true
1489});
1490
1491#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1494pub struct Coverage {
1495 pub compiler: Compiler,
1496 pub target: TargetSelection,
1497 pub mode: &'static str,
1498}
1499
1500impl Coverage {
1501 const PATH: &'static str = "tests/coverage";
1502 const SUITE: &'static str = "coverage";
1503 const ALL_MODES: &[&str] = &["coverage-map", "coverage-run"];
1504}
1505
1506impl Step for Coverage {
1507 type Output = ();
1508 const DEFAULT: bool = true;
1509 const ONLY_HOSTS: bool = false;
1511
1512 fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {
1513 run = run.suite_path(Self::PATH);
1519 for mode in Self::ALL_MODES {
1520 run = run.alias(mode);
1521 }
1522 run
1523 }
1524
1525 fn make_run(run: RunConfig<'_>) {
1526 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1527 let target = run.target;
1528
1529 let mut modes = vec![];
1533
1534 for path in &run.paths {
1537 match path {
1538 PathSet::Set(_) => {
1539 for mode in Self::ALL_MODES {
1540 if path.assert_single_path().path == Path::new(mode) {
1541 modes.push(mode);
1542 break;
1543 }
1544 }
1545 }
1546 PathSet::Suite(_) => {
1547 modes.extend(Self::ALL_MODES);
1548 break;
1549 }
1550 }
1551 }
1552
1553 modes.retain(|mode| !run.builder.config.skip.iter().any(|skip| skip == Path::new(mode)));
1556
1557 for mode in modes {
1565 run.builder.ensure(Coverage { compiler, target, mode });
1566 }
1567 }
1568
1569 fn run(self, builder: &Builder<'_>) {
1570 let Self { compiler, target, mode } = self;
1571 builder.ensure(Compiletest {
1574 compiler,
1575 target,
1576 mode,
1577 suite: Self::SUITE,
1578 path: Self::PATH,
1579 compare_mode: None,
1580 });
1581 }
1582}
1583
1584test!(CoverageRunRustdoc {
1585 path: "tests/coverage-run-rustdoc",
1586 mode: "coverage-run",
1587 suite: "coverage-run-rustdoc",
1588 default: true,
1589 only_hosts: true,
1590});
1591
1592#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1594pub struct MirOpt {
1595 pub compiler: Compiler,
1596 pub target: TargetSelection,
1597}
1598
1599impl Step for MirOpt {
1600 type Output = ();
1601 const DEFAULT: bool = true;
1602 const ONLY_HOSTS: bool = false;
1603
1604 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1605 run.suite_path("tests/mir-opt")
1606 }
1607
1608 fn make_run(run: RunConfig<'_>) {
1609 let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1610 run.builder.ensure(MirOpt { compiler, target: run.target });
1611 }
1612
1613 fn run(self, builder: &Builder<'_>) {
1614 let run = |target| {
1615 builder.ensure(Compiletest {
1616 compiler: self.compiler,
1617 target,
1618 mode: "mir-opt",
1619 suite: "mir-opt",
1620 path: "tests/mir-opt",
1621 compare_mode: None,
1622 })
1623 };
1624
1625 run(self.target);
1626
1627 if builder.config.cmd.bless() {
1630 for target in ["aarch64-unknown-linux-gnu", "i686-pc-windows-msvc"] {
1636 run(TargetSelection::from_user(target));
1637 }
1638
1639 for target in ["x86_64-apple-darwin", "i686-unknown-linux-musl"] {
1640 let target = TargetSelection::from_user(target);
1641 let panic_abort_target = builder.ensure(MirOptPanicAbortSyntheticTarget {
1642 compiler: self.compiler,
1643 base: target,
1644 });
1645 run(panic_abort_target);
1646 }
1647 }
1648 }
1649}
1650
1651#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1652struct Compiletest {
1653 compiler: Compiler,
1654 target: TargetSelection,
1655 mode: &'static str,
1656 suite: &'static str,
1657 path: &'static str,
1658 compare_mode: Option<&'static str>,
1659}
1660
1661impl Step for Compiletest {
1662 type Output = ();
1663
1664 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1665 run.never()
1666 }
1667
1668 fn run(self, builder: &Builder<'_>) {
1674 if builder.doc_tests == DocTests::Only {
1675 return;
1676 }
1677
1678 if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 {
1679 eprintln!("\
1680ERROR: `--stage 0` runs compiletest on the stage0 (precompiled) compiler, not your local changes, and will almost always cause tests to fail
1681HELP: to test the compiler or standard library, omit the stage or explicitly use `--stage 1` instead
1682NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `--set build.compiletest-allow-stage0=true`."
1683 );
1684 crate::exit!(1);
1685 }
1686
1687 let mut compiler = self.compiler;
1688 let target = self.target;
1689 let mode = self.mode;
1690 let suite = self.suite;
1691
1692 let suite_path = self.path;
1694
1695 if !builder.config.codegen_tests && mode == "codegen" {
1697 return;
1698 }
1699
1700 let query_compiler;
1707 let (stage, stage_id) = if suite == "ui-fulldeps" && compiler.stage == 1 {
1708 query_compiler = Some(compiler);
1711 let build = builder.build.host_target;
1715 compiler = builder.compiler(compiler.stage - 1, build);
1716 let test_stage = compiler.stage + 1;
1717 (test_stage, format!("stage{test_stage}-{build}"))
1718 } else {
1719 query_compiler = None;
1720 let stage = compiler.stage;
1721 (stage, format!("stage{stage}-{target}"))
1722 };
1723
1724 if suite.ends_with("fulldeps") {
1725 builder.ensure(compile::Rustc::new(compiler, target));
1726 }
1727
1728 if suite == "debuginfo" {
1729 builder.ensure(dist::DebuggerScripts {
1730 sysroot: builder.sysroot(compiler).to_path_buf(),
1731 host: target,
1732 });
1733 }
1734 if suite == "run-make" {
1735 builder.tool_exe(Tool::RunMakeSupport);
1736 }
1737
1738 if suite == "mir-opt" {
1740 builder.ensure(compile::Std::new(compiler, compiler.host).is_for_mir_opt_tests(true));
1741 } else {
1742 builder.std(compiler, compiler.host);
1743 }
1744
1745 let mut cmd = builder.tool_cmd(Tool::Compiletest);
1746
1747 if suite == "mir-opt" {
1748 builder.ensure(compile::Std::new(compiler, target).is_for_mir_opt_tests(true));
1749 } else {
1750 builder.std(compiler, target);
1751 }
1752
1753 builder.ensure(RemoteCopyLibs { compiler, target });
1754
1755 cmd.arg("--stage").arg(stage.to_string());
1759 cmd.arg("--stage-id").arg(stage_id);
1760
1761 cmd.arg("--compile-lib-path").arg(builder.rustc_libdir(compiler));
1762 cmd.arg("--run-lib-path").arg(builder.sysroot_target_libdir(compiler, target));
1763 cmd.arg("--rustc-path").arg(builder.rustc(compiler));
1764 if let Some(query_compiler) = query_compiler {
1765 cmd.arg("--query-rustc-path").arg(builder.rustc(query_compiler));
1766 }
1767
1768 cmd.arg("--minicore-path")
1771 .arg(builder.src.join("tests").join("auxiliary").join("minicore.rs"));
1772
1773 let is_rustdoc = suite == "rustdoc-ui" || suite == "rustdoc-js";
1774
1775 if mode == "run-make" {
1776 let cargo_path = if builder.top_stage == 0 {
1777 builder.initial_cargo.clone()
1779 } else {
1780 builder.ensure(tool::Cargo::from_build_compiler(compiler, compiler.host)).tool_path
1781 };
1782
1783 cmd.arg("--cargo-path").arg(cargo_path);
1784
1785 let stage0_rustc_path = builder.compiler(0, compiler.host);
1788 cmd.arg("--stage0-rustc-path").arg(builder.rustc(stage0_rustc_path));
1789 }
1790
1791 if mode == "rustdoc"
1793 || mode == "run-make"
1794 || (mode == "ui" && is_rustdoc)
1795 || mode == "rustdoc-js"
1796 || mode == "rustdoc-json"
1797 || suite == "coverage-run-rustdoc"
1798 {
1799 cmd.arg("--rustdoc-path").arg(builder.rustdoc_for_compiler(compiler));
1800 }
1801
1802 if mode == "rustdoc-json" {
1803 let json_compiler = compiler.with_stage(0);
1805 cmd.arg("--jsondocck-path")
1806 .arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target }).tool_path);
1807 cmd.arg("--jsondoclint-path").arg(
1808 builder.ensure(tool::JsonDocLint { compiler: json_compiler, target }).tool_path,
1809 );
1810 }
1811
1812 if matches!(mode, "coverage-map" | "coverage-run") {
1813 let coverage_dump = builder.tool_exe(Tool::CoverageDump);
1814 cmd.arg("--coverage-dump-path").arg(coverage_dump);
1815 }
1816
1817 cmd.arg("--src-root").arg(&builder.src);
1818 cmd.arg("--src-test-suite-root").arg(builder.src.join("tests").join(suite));
1819
1820 cmd.arg("--build-root").arg(&builder.out);
1824 cmd.arg("--build-test-suite-root").arg(testdir(builder, compiler.host).join(suite));
1825
1826 let sysroot = if builder.top_stage == 0 {
1829 builder.initial_sysroot.clone()
1830 } else {
1831 builder.sysroot(compiler)
1832 };
1833
1834 cmd.arg("--sysroot-base").arg(sysroot);
1835
1836 cmd.arg("--suite").arg(suite);
1837 cmd.arg("--mode").arg(mode);
1838 cmd.arg("--target").arg(target.rustc_target_arg());
1839 cmd.arg("--host").arg(&*compiler.host.triple);
1840 cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.host_target));
1841
1842 if let Some(codegen_backend) = builder.config.default_codegen_backend(compiler.host) {
1843 cmd.arg("--codegen-backend").arg(codegen_backend.name());
1846 }
1847
1848 if builder.build.config.llvm_enzyme {
1849 cmd.arg("--has-enzyme");
1850 }
1851
1852 if builder.config.cmd.bless() {
1853 cmd.arg("--bless");
1854 }
1855
1856 if builder.config.cmd.force_rerun() {
1857 cmd.arg("--force-rerun");
1858 }
1859
1860 if builder.config.cmd.no_capture() {
1861 cmd.arg("--no-capture");
1862 }
1863
1864 let compare_mode =
1865 builder.config.cmd.compare_mode().or_else(|| {
1866 if builder.config.test_compare_mode { self.compare_mode } else { None }
1867 });
1868
1869 if let Some(ref pass) = builder.config.cmd.pass() {
1870 cmd.arg("--pass");
1871 cmd.arg(pass);
1872 }
1873
1874 if let Some(ref run) = builder.config.cmd.run() {
1875 cmd.arg("--run");
1876 cmd.arg(run);
1877 }
1878
1879 if let Some(ref nodejs) = builder.config.nodejs {
1880 cmd.arg("--nodejs").arg(nodejs);
1881 } else if mode == "rustdoc-js" {
1882 panic!("need nodejs to run rustdoc-js suite");
1883 }
1884 if let Some(ref npm) = builder.config.npm {
1885 cmd.arg("--npm").arg(npm);
1886 }
1887 if builder.config.rust_optimize_tests {
1888 cmd.arg("--optimize-tests");
1889 }
1890 if builder.config.rust_randomize_layout {
1891 cmd.arg("--rust-randomized-layout");
1892 }
1893 if builder.config.cmd.only_modified() {
1894 cmd.arg("--only-modified");
1895 }
1896 if let Some(compiletest_diff_tool) = &builder.config.compiletest_diff_tool {
1897 cmd.arg("--compiletest-diff-tool").arg(compiletest_diff_tool);
1898 }
1899
1900 let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
1901 flags.push(format!(
1902 "-Cdebuginfo={}",
1903 if mode == "codegen" {
1904 if builder.config.rust_debuginfo_level_tests
1907 != crate::core::config::DebuginfoLevel::None
1908 {
1909 println!(
1910 "NOTE: ignoring `rust.debuginfo-level-tests={}` for codegen tests",
1911 builder.config.rust_debuginfo_level_tests
1912 );
1913 }
1914 crate::core::config::DebuginfoLevel::None
1915 } else {
1916 builder.config.rust_debuginfo_level_tests
1917 }
1918 ));
1919 flags.extend(builder.config.cmd.compiletest_rustc_args().iter().map(|s| s.to_string()));
1920
1921 if suite != "mir-opt" {
1922 if let Some(linker) = builder.linker(target) {
1923 cmd.arg("--target-linker").arg(linker);
1924 }
1925 if let Some(linker) = builder.linker(compiler.host) {
1926 cmd.arg("--host-linker").arg(linker);
1927 }
1928 }
1929
1930 if suite == "ui-fulldeps" && target.ends_with("darwin") {
1932 flags.push("-Alinker_messages".into());
1933 }
1934
1935 let mut hostflags = flags.clone();
1936 hostflags.extend(linker_flags(builder, compiler.host, LldThreads::No));
1937
1938 let mut targetflags = flags;
1939
1940 if suite == "ui" || suite == "incremental" {
1942 builder.ensure(TestHelpers { target: compiler.host });
1943 builder.ensure(TestHelpers { target });
1944 hostflags
1945 .push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display()));
1946 targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
1947 }
1948
1949 for flag in hostflags {
1950 cmd.arg("--host-rustcflags").arg(flag);
1951 }
1952 for flag in targetflags {
1953 cmd.arg("--target-rustcflags").arg(flag);
1954 }
1955
1956 cmd.arg("--python").arg(builder.python());
1957
1958 if let Some(ref gdb) = builder.config.gdb {
1959 cmd.arg("--gdb").arg(gdb);
1960 }
1961
1962 let lldb_exe = builder.config.lldb.clone().unwrap_or_else(|| PathBuf::from("lldb"));
1963 let lldb_version = command(&lldb_exe)
1964 .allow_failure()
1965 .arg("--version")
1966 .run_capture(builder)
1967 .stdout_if_ok()
1968 .and_then(|v| if v.trim().is_empty() { None } else { Some(v) });
1969 if let Some(ref vers) = lldb_version {
1970 cmd.arg("--lldb-version").arg(vers);
1971 let lldb_python_dir = command(&lldb_exe)
1972 .allow_failure()
1973 .arg("-P")
1974 .run_capture_stdout(builder)
1975 .stdout_if_ok()
1976 .map(|p| p.lines().next().expect("lldb Python dir not found").to_string());
1977 if let Some(ref dir) = lldb_python_dir {
1978 cmd.arg("--lldb-python-dir").arg(dir);
1979 }
1980 }
1981
1982 if helpers::forcing_clang_based_tests() {
1983 let clang_exe = builder.llvm_out(target).join("bin").join("clang");
1984 cmd.arg("--run-clang-based-tests-with").arg(clang_exe);
1985 }
1986
1987 for exclude in &builder.config.skip {
1988 cmd.arg("--skip");
1989 cmd.arg(exclude);
1990 }
1991
1992 let paths = match &builder.config.cmd {
1994 Subcommand::Test { .. } => &builder.config.paths[..],
1995 _ => &[],
1996 };
1997
1998 let mut test_args: Vec<&str> = paths
2000 .iter()
2001 .filter_map(|p| helpers::is_valid_test_suite_arg(p, suite_path, builder))
2002 .collect();
2003
2004 test_args.append(&mut builder.config.test_args());
2005
2006 if cfg!(windows) {
2009 let test_args_win: Vec<String> =
2010 test_args.iter().map(|s| s.replace('/', "\\")).collect();
2011 cmd.args(&test_args_win);
2012 } else {
2013 cmd.args(&test_args);
2014 }
2015
2016 if builder.is_verbose() {
2017 cmd.arg("--verbose");
2018 }
2019
2020 cmd.arg("--json");
2021
2022 if builder.config.rustc_debug_assertions {
2023 cmd.arg("--with-rustc-debug-assertions");
2024 }
2025
2026 if builder.config.std_debug_assertions {
2027 cmd.arg("--with-std-debug-assertions");
2028 }
2029
2030 let mut llvm_components_passed = false;
2031 let mut copts_passed = false;
2032 if builder.config.llvm_enabled(compiler.host) {
2033 let llvm::LlvmResult { llvm_config, .. } =
2034 builder.ensure(llvm::Llvm { target: builder.config.host_target });
2035 if !builder.config.dry_run() {
2036 let llvm_version = get_llvm_version(builder, &llvm_config);
2037 let llvm_components =
2038 command(&llvm_config).arg("--components").run_capture_stdout(builder).stdout();
2039 cmd.arg("--llvm-version")
2041 .arg(llvm_version.trim())
2042 .arg("--llvm-components")
2043 .arg(llvm_components.trim());
2044 llvm_components_passed = true;
2045 }
2046 if !builder.config.is_rust_llvm(target) {
2047 cmd.arg("--system-llvm");
2048 }
2049
2050 if !builder.config.dry_run() && suite.ends_with("fulldeps") {
2055 let llvm_libdir =
2056 command(&llvm_config).arg("--libdir").run_capture_stdout(builder).stdout();
2057 let link_llvm = if target.is_msvc() {
2058 format!("-Clink-arg=-LIBPATH:{llvm_libdir}")
2059 } else {
2060 format!("-Clink-arg=-L{llvm_libdir}")
2061 };
2062 cmd.arg("--host-rustcflags").arg(link_llvm);
2063 }
2064
2065 if !builder.config.dry_run() && matches!(mode, "run-make" | "coverage-run") {
2066 let llvm_bin_path = llvm_config
2071 .parent()
2072 .expect("Expected llvm-config to be contained in directory");
2073 assert!(llvm_bin_path.is_dir());
2074 cmd.arg("--llvm-bin-dir").arg(llvm_bin_path);
2075 }
2076
2077 if !builder.config.dry_run() && mode == "run-make" {
2078 if builder.config.lld_enabled {
2080 let lld_install_root =
2081 builder.ensure(llvm::Lld { target: builder.config.host_target });
2082
2083 let lld_bin_path = lld_install_root.join("bin");
2084
2085 let old_path = env::var_os("PATH").unwrap_or_default();
2086 let new_path = env::join_paths(
2087 std::iter::once(lld_bin_path).chain(env::split_paths(&old_path)),
2088 )
2089 .expect("Could not add LLD bin path to PATH");
2090 cmd.env("PATH", new_path);
2091 }
2092 }
2093 }
2094
2095 if !builder.config.dry_run() && mode == "run-make" {
2098 let mut cflags = builder.cc_handled_clags(target, CLang::C);
2099 cflags.extend(builder.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::C));
2100 let mut cxxflags = builder.cc_handled_clags(target, CLang::Cxx);
2101 cxxflags.extend(builder.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::Cxx));
2102 cmd.arg("--cc")
2103 .arg(builder.cc(target))
2104 .arg("--cxx")
2105 .arg(builder.cxx(target).unwrap())
2106 .arg("--cflags")
2107 .arg(cflags.join(" "))
2108 .arg("--cxxflags")
2109 .arg(cxxflags.join(" "));
2110 copts_passed = true;
2111 if let Some(ar) = builder.ar(target) {
2112 cmd.arg("--ar").arg(ar);
2113 }
2114 }
2115
2116 if !llvm_components_passed {
2117 cmd.arg("--llvm-components").arg("");
2118 }
2119 if !copts_passed {
2120 cmd.arg("--cc")
2121 .arg("")
2122 .arg("--cxx")
2123 .arg("")
2124 .arg("--cflags")
2125 .arg("")
2126 .arg("--cxxflags")
2127 .arg("");
2128 }
2129
2130 if builder.remote_tested(target) {
2131 cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient));
2132 } else if let Some(tool) = builder.runner(target) {
2133 cmd.arg("--runner").arg(tool);
2134 }
2135
2136 if suite != "mir-opt" {
2137 if !builder.config.dry_run() && target.is_msvc() {
2143 for (k, v) in builder.cc[&target].env() {
2144 if k != "PATH" {
2145 cmd.env(k, v);
2146 }
2147 }
2148 }
2149 }
2150
2151 if !builder.config.dry_run()
2153 && target.contains("msvc")
2154 && builder.config.sanitizers_enabled(target)
2155 {
2156 cmd.env("ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE", "1");
2159 let asan_runtime_path = builder.cc[&target].path().parent().unwrap().to_path_buf();
2161 let old_path = cmd
2162 .get_envs()
2163 .find_map(|(k, v)| (k == "PATH").then_some(v))
2164 .flatten()
2165 .map_or_else(|| env::var_os("PATH").unwrap_or_default(), |v| v.to_owned());
2166 let new_path = env::join_paths(
2167 env::split_paths(&old_path).chain(std::iter::once(asan_runtime_path)),
2168 )
2169 .expect("Could not add ASAN runtime path to PATH");
2170 cmd.env("PATH", new_path);
2171 }
2172
2173 cmd.env_remove("CARGO");
2176
2177 cmd.env("RUSTC_BOOTSTRAP", "1");
2178 cmd.env("RUSTC_FORCE_RUSTC_VERSION", "compiletest");
2181 cmd.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
2182 builder.add_rust_test_threads(&mut cmd);
2183
2184 if builder.config.sanitizers_enabled(target) {
2185 cmd.env("RUSTC_SANITIZER_SUPPORT", "1");
2186 }
2187
2188 if builder.config.profiler_enabled(target) {
2189 cmd.arg("--profiler-runtime");
2190 }
2191
2192 cmd.env("RUST_TEST_TMPDIR", builder.tempdir());
2193
2194 cmd.arg("--adb-path").arg("adb");
2195 cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
2196 if target.contains("android") && !builder.config.dry_run() {
2197 cmd.arg("--android-cross-path")
2199 .arg(builder.cc(target).parent().unwrap().parent().unwrap());
2200 } else {
2201 cmd.arg("--android-cross-path").arg("");
2202 }
2203
2204 if builder.config.cmd.rustfix_coverage() {
2205 cmd.arg("--rustfix-coverage");
2206 }
2207
2208 cmd.arg("--channel").arg(&builder.config.channel);
2209
2210 if !builder.config.omit_git_hash {
2211 cmd.arg("--git-hash");
2212 }
2213
2214 let git_config = builder.config.git_config();
2215 cmd.arg("--nightly-branch").arg(git_config.nightly_branch);
2216 cmd.arg("--git-merge-commit-email").arg(git_config.git_merge_commit_email);
2217 cmd.force_coloring_in_ci();
2218
2219 #[cfg(feature = "build-metrics")]
2220 builder.metrics.begin_test_suite(
2221 build_helper::metrics::TestSuiteMetadata::Compiletest {
2222 suite: suite.into(),
2223 mode: mode.into(),
2224 compare_mode: None,
2225 target: self.target.triple.to_string(),
2226 host: self.compiler.host.triple.to_string(),
2227 stage: self.compiler.stage,
2228 },
2229 builder,
2230 );
2231
2232 let _group = builder.msg(
2233 Kind::Test,
2234 format!("compiletest suite={suite} mode={mode}"),
2235 Mode::ToolBootstrap,
2237 compiler,
2238 target,
2239 );
2240 try_run_tests(builder, &mut cmd, false);
2241
2242 if let Some(compare_mode) = compare_mode {
2243 cmd.arg("--compare-mode").arg(compare_mode);
2244
2245 #[cfg(feature = "build-metrics")]
2246 builder.metrics.begin_test_suite(
2247 build_helper::metrics::TestSuiteMetadata::Compiletest {
2248 suite: suite.into(),
2249 mode: mode.into(),
2250 compare_mode: Some(compare_mode.into()),
2251 target: self.target.triple.to_string(),
2252 host: self.compiler.host.triple.to_string(),
2253 stage: self.compiler.stage,
2254 },
2255 builder,
2256 );
2257
2258 builder.info(&format!(
2259 "Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
2260 suite, mode, compare_mode, &compiler.host, target
2261 ));
2262 let _time = helpers::timeit(builder);
2263 try_run_tests(builder, &mut cmd, false);
2264 }
2265 }
2266}
2267
2268#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2269struct BookTest {
2270 compiler: Compiler,
2271 path: PathBuf,
2272 name: &'static str,
2273 is_ext_doc: bool,
2274 dependencies: Vec<&'static str>,
2275}
2276
2277impl Step for BookTest {
2278 type Output = ();
2279 const ONLY_HOSTS: bool = true;
2280
2281 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2282 run.never()
2283 }
2284
2285 fn run(self, builder: &Builder<'_>) {
2289 if self.is_ext_doc {
2299 self.run_ext_doc(builder);
2300 } else {
2301 self.run_local_doc(builder);
2302 }
2303 }
2304}
2305
2306impl BookTest {
2307 fn run_ext_doc(self, builder: &Builder<'_>) {
2310 let compiler = self.compiler;
2311
2312 builder.std(compiler, compiler.host);
2313
2314 let mut rustdoc_path = builder.rustdoc_for_compiler(compiler);
2317 rustdoc_path.pop();
2318 let old_path = env::var_os("PATH").unwrap_or_default();
2319 let new_path = env::join_paths(iter::once(rustdoc_path).chain(env::split_paths(&old_path)))
2320 .expect("could not add rustdoc to PATH");
2321
2322 let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
2323 let path = builder.src.join(&self.path);
2324 rustbook_cmd.env("RUSTC_BOOTSTRAP", "1");
2326 rustbook_cmd.env("PATH", new_path).arg("test").arg(path);
2327
2328 let libs = if !self.dependencies.is_empty() {
2333 let mut lib_paths = vec![];
2334 for dep in self.dependencies {
2335 let mode = Mode::ToolRustc;
2336 let target = builder.config.host_target;
2337 let cargo = tool::prepare_tool_cargo(
2338 builder,
2339 compiler,
2340 mode,
2341 target,
2342 Kind::Build,
2343 dep,
2344 SourceType::Submodule,
2345 &[],
2346 );
2347
2348 let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, target))
2349 .with_prefix(PathBuf::from(dep).file_name().and_then(|v| v.to_str()).unwrap());
2350
2351 let output_paths = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false);
2352 let directories = output_paths
2353 .into_iter()
2354 .filter_map(|p| p.parent().map(ToOwned::to_owned))
2355 .fold(HashSet::new(), |mut set, dir| {
2356 set.insert(dir);
2357 set
2358 });
2359
2360 lib_paths.extend(directories);
2361 }
2362 lib_paths
2363 } else {
2364 vec![]
2365 };
2366
2367 if !libs.is_empty() {
2368 let paths = libs
2369 .into_iter()
2370 .map(|path| path.into_os_string())
2371 .collect::<Vec<OsString>>()
2372 .join(OsStr::new(","));
2373 rustbook_cmd.args([OsString::from("--library-path"), paths]);
2374 }
2375
2376 builder.add_rust_test_threads(&mut rustbook_cmd);
2377 let _guard = builder.msg(
2378 Kind::Test,
2379 format_args!("mdbook {}", self.path.display()),
2380 None,
2381 compiler,
2382 compiler.host,
2383 );
2384 let _time = helpers::timeit(builder);
2385 let toolstate = if rustbook_cmd.delay_failure().run(builder) {
2386 ToolState::TestPass
2387 } else {
2388 ToolState::TestFail
2389 };
2390 builder.save_toolstate(self.name, toolstate);
2391 }
2392
2393 fn run_local_doc(self, builder: &Builder<'_>) {
2395 let compiler = self.compiler;
2396 let host = self.compiler.host;
2397
2398 builder.std(compiler, host);
2399
2400 let _guard = builder.msg(Kind::Test, format!("book {}", self.name), None, compiler, host);
2401
2402 let mut stack = vec![builder.src.join(self.path)];
2405 let _time = helpers::timeit(builder);
2406 let mut files = Vec::new();
2407 while let Some(p) = stack.pop() {
2408 if p.is_dir() {
2409 stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
2410 continue;
2411 }
2412
2413 if p.extension().and_then(|s| s.to_str()) != Some("md") {
2414 continue;
2415 }
2416
2417 files.push(p);
2418 }
2419
2420 files.sort();
2421
2422 for file in files {
2423 markdown_test(builder, compiler, &file);
2424 }
2425 }
2426}
2427
2428macro_rules! test_book {
2429 ($(
2430 $name:ident, $path:expr, $book_name:expr,
2431 default=$default:expr
2432 $(,submodules = $submodules:expr)?
2433 $(,dependencies=$dependencies:expr)?
2434 ;
2435 )+) => {
2436 $(
2437 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
2438 pub struct $name {
2439 compiler: Compiler,
2440 }
2441
2442 impl Step for $name {
2443 type Output = ();
2444 const DEFAULT: bool = $default;
2445 const ONLY_HOSTS: bool = true;
2446
2447 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2448 run.path($path)
2449 }
2450
2451 fn make_run(run: RunConfig<'_>) {
2452 run.builder.ensure($name {
2453 compiler: run.builder.compiler(run.builder.top_stage, run.target),
2454 });
2455 }
2456
2457 fn run(self, builder: &Builder<'_>) {
2458 $(
2459 for submodule in $submodules {
2460 builder.require_submodule(submodule, None);
2461 }
2462 )*
2463
2464 let dependencies = vec![];
2465 $(
2466 let mut dependencies = dependencies;
2467 for dep in $dependencies {
2468 dependencies.push(dep);
2469 }
2470 )?
2471
2472 builder.ensure(BookTest {
2473 compiler: self.compiler,
2474 path: PathBuf::from($path),
2475 name: $book_name,
2476 is_ext_doc: !$default,
2477 dependencies,
2478 });
2479 }
2480 }
2481 )+
2482 }
2483}
2484
2485test_book!(
2486 Nomicon, "src/doc/nomicon", "nomicon", default=false, submodules=["src/doc/nomicon"];
2487 Reference, "src/doc/reference", "reference", default=false, submodules=["src/doc/reference"];
2488 RustdocBook, "src/doc/rustdoc", "rustdoc", default=true;
2489 RustcBook, "src/doc/rustc", "rustc", default=true;
2490 RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false, submodules=["src/doc/rust-by-example"];
2491 EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false, submodules=["src/doc/embedded-book"];
2492 TheBook, "src/doc/book", "book", default=false, submodules=["src/doc/book"], dependencies=["src/doc/book/packages/trpl"];
2493 UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
2494 EditionGuide, "src/doc/edition-guide", "edition-guide", default=false, submodules=["src/doc/edition-guide"];
2495);
2496
2497#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2498pub struct ErrorIndex {
2499 compilers: RustcPrivateCompilers,
2500}
2501
2502impl Step for ErrorIndex {
2503 type Output = ();
2504 const DEFAULT: bool = true;
2505 const ONLY_HOSTS: bool = true;
2506
2507 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2508 run.path("src/tools/error_index_generator").alias("error-index")
2511 }
2512
2513 fn make_run(run: RunConfig<'_>) {
2514 let compilers = RustcPrivateCompilers::new(
2518 run.builder,
2519 run.builder.top_stage,
2520 run.builder.config.host_target,
2521 );
2522 run.builder.ensure(ErrorIndex { compilers });
2523 }
2524
2525 fn run(self, builder: &Builder<'_>) {
2532 let target_compiler = self.compilers.target_compiler();
2534
2535 let dir = testdir(builder, target_compiler.host);
2536 t!(fs::create_dir_all(&dir));
2537 let output = dir.join("error-index.md");
2538
2539 let mut tool = tool::ErrorIndex::command(builder, self.compilers);
2540 tool.arg("markdown").arg(&output);
2541
2542 let guard = builder.msg(
2543 Kind::Test,
2544 "error-index",
2545 None,
2546 self.compilers.build_compiler(),
2547 target_compiler.host,
2548 );
2549 let _time = helpers::timeit(builder);
2550 tool.run_capture(builder);
2551 drop(guard);
2552 builder.std(target_compiler, target_compiler.host);
2555 markdown_test(builder, target_compiler, &output);
2556 }
2557}
2558
2559fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool {
2560 if let Ok(contents) = fs::read_to_string(markdown)
2561 && !contents.contains("```")
2562 {
2563 return true;
2564 }
2565
2566 builder.verbose(|| println!("doc tests for: {}", markdown.display()));
2567 let mut cmd = builder.rustdoc_cmd(compiler);
2568 builder.add_rust_test_threads(&mut cmd);
2569 cmd.arg("-Z");
2571 cmd.arg("unstable-options");
2572 cmd.arg("--test");
2573 cmd.arg(markdown);
2574 cmd.env("RUSTC_BOOTSTRAP", "1");
2575
2576 let test_args = builder.config.test_args().join(" ");
2577 cmd.arg("--test-args").arg(test_args);
2578
2579 cmd = cmd.delay_failure();
2580 if !builder.config.verbose_tests {
2581 cmd.run_capture(builder).is_success()
2582 } else {
2583 cmd.run(builder)
2584 }
2585}
2586
2587#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2592pub struct CrateLibrustc {
2593 compiler: Compiler,
2594 target: TargetSelection,
2595 crates: Vec<String>,
2596}
2597
2598impl Step for CrateLibrustc {
2599 type Output = ();
2600 const DEFAULT: bool = true;
2601 const ONLY_HOSTS: bool = true;
2602
2603 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2604 run.crate_or_deps("rustc-main").path("compiler")
2605 }
2606
2607 fn make_run(run: RunConfig<'_>) {
2608 let builder = run.builder;
2609 let host = run.build_triple();
2610 let compiler = builder.compiler_for(builder.top_stage, host, host);
2611 let crates = run.make_run_crates(Alias::Compiler);
2612
2613 builder.ensure(CrateLibrustc { compiler, target: run.target, crates });
2614 }
2615
2616 fn run(self, builder: &Builder<'_>) {
2617 builder.std(self.compiler, self.target);
2618
2619 builder.ensure(Crate {
2621 compiler: self.compiler,
2622 target: self.target,
2623 mode: Mode::Rustc,
2624 crates: self.crates,
2625 });
2626 }
2627
2628 fn metadata(&self) -> Option<StepMetadata> {
2629 Some(StepMetadata::test("CrateLibrustc", self.target))
2630 }
2631}
2632
2633fn run_cargo_test<'a>(
2637 cargo: builder::Cargo,
2638 libtest_args: &[&str],
2639 crates: &[String],
2640 description: impl Into<Option<&'a str>>,
2641 target: TargetSelection,
2642 builder: &Builder<'_>,
2643) -> bool {
2644 let compiler = cargo.compiler();
2645 let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, target, builder);
2646 let _time = helpers::timeit(builder);
2647 let _group =
2648 description.into().and_then(|what| builder.msg(Kind::Test, what, None, compiler, target));
2649
2650 #[cfg(feature = "build-metrics")]
2651 builder.metrics.begin_test_suite(
2652 build_helper::metrics::TestSuiteMetadata::CargoPackage {
2653 crates: crates.iter().map(|c| c.to_string()).collect(),
2654 target: target.triple.to_string(),
2655 host: compiler.host.triple.to_string(),
2656 stage: compiler.stage,
2657 },
2658 builder,
2659 );
2660 add_flags_and_try_run_tests(builder, &mut cargo)
2661}
2662
2663fn prepare_cargo_test(
2665 cargo: builder::Cargo,
2666 libtest_args: &[&str],
2667 crates: &[String],
2668 target: TargetSelection,
2669 builder: &Builder<'_>,
2670) -> BootstrapCommand {
2671 let compiler = cargo.compiler();
2672 let mut cargo: BootstrapCommand = cargo.into();
2673
2674 if builder.config.cmd.bless() && !cargo.get_envs().any(|v| v.0 == "RUSTC_BLESS") {
2678 cargo.env("RUSTC_BLESS", "Gesundheit");
2679 }
2680
2681 if builder.kind == Kind::Test && !builder.fail_fast {
2685 cargo.arg("--no-fail-fast");
2686 }
2687
2688 if builder.config.json_output {
2689 cargo.arg("--message-format=json");
2690 }
2691
2692 match builder.doc_tests {
2693 DocTests::Only => {
2694 cargo.arg("--doc");
2695 }
2696 DocTests::No => {
2697 cargo.args(["--bins", "--examples", "--tests", "--benches"]);
2698 }
2699 DocTests::Yes => {}
2700 }
2701
2702 for krate in crates {
2703 cargo.arg("-p").arg(krate);
2704 }
2705
2706 cargo.arg("--").args(builder.config.test_args()).args(libtest_args);
2707 if !builder.config.verbose_tests {
2708 cargo.arg("--quiet");
2709 }
2710
2711 if builder.kind != Kind::Miri {
2720 let mut dylib_paths = builder.rustc_lib_paths(compiler);
2721 dylib_paths.push(builder.sysroot_target_libdir(compiler, target));
2722 helpers::add_dylib_path(dylib_paths, &mut cargo);
2723 }
2724
2725 if builder.remote_tested(target) {
2726 cargo.env(
2727 format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
2728 format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
2729 );
2730 } else if let Some(tool) = builder.runner(target) {
2731 cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), tool);
2732 }
2733
2734 cargo
2735}
2736
2737#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2745pub struct Crate {
2746 pub compiler: Compiler,
2747 pub target: TargetSelection,
2748 pub mode: Mode,
2749 pub crates: Vec<String>,
2750}
2751
2752impl Step for Crate {
2753 type Output = ();
2754 const DEFAULT: bool = true;
2755
2756 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2757 run.crate_or_deps("sysroot").crate_or_deps("coretests").crate_or_deps("alloctests")
2758 }
2759
2760 fn make_run(run: RunConfig<'_>) {
2761 let builder = run.builder;
2762 let host = run.build_triple();
2763 let compiler = builder.compiler_for(builder.top_stage, host, host);
2764 let crates = run
2765 .paths
2766 .iter()
2767 .map(|p| builder.crate_paths[&p.assert_single_path().path].clone())
2768 .collect();
2769
2770 builder.ensure(Crate { compiler, target: run.target, mode: Mode::Std, crates });
2771 }
2772
2773 fn run(self, builder: &Builder<'_>) {
2782 let compiler = self.compiler;
2783 let target = self.target;
2784 let mode = self.mode;
2785
2786 builder.ensure(Std::new(compiler, compiler.host).force_recompile(true));
2789
2790 let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
2795
2796 let mut cargo = if builder.kind == Kind::Miri {
2797 if builder.top_stage == 0 {
2798 eprintln!("ERROR: `x.py miri` requires stage 1 or higher");
2799 std::process::exit(1);
2800 }
2801
2802 let mut cargo = builder::Cargo::new(
2805 builder,
2806 compiler,
2807 mode,
2808 SourceType::InTree,
2809 target,
2810 Kind::MiriTest,
2811 );
2812 cargo.env("MIRI_REPLACE_LIBRS_IF_NOT_TEST", "1");
2824 cargo.rustflag("-Zforce-unstable-if-unmarked");
2828 cargo
2829 } else {
2830 if !builder.config.is_host_target(target) {
2832 builder.ensure(compile::Std::new(compiler, target).force_recompile(true));
2833 builder.ensure(RemoteCopyLibs { compiler, target });
2834 }
2835
2836 builder::Cargo::new(builder, compiler, mode, SourceType::InTree, target, builder.kind)
2838 };
2839
2840 match mode {
2841 Mode::Std => {
2842 if builder.kind == Kind::Miri {
2843 cargo
2849 .arg("--manifest-path")
2850 .arg(builder.src.join("library/sysroot/Cargo.toml"));
2851 } else {
2852 compile::std_cargo(builder, target, &mut cargo);
2853 }
2854 }
2855 Mode::Rustc => {
2856 compile::rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates);
2857 }
2858 _ => panic!("can only test libraries"),
2859 };
2860
2861 let mut crates = self.crates.clone();
2862 if crates.iter().any(|crate_| crate_ == "core") {
2867 crates.push("coretests".to_owned());
2868 }
2869 if crates.iter().any(|crate_| crate_ == "alloc") {
2870 crates.push("alloctests".to_owned());
2871 }
2872
2873 run_cargo_test(cargo, &[], &crates, &*crate_description(&self.crates), target, builder);
2874 }
2875}
2876
2877#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2879pub struct CrateRustdoc {
2880 host: TargetSelection,
2881}
2882
2883impl Step for CrateRustdoc {
2884 type Output = ();
2885 const DEFAULT: bool = true;
2886 const ONLY_HOSTS: bool = true;
2887
2888 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2889 run.paths(&["src/librustdoc", "src/tools/rustdoc"])
2890 }
2891
2892 fn make_run(run: RunConfig<'_>) {
2893 let builder = run.builder;
2894
2895 builder.ensure(CrateRustdoc { host: run.target });
2896 }
2897
2898 fn run(self, builder: &Builder<'_>) {
2899 let target = self.host;
2900
2901 let compiler = if builder.download_rustc() {
2902 builder.compiler(builder.top_stage, target)
2903 } else {
2904 builder.compiler_for(builder.top_stage, target, target)
2909 };
2910 builder.std(compiler, target);
2915 builder.ensure(compile::Rustc::new(compiler, target));
2916
2917 let mut cargo = tool::prepare_tool_cargo(
2918 builder,
2919 compiler,
2920 Mode::ToolRustc,
2921 target,
2922 builder.kind,
2923 "src/tools/rustdoc",
2924 SourceType::InTree,
2925 &[],
2926 );
2927 if self.host.contains("musl") {
2928 cargo.arg("'-Ctarget-feature=-crt-static'");
2929 }
2930
2931 let libdir = if builder.download_rustc() {
2958 builder.rustc_libdir(compiler)
2959 } else {
2960 builder.sysroot_target_libdir(compiler, target).to_path_buf()
2961 };
2962 let mut dylib_path = dylib_path();
2963 dylib_path.insert(0, PathBuf::from(&*libdir));
2964 cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
2965
2966 run_cargo_test(cargo, &[], &["rustdoc:0.0.0".to_string()], "rustdoc", target, builder);
2967 }
2968}
2969
2970#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2971pub struct CrateRustdocJsonTypes {
2972 host: TargetSelection,
2973}
2974
2975impl Step for CrateRustdocJsonTypes {
2976 type Output = ();
2977 const DEFAULT: bool = true;
2978 const ONLY_HOSTS: bool = true;
2979
2980 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2981 run.path("src/rustdoc-json-types")
2982 }
2983
2984 fn make_run(run: RunConfig<'_>) {
2985 let builder = run.builder;
2986
2987 builder.ensure(CrateRustdocJsonTypes { host: run.target });
2988 }
2989
2990 fn run(self, builder: &Builder<'_>) {
2991 let target = self.host;
2992
2993 let compiler = builder.compiler_for(builder.top_stage, target, target);
2998 builder.ensure(compile::Rustc::new(compiler, target));
2999
3000 let cargo = tool::prepare_tool_cargo(
3001 builder,
3002 compiler,
3003 Mode::ToolRustc,
3004 target,
3005 builder.kind,
3006 "src/rustdoc-json-types",
3007 SourceType::InTree,
3008 &[],
3009 );
3010
3011 let libtest_args = if self.host.contains("musl") {
3013 ["'-Ctarget-feature=-crt-static'"].as_slice()
3014 } else {
3015 &[]
3016 };
3017
3018 run_cargo_test(
3019 cargo,
3020 libtest_args,
3021 &["rustdoc-json-types".to_string()],
3022 "rustdoc-json-types",
3023 target,
3024 builder,
3025 );
3026 }
3027}
3028
3029#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3039pub struct RemoteCopyLibs {
3040 compiler: Compiler,
3041 target: TargetSelection,
3042}
3043
3044impl Step for RemoteCopyLibs {
3045 type Output = ();
3046
3047 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3048 run.never()
3049 }
3050
3051 fn run(self, builder: &Builder<'_>) {
3052 let compiler = self.compiler;
3053 let target = self.target;
3054 if !builder.remote_tested(target) {
3055 return;
3056 }
3057
3058 builder.std(compiler, target);
3059
3060 builder.info(&format!("REMOTE copy libs to emulator ({target})"));
3061
3062 let remote_test_server =
3063 builder.ensure(tool::RemoteTestServer { build_compiler: compiler, target });
3064
3065 let tool = builder.tool_exe(Tool::RemoteTestClient);
3067 let mut cmd = command(&tool);
3068 cmd.arg("spawn-emulator")
3069 .arg(target.triple)
3070 .arg(&remote_test_server.tool_path)
3071 .arg(builder.tempdir());
3072 if let Some(rootfs) = builder.qemu_rootfs(target) {
3073 cmd.arg(rootfs);
3074 }
3075 cmd.run(builder);
3076
3077 for f in t!(builder.sysroot_target_libdir(compiler, target).read_dir()) {
3079 let f = t!(f);
3080 if helpers::is_dylib(&f.path()) {
3081 command(&tool).arg("push").arg(f.path()).run(builder);
3082 }
3083 }
3084 }
3085}
3086
3087#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3088pub struct Distcheck;
3089
3090impl Step for Distcheck {
3091 type Output = ();
3092
3093 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3094 run.alias("distcheck")
3095 }
3096
3097 fn make_run(run: RunConfig<'_>) {
3098 run.builder.ensure(Distcheck);
3099 }
3100
3101 fn run(self, builder: &Builder<'_>) {
3110 builder.info("Distcheck");
3111 let dir = builder.tempdir().join("distcheck");
3112 let _ = fs::remove_dir_all(&dir);
3113 t!(fs::create_dir_all(&dir));
3114
3115 builder.ensure(dist::PlainSourceTarball);
3117 builder.ensure(dist::Src);
3118
3119 command("tar")
3120 .arg("-xf")
3121 .arg(builder.ensure(dist::PlainSourceTarball).tarball())
3122 .arg("--strip-components=1")
3123 .current_dir(&dir)
3124 .run(builder);
3125 command("./configure")
3126 .args(&builder.config.configure_args)
3127 .arg("--enable-vendor")
3128 .current_dir(&dir)
3129 .run(builder);
3130 command(helpers::make(&builder.config.host_target.triple))
3131 .arg("check")
3132 .current_dir(&dir)
3133 .run(builder);
3134
3135 builder.info("Distcheck rust-src");
3137 let dir = builder.tempdir().join("distcheck-src");
3138 let _ = fs::remove_dir_all(&dir);
3139 t!(fs::create_dir_all(&dir));
3140
3141 command("tar")
3142 .arg("-xf")
3143 .arg(builder.ensure(dist::Src).tarball())
3144 .arg("--strip-components=1")
3145 .current_dir(&dir)
3146 .run(builder);
3147
3148 let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml");
3149 command(&builder.initial_cargo)
3150 .env("RUSTC_BOOTSTRAP", "1")
3153 .arg("generate-lockfile")
3154 .arg("--manifest-path")
3155 .arg(&toml)
3156 .current_dir(&dir)
3157 .run(builder);
3158 }
3159}
3160
3161#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3162pub struct Bootstrap;
3163
3164impl Step for Bootstrap {
3165 type Output = ();
3166 const DEFAULT: bool = true;
3167 const ONLY_HOSTS: bool = true;
3168
3169 fn run(self, builder: &Builder<'_>) {
3171 let host = builder.config.host_target;
3172 let build_compiler = builder.compiler(0, host);
3173 let _guard =
3174 builder.msg(Kind::Test, "bootstrap", Mode::ToolBootstrap, build_compiler, host);
3175
3176 builder.build.require_submodule("src/tools/cargo", None);
3178
3179 let mut check_bootstrap = command(builder.python());
3180 check_bootstrap
3181 .args(["-m", "unittest", "bootstrap_test.py"])
3182 .env("BUILD_DIR", &builder.out)
3183 .env("BUILD_PLATFORM", builder.build.host_target.triple)
3184 .env("BOOTSTRAP_TEST_RUSTC_BIN", &builder.initial_rustc)
3185 .env("BOOTSTRAP_TEST_CARGO_BIN", &builder.initial_cargo)
3186 .current_dir(builder.src.join("src/bootstrap/"));
3187 check_bootstrap.delay_failure().run(builder);
3190
3191 let mut cargo = tool::prepare_tool_cargo(
3192 builder,
3193 build_compiler,
3194 Mode::ToolBootstrap,
3195 host,
3196 Kind::Test,
3197 "src/bootstrap",
3198 SourceType::InTree,
3199 &[],
3200 );
3201
3202 cargo.release_build(false);
3203
3204 cargo
3205 .rustflag("-Cdebuginfo=2")
3206 .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
3207 .env("INSTA_WORKSPACE_ROOT", &builder.src)
3209 .env("RUSTC_BOOTSTRAP", "1");
3210
3211 run_cargo_test(cargo, &["--test-threads=1"], &[], None, host, builder);
3214 }
3215
3216 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3217 let runs_on_ci = run.builder.config.is_running_on_ci;
3221 run.path("src/bootstrap").default_condition(runs_on_ci)
3222 }
3223
3224 fn make_run(run: RunConfig<'_>) {
3225 run.builder.ensure(Bootstrap);
3226 }
3227}
3228
3229#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3230pub struct TierCheck {
3231 pub compiler: Compiler,
3232}
3233
3234impl Step for TierCheck {
3235 type Output = ();
3236 const DEFAULT: bool = true;
3237 const ONLY_HOSTS: bool = true;
3238
3239 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3240 run.path("src/tools/tier-check")
3241 }
3242
3243 fn make_run(run: RunConfig<'_>) {
3244 let compiler = run.builder.compiler_for(
3245 run.builder.top_stage,
3246 run.builder.build.host_target,
3247 run.target,
3248 );
3249 run.builder.ensure(TierCheck { compiler });
3250 }
3251
3252 fn run(self, builder: &Builder<'_>) {
3254 builder.std(self.compiler, self.compiler.host);
3255 let mut cargo = tool::prepare_tool_cargo(
3256 builder,
3257 self.compiler,
3258 Mode::ToolStd,
3259 self.compiler.host,
3260 Kind::Run,
3261 "src/tools/tier-check",
3262 SourceType::InTree,
3263 &[],
3264 );
3265 cargo.arg(builder.src.join("src/doc/rustc/src/platform-support.md"));
3266 cargo.arg(builder.rustc(self.compiler));
3267 if builder.is_verbose() {
3268 cargo.arg("--verbose");
3269 }
3270
3271 let _guard = builder.msg(
3272 Kind::Test,
3273 "platform support check",
3274 None,
3275 self.compiler,
3276 self.compiler.host,
3277 );
3278 BootstrapCommand::from(cargo).delay_failure().run(builder);
3279 }
3280}
3281
3282#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3283pub struct LintDocs {
3284 pub compiler: Compiler,
3285 pub target: TargetSelection,
3286}
3287
3288impl Step for LintDocs {
3289 type Output = ();
3290 const DEFAULT: bool = true;
3291 const ONLY_HOSTS: bool = true;
3292
3293 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3294 run.path("src/tools/lint-docs")
3295 }
3296
3297 fn make_run(run: RunConfig<'_>) {
3298 run.builder.ensure(LintDocs {
3299 compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
3300 target: run.target,
3301 });
3302 }
3303
3304 fn run(self, builder: &Builder<'_>) {
3307 builder
3308 .ensure(crate::core::build_steps::doc::RustcBook::validate(self.compiler, self.target));
3309 }
3310}
3311
3312#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3313pub struct RustInstaller;
3314
3315impl Step for RustInstaller {
3316 type Output = ();
3317 const ONLY_HOSTS: bool = true;
3318 const DEFAULT: bool = true;
3319
3320 fn run(self, builder: &Builder<'_>) {
3322 let bootstrap_host = builder.config.host_target;
3323 let build_compiler = builder.compiler(0, bootstrap_host);
3324 let cargo = tool::prepare_tool_cargo(
3325 builder,
3326 build_compiler,
3327 Mode::ToolBootstrap,
3328 bootstrap_host,
3329 Kind::Test,
3330 "src/tools/rust-installer",
3331 SourceType::InTree,
3332 &[],
3333 );
3334
3335 let _guard =
3336 builder.msg(Kind::Test, "rust-installer", None, build_compiler, bootstrap_host);
3337 run_cargo_test(cargo, &[], &[], None, bootstrap_host, builder);
3338
3339 if bootstrap_host != "x86_64-unknown-linux-gnu" {
3343 return;
3344 }
3345
3346 let mut cmd = command(builder.src.join("src/tools/rust-installer/test.sh"));
3347 let tmpdir = testdir(builder, build_compiler.host).join("rust-installer");
3348 let _ = std::fs::remove_dir_all(&tmpdir);
3349 let _ = std::fs::create_dir_all(&tmpdir);
3350 cmd.current_dir(&tmpdir);
3351 cmd.env("CARGO_TARGET_DIR", tmpdir.join("cargo-target"));
3352 cmd.env("CARGO", &builder.initial_cargo);
3353 cmd.env("RUSTC", &builder.initial_rustc);
3354 cmd.env("TMP_DIR", &tmpdir);
3355 cmd.delay_failure().run(builder);
3356 }
3357
3358 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3359 run.path("src/tools/rust-installer")
3360 }
3361
3362 fn make_run(run: RunConfig<'_>) {
3363 run.builder.ensure(Self);
3364 }
3365}
3366
3367#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3368pub struct TestHelpers {
3369 pub target: TargetSelection,
3370}
3371
3372impl Step for TestHelpers {
3373 type Output = ();
3374
3375 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3376 run.path("tests/auxiliary/rust_test_helpers.c")
3377 }
3378
3379 fn make_run(run: RunConfig<'_>) {
3380 run.builder.ensure(TestHelpers { target: run.target })
3381 }
3382
3383 fn run(self, builder: &Builder<'_>) {
3386 if builder.config.dry_run() {
3387 return;
3388 }
3389 let target = if self.target == "x86_64-fortanix-unknown-sgx" {
3393 TargetSelection::from_user("x86_64-unknown-linux-gnu")
3394 } else {
3395 self.target
3396 };
3397 let dst = builder.test_helpers_out(target);
3398 let src = builder.src.join("tests/auxiliary/rust_test_helpers.c");
3399 if up_to_date(&src, &dst.join("librust_test_helpers.a")) {
3400 return;
3401 }
3402
3403 let _guard = builder.msg_unstaged(Kind::Build, "test helpers", target);
3404 t!(fs::create_dir_all(&dst));
3405 let mut cfg = cc::Build::new();
3406
3407 if !target.is_msvc() {
3411 if let Some(ar) = builder.ar(target) {
3412 cfg.archiver(ar);
3413 }
3414 cfg.compiler(builder.cc(target));
3415 }
3416 cfg.cargo_metadata(false)
3417 .out_dir(&dst)
3418 .target(&target.triple)
3419 .host(&builder.config.host_target.triple)
3420 .opt_level(0)
3421 .warnings(false)
3422 .debug(false)
3423 .file(builder.src.join("tests/auxiliary/rust_test_helpers.c"))
3424 .compile("rust_test_helpers");
3425 }
3426}
3427
3428#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3429pub struct CodegenCranelift {
3430 compiler: Compiler,
3431 target: TargetSelection,
3432}
3433
3434impl Step for CodegenCranelift {
3435 type Output = ();
3436 const DEFAULT: bool = true;
3437 const ONLY_HOSTS: bool = true;
3438
3439 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3440 run.paths(&["compiler/rustc_codegen_cranelift"])
3441 }
3442
3443 fn make_run(run: RunConfig<'_>) {
3444 let builder = run.builder;
3445 let host = run.build_triple();
3446 let compiler = run.builder.compiler_for(run.builder.top_stage, host, host);
3447
3448 if builder.doc_tests == DocTests::Only {
3449 return;
3450 }
3451
3452 if builder.download_rustc() {
3453 builder.info("CI rustc uses the default codegen backend. skipping");
3454 return;
3455 }
3456
3457 if !target_supports_cranelift_backend(run.target) {
3458 builder.info("target not supported by rustc_codegen_cranelift. skipping");
3459 return;
3460 }
3461
3462 if builder.remote_tested(run.target) {
3463 builder.info("remote testing is not supported by rustc_codegen_cranelift. skipping");
3464 return;
3465 }
3466
3467 if !builder
3468 .config
3469 .enabled_codegen_backends(run.target)
3470 .contains(&CodegenBackendKind::Cranelift)
3471 {
3472 builder.info("cranelift not in rust.codegen-backends. skipping");
3473 return;
3474 }
3475
3476 builder.ensure(CodegenCranelift { compiler, target: run.target });
3477 }
3478
3479 fn run(self, builder: &Builder<'_>) {
3480 let compiler = self.compiler;
3481 let target = self.target;
3482
3483 builder.std(compiler, target);
3484
3485 let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
3490
3491 let build_cargo = || {
3492 let mut cargo = builder::Cargo::new(
3493 builder,
3494 compiler,
3495 Mode::Codegen, SourceType::InTree,
3497 target,
3498 Kind::Run,
3499 );
3500
3501 cargo.current_dir(&builder.src.join("compiler/rustc_codegen_cranelift"));
3502 cargo
3503 .arg("--manifest-path")
3504 .arg(builder.src.join("compiler/rustc_codegen_cranelift/build_system/Cargo.toml"));
3505 compile::rustc_cargo_env(builder, &mut cargo, target);
3506
3507 cargo.env("CARGO_BUILD_INCREMENTAL", "false");
3509
3510 cargo
3511 };
3512
3513 builder.info(&format!(
3514 "{} cranelift stage{} ({} -> {})",
3515 Kind::Test.description(),
3516 compiler.stage,
3517 &compiler.host,
3518 target
3519 ));
3520 let _time = helpers::timeit(builder);
3521
3522 let download_dir = builder.out.join("cg_clif_download");
3524
3525 let mut cargo = build_cargo();
3534 cargo
3535 .arg("--")
3536 .arg("test")
3537 .arg("--download-dir")
3538 .arg(&download_dir)
3539 .arg("--out-dir")
3540 .arg(builder.stage_out(compiler, Mode::ToolRustc).join("cg_clif"))
3541 .arg("--no-unstable-features")
3542 .arg("--use-backend")
3543 .arg("cranelift")
3544 .arg("--sysroot")
3546 .arg("llvm")
3547 .arg("--skip-test")
3550 .arg("testsuite.extended_sysroot");
3551
3552 cargo.into_cmd().run(builder);
3553 }
3554}
3555
3556#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3557pub struct CodegenGCC {
3558 compiler: Compiler,
3559 target: TargetSelection,
3560}
3561
3562impl Step for CodegenGCC {
3563 type Output = ();
3564 const DEFAULT: bool = true;
3565 const ONLY_HOSTS: bool = true;
3566
3567 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3568 run.paths(&["compiler/rustc_codegen_gcc"])
3569 }
3570
3571 fn make_run(run: RunConfig<'_>) {
3572 let builder = run.builder;
3573 let host = run.build_triple();
3574 let compiler = run.builder.compiler_for(run.builder.top_stage, host, host);
3575
3576 if builder.doc_tests == DocTests::Only {
3577 return;
3578 }
3579
3580 if builder.download_rustc() {
3581 builder.info("CI rustc uses the default codegen backend. skipping");
3582 return;
3583 }
3584
3585 let triple = run.target.triple;
3586 let target_supported =
3587 if triple.contains("linux") { triple.contains("x86_64") } else { false };
3588 if !target_supported {
3589 builder.info("target not supported by rustc_codegen_gcc. skipping");
3590 return;
3591 }
3592
3593 if builder.remote_tested(run.target) {
3594 builder.info("remote testing is not supported by rustc_codegen_gcc. skipping");
3595 return;
3596 }
3597
3598 if !builder.config.enabled_codegen_backends(run.target).contains(&CodegenBackendKind::Gcc) {
3599 builder.info("gcc not in rust.codegen-backends. skipping");
3600 return;
3601 }
3602
3603 builder.ensure(CodegenGCC { compiler, target: run.target });
3604 }
3605
3606 fn run(self, builder: &Builder<'_>) {
3607 let compiler = self.compiler;
3608 let target = self.target;
3609
3610 let gcc = builder.ensure(Gcc { target });
3611
3612 builder.ensure(
3613 compile::Std::new(compiler, target)
3614 .extra_rust_args(&["-Csymbol-mangling-version=v0", "-Cpanic=abort"]),
3615 );
3616
3617 let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
3622
3623 let build_cargo = || {
3624 let mut cargo = builder::Cargo::new(
3625 builder,
3626 compiler,
3627 Mode::Codegen, SourceType::InTree,
3629 target,
3630 Kind::Run,
3631 );
3632
3633 cargo.current_dir(&builder.src.join("compiler/rustc_codegen_gcc"));
3634 cargo
3635 .arg("--manifest-path")
3636 .arg(builder.src.join("compiler/rustc_codegen_gcc/build_system/Cargo.toml"));
3637 compile::rustc_cargo_env(builder, &mut cargo, target);
3638 add_cg_gcc_cargo_flags(&mut cargo, &gcc);
3639
3640 cargo.env("CARGO_BUILD_INCREMENTAL", "false");
3642 cargo.rustflag("-Cpanic=abort");
3643
3644 cargo
3645 };
3646
3647 builder.info(&format!(
3648 "{} GCC stage{} ({} -> {})",
3649 Kind::Test.description(),
3650 compiler.stage,
3651 &compiler.host,
3652 target
3653 ));
3654 let _time = helpers::timeit(builder);
3655
3656 let mut cargo = build_cargo();
3665
3666 cargo
3667 .env("CG_RUSTFLAGS", "-Alinker-messages")
3669 .arg("--")
3670 .arg("test")
3671 .arg("--use-backend")
3672 .arg("gcc")
3673 .arg("--gcc-path")
3674 .arg(gcc.libgccjit.parent().unwrap())
3675 .arg("--out-dir")
3676 .arg(builder.stage_out(compiler, Mode::ToolRustc).join("cg_gcc"))
3677 .arg("--release")
3678 .arg("--mini-tests")
3679 .arg("--std-tests");
3680 cargo.args(builder.config.test_args());
3681
3682 cargo.into_cmd().run(builder);
3683 }
3684}
3685
3686#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3691pub struct TestFloatParse {
3692 path: PathBuf,
3693 host: TargetSelection,
3694}
3695
3696impl Step for TestFloatParse {
3697 type Output = ();
3698 const ONLY_HOSTS: bool = true;
3699 const DEFAULT: bool = true;
3700
3701 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3702 run.path("src/tools/test-float-parse")
3703 }
3704
3705 fn make_run(run: RunConfig<'_>) {
3706 for path in run.paths {
3707 let path = path.assert_single_path().path.clone();
3708 run.builder.ensure(Self { path, host: run.target });
3709 }
3710 }
3711
3712 fn run(self, builder: &Builder<'_>) {
3713 let bootstrap_host = builder.config.host_target;
3714 let compiler = builder.compiler(builder.top_stage, bootstrap_host);
3715 let path = self.path.to_str().unwrap();
3716 let crate_name = self.path.iter().next_back().unwrap().to_str().unwrap();
3717
3718 builder.ensure(tool::TestFloatParse { host: self.host });
3719
3720 let mut cargo_test = tool::prepare_tool_cargo(
3722 builder,
3723 compiler,
3724 Mode::ToolStd,
3725 bootstrap_host,
3726 Kind::Test,
3727 path,
3728 SourceType::InTree,
3729 &[],
3730 );
3731 cargo_test.allow_features(tool::TestFloatParse::ALLOW_FEATURES);
3732
3733 run_cargo_test(cargo_test, &[], &[], crate_name, bootstrap_host, builder);
3734
3735 let mut cargo_run = tool::prepare_tool_cargo(
3737 builder,
3738 compiler,
3739 Mode::ToolStd,
3740 bootstrap_host,
3741 Kind::Run,
3742 path,
3743 SourceType::InTree,
3744 &[],
3745 );
3746 cargo_run.allow_features(tool::TestFloatParse::ALLOW_FEATURES);
3747
3748 if !matches!(env::var("FLOAT_PARSE_TESTS_NO_SKIP_HUGE").as_deref(), Ok("1") | Ok("true")) {
3749 cargo_run.args(["--", "--skip-huge"]);
3750 }
3751
3752 cargo_run.into_cmd().run(builder);
3753 }
3754}
3755
3756#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
3760pub struct CollectLicenseMetadata;
3761
3762impl Step for CollectLicenseMetadata {
3763 type Output = PathBuf;
3764 const ONLY_HOSTS: bool = true;
3765
3766 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3767 run.path("src/tools/collect-license-metadata")
3768 }
3769
3770 fn make_run(run: RunConfig<'_>) {
3771 run.builder.ensure(CollectLicenseMetadata);
3772 }
3773
3774 fn run(self, builder: &Builder<'_>) -> Self::Output {
3775 let Some(reuse) = &builder.config.reuse else {
3776 panic!("REUSE is required to collect the license metadata");
3777 };
3778
3779 let dest = builder.src.join("license-metadata.json");
3780
3781 let mut cmd = builder.tool_cmd(Tool::CollectLicenseMetadata);
3782 cmd.env("REUSE_EXE", reuse);
3783 cmd.env("DEST", &dest);
3784 cmd.env("ONLY_CHECK", "1");
3785 cmd.run(builder);
3786
3787 dest
3788 }
3789}