1use std::fs;
4use std::path::{Path, PathBuf};
5
6use crate::core::build_steps::compile::{
7 ArtifactKeepMode, add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo,
8 std_crates_for_make_run,
9};
10use crate::core::build_steps::tool;
11use crate::core::build_steps::tool::{
12 SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, ToolTargetBuildMode, get_tool_target_compiler,
13 prepare_tool_cargo,
14};
15use crate::core::builder::{
16 self, Alias, Builder, Cargo, CommandLineStep, Kind, RunConfig, ShouldRun, Step, StepMetadata,
17 crate_description,
18};
19use crate::core::config::TargetSelection;
20use crate::core::config::flags::Subcommand;
21use crate::utils::build_stamp::{self, BuildStamp};
22use crate::utils::helpers::t;
23use crate::{CodegenBackendKind, Compiler, Mode};
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28enum CheckKind {
29 Check,
30 Fix,
31}
32
33impl CheckKind {
34 fn to_kind(self) -> Kind {
35 match self {
36 CheckKind::Check => Kind::Check,
37 CheckKind::Fix => Kind::Fix,
38 }
39 }
40}
41
42#[derive(Debug, Clone, PartialEq, Eq, Hash)]
43pub struct Std {
44 pub build_compiler: Compiler,
46 pub target: TargetSelection,
47 crates: Vec<String>,
53}
54
55impl Std {
56 const CRATE_OR_DEPS: &[&str] = &["sysroot", "coretests", "alloctests"];
57}
58
59impl CommandLineStep for Std {
60 type Output = BuildStamp;
61
62 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
63 let mut run = run;
64 for c in Std::CRATE_OR_DEPS {
65 run = run.crate_or_deps(c);
66 }
67
68 run.path("library")
69 }
70
71 fn is_default_step(_builder: &Builder<'_>) -> bool {
72 true
73 }
74
75 fn make_run(run: RunConfig<'_>) {
76 if !run.builder.download_rustc() && run.builder.config.skip_std_check_if_no_download_rustc {
77 eprintln!(
78 "WARNING: `--skip-std-check-if-no-download-rustc` flag was passed and `rust.download-rustc` is not available. Skipping."
79 );
80 return;
81 }
82
83 if run.builder.config.compile_time_deps {
84 return;
86 }
87
88 let crates = std_crates_for_make_run(&run);
92 run.builder.ensure(Std {
93 build_compiler: prepare_compiler_for_check(run.builder, run.target, Mode::Std)
94 .build_compiler(),
95 target: run.target,
96 crates,
97 });
98 }
99
100 fn run(self, builder: &Builder<'_>) -> Self::Output {
101 let build_compiler = self.build_compiler;
102 let target = self.target;
103
104 let mut cargo = builder::Cargo::new(
105 builder,
106 build_compiler,
107 Mode::Std,
108 SourceType::InTree,
109 target,
110 builder.kind,
111 );
112
113 std_cargo(builder, target, &mut cargo, &self.crates);
114 if matches!(builder.config.cmd, Subcommand::Fix) {
115 cargo.arg("--lib");
117 }
118
119 let _guard = builder.msg(
120 builder.kind,
121 format_args!("library artifacts{}", crate_description(&self.crates)),
122 Mode::Std,
123 build_compiler,
124 target,
125 );
126
127 let check_stamp =
128 build_stamp::libstd_stamp(builder, build_compiler, target).with_prefix("check");
129 run_cargo(
130 builder,
131 cargo,
132 builder.config.free_args.clone(),
133 &check_stamp,
134 vec![],
135 ArtifactKeepMode::OnlyRmeta,
136 );
137
138 drop(_guard);
139
140 if !self.crates.iter().any(|krate| krate == "test") {
142 return check_stamp;
143 }
144
145 let mut cargo = builder::Cargo::new(
152 builder,
153 build_compiler,
154 Mode::Std,
155 SourceType::InTree,
156 target,
157 Kind::Check,
158 );
159
160 std_cargo(builder, target, &mut cargo, &self.crates);
161
162 let stamp =
163 build_stamp::libstd_stamp(builder, build_compiler, target).with_prefix("check-test");
164 let _guard = builder.msg(
165 Kind::Check,
166 "library test/bench/example targets",
167 Mode::Std,
168 build_compiler,
169 target,
170 );
171 run_cargo(
172 builder,
173 cargo,
174 builder.config.free_args.clone(),
175 &stamp,
176 vec![],
177 ArtifactKeepMode::OnlyRmeta,
178 );
179 check_stamp
180 }
181
182 fn metadata(&self) -> Option<StepMetadata> {
183 Some(StepMetadata::check("std", self.target).built_by(self.build_compiler))
184 }
185}
186
187#[derive(Debug, Clone, PartialEq, Eq, Hash)]
191struct RmetaSysroot {
192 host_dir: PathBuf,
193 target_dir: PathBuf,
194}
195
196impl RmetaSysroot {
197 fn from_stamp(
199 builder: &Builder<'_>,
200 stamp: BuildStamp,
201 target: TargetSelection,
202 directory: &Path,
203 ) -> Self {
204 let host_dir = directory.join("host");
205 let target_dir = directory.join(target);
206 let _ = fs::remove_dir_all(directory);
207 t!(fs::create_dir_all(directory));
208 add_to_sysroot(builder, &target_dir, &host_dir, &stamp);
209
210 Self { host_dir, target_dir }
211 }
212
213 fn configure_cargo(&self, cargo: &mut Cargo) {
216 cargo.append_to_env(
217 "RUSTC_ADDITIONAL_SYSROOT_PATHS",
218 format!("{},{}", self.host_dir.to_str().unwrap(), self.target_dir.to_str().unwrap()),
219 ",",
220 );
221 }
222}
223
224#[derive(Debug, Clone, PartialEq, Eq, Hash)]
231struct PrepareRustcRmetaSysroot {
232 build_compiler: CompilerForCheck,
233 target: TargetSelection,
234}
235
236impl PrepareRustcRmetaSysroot {
237 fn new(build_compiler: CompilerForCheck, target: TargetSelection) -> Self {
238 Self { build_compiler, target }
239 }
240}
241
242impl Step for PrepareRustcRmetaSysroot {
243 type Output = RmetaSysroot;
244
245 fn run(self, builder: &Builder<'_>) -> Self::Output {
246 let stamp = Rustc::check_rustc_for_preparing_sysroot(builder, &self);
248
249 let build_compiler = self.build_compiler.build_compiler();
250
251 let dir = builder
253 .out
254 .join(build_compiler.host)
255 .join(format!("stage{}-rustc-rmeta-artifacts", build_compiler.stage + 1));
256 RmetaSysroot::from_stamp(builder, stamp, self.target, &dir)
257 }
258}
259
260#[derive(Debug, Clone, PartialEq, Eq, Hash)]
267struct PrepareStdRmetaSysroot {
268 build_compiler: Compiler,
269 target: TargetSelection,
270}
271
272impl PrepareStdRmetaSysroot {
273 fn new(build_compiler: Compiler, target: TargetSelection) -> Self {
274 Self { build_compiler, target }
275 }
276}
277
278impl Step for PrepareStdRmetaSysroot {
279 type Output = RmetaSysroot;
280
281 fn run(self, builder: &Builder<'_>) -> Self::Output {
282 let stamp = builder.ensure(Std {
284 build_compiler: self.build_compiler,
285 target: self.target,
286 crates: vec![],
287 });
288
289 let dir = builder
291 .out
292 .join(self.build_compiler.host)
293 .join(format!("stage{}-std-rmeta-artifacts", self.build_compiler.stage));
294
295 RmetaSysroot::from_stamp(builder, stamp, self.target, &dir)
296 }
297}
298
299#[derive(Debug, Clone, PartialEq, Eq, Hash)]
301pub struct Rustc {
302 check_kind: CheckKind,
303
304 build_compiler: CompilerForCheck,
306 target: TargetSelection,
307
308 crates: Vec<String>,
314}
315
316impl Rustc {
317 fn check_rustc_for_preparing_sysroot(
318 builder: &Builder<'_>,
319 prepare: &PrepareRustcRmetaSysroot,
320 ) -> BuildStamp {
321 builder.ensure(Rustc {
322 check_kind: CheckKind::Check,
324 build_compiler: prepare.build_compiler.clone(),
325 target: prepare.target,
326 crates: vec![],
327 })
328 }
329}
330
331impl CommandLineStep for Rustc {
332 type Output = BuildStamp;
333 const IS_HOST: bool = true;
334
335 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
336 run.crate_or_deps("rustc-main").path("compiler")
337 }
338
339 fn is_default_step(_builder: &Builder<'_>) -> bool {
340 true
341 }
342
343 fn make_run(run: RunConfig<'_>) {
344 let check_kind = match run.builder.kind {
345 Kind::Check => CheckKind::Check,
346 Kind::Fix => CheckKind::Fix,
347 kind => panic!("unexpected kind for `check::Rustc`: {kind:?}"),
348 };
349
350 let target = run.target;
351 let build_compiler = prepare_compiler_for_check(run.builder, target, Mode::Rustc);
352 let crates = run.make_run_crates(Alias::Compiler);
353
354 run.builder.ensure(Rustc { check_kind, build_compiler, target, crates });
355 }
356
357 fn run(self, builder: &Builder<'_>) -> Self::Output {
365 let build_compiler = self.build_compiler.build_compiler;
366 let target = self.target;
367
368 let mut cargo = builder::Cargo::new(
369 builder,
370 build_compiler,
371 Mode::Rustc,
372 SourceType::InTree,
373 target,
374 self.check_kind.to_kind(),
375 );
376
377 rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
378 self.build_compiler.configure_cargo(&mut cargo);
379
380 for krate in &*self.crates {
384 cargo.arg("-p").arg(krate);
385 }
386
387 let _guard = builder.msg(
388 self.check_kind.to_kind(),
389 format_args!("compiler artifacts{}", crate_description(&self.crates)),
390 Mode::Rustc,
391 self.build_compiler.build_compiler(),
392 target,
393 );
394
395 let stamp =
396 build_stamp::librustc_stamp(builder, build_compiler, target).with_prefix("check");
397
398 run_cargo(
399 builder,
400 cargo,
401 builder.config.free_args.clone(),
402 &stamp,
403 vec![],
404 ArtifactKeepMode::OnlyRmeta,
405 );
406
407 stamp
408 }
409
410 fn metadata(&self) -> Option<StepMetadata> {
411 let mut metadata = StepMetadata::new("rustc", self.target, self.check_kind.to_kind())
412 .built_by(self.build_compiler.build_compiler());
413 if !self.crates.is_empty() {
414 metadata = metadata.with_metadata(format!("({} crates)", self.crates.len()));
415 }
416 Some(metadata)
417 }
418}
419
420#[derive(Debug, Clone, PartialEq, Eq, Hash)]
429pub struct CompilerForCheck {
430 build_compiler: Compiler,
431 rustc_rmeta_sysroot: Option<RmetaSysroot>,
432 std_rmeta_sysroot: Option<RmetaSysroot>,
433}
434
435impl CompilerForCheck {
436 pub fn build_compiler(&self) -> Compiler {
437 self.build_compiler
438 }
439
440 pub fn configure_cargo(&self, cargo: &mut Cargo) {
443 if let Some(sysroot) = &self.rustc_rmeta_sysroot {
444 sysroot.configure_cargo(cargo);
445 }
446 if let Some(sysroot) = &self.std_rmeta_sysroot {
447 sysroot.configure_cargo(cargo);
448 }
449 }
450}
451
452fn prepare_std(
455 builder: &Builder<'_>,
456 build_compiler: Compiler,
457 target: TargetSelection,
458) -> Option<RmetaSysroot> {
459 builder.std(build_compiler, builder.host_target);
462
463 if builder.host_target != target {
467 Some(builder.ensure(PrepareStdRmetaSysroot::new(build_compiler, target)))
468 } else {
469 None
470 }
471}
472
473pub fn prepare_compiler_for_check(
475 builder: &Builder<'_>,
476 target: TargetSelection,
477 mode: Mode,
478) -> CompilerForCheck {
479 let host = builder.host_target;
480
481 let mut rustc_rmeta_sysroot = None;
482 let mut std_rmeta_sysroot = None;
483 let build_compiler = match mode {
484 Mode::ToolBootstrap => builder.compiler(0, host),
485 Mode::ToolTarget => get_tool_target_compiler(builder, ToolTargetBuildMode::Build(target)),
489 Mode::ToolStd => {
490 if builder.config.compile_time_deps {
491 builder.compiler(0, host)
495 } else {
496 let build_compiler = builder.compiler(builder.top_stage, host);
498 std_rmeta_sysroot = prepare_std(builder, build_compiler, target);
499 build_compiler
500 }
501 }
502 Mode::ToolRustcPrivate | Mode::Codegen => {
503 let compiler_for_rustc = prepare_compiler_for_check(builder, target, Mode::Rustc);
508 rustc_rmeta_sysroot = Some(
509 builder.ensure(PrepareRustcRmetaSysroot::new(compiler_for_rustc.clone(), target)),
510 );
511 let build_compiler = compiler_for_rustc.build_compiler();
512
513 std_rmeta_sysroot = prepare_std(builder, build_compiler, target);
515 build_compiler
516 }
517 Mode::Rustc => {
518 let stage = if host == target { builder.top_stage - 1 } else { builder.top_stage };
526 let build_compiler = builder.compiler(stage, host);
527
528 std_rmeta_sysroot = prepare_std(builder, build_compiler, target);
530 build_compiler
531 }
532 Mode::Std => {
533 builder.compiler(builder.top_stage, host)
537 }
538 };
539 CompilerForCheck { build_compiler, rustc_rmeta_sysroot, std_rmeta_sysroot }
540}
541
542#[derive(Debug, Clone, PartialEq, Eq, Hash)]
544pub struct CraneliftCodegenBackend {
545 build_compiler: CompilerForCheck,
546 target: TargetSelection,
547}
548
549impl CommandLineStep for CraneliftCodegenBackend {
550 type Output = ();
551 const IS_HOST: bool = true;
552
553 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
554 run.alias("rustc_codegen_cranelift").alias("cg_clif")
555 }
556
557 fn is_default_step(_builder: &Builder<'_>) -> bool {
558 true
559 }
560
561 fn make_run(run: RunConfig<'_>) {
562 run.builder.ensure(CraneliftCodegenBackend {
563 build_compiler: prepare_compiler_for_check(run.builder, run.target, Mode::Codegen),
564 target: run.target,
565 });
566 }
567
568 fn run(self, builder: &Builder<'_>) {
569 let build_compiler = self.build_compiler.build_compiler();
570 let target = self.target;
571
572 let mut cargo = builder::Cargo::new(
573 builder,
574 build_compiler,
575 Mode::Codegen,
576 SourceType::InTree,
577 target,
578 builder.kind,
579 );
580
581 cargo
582 .arg("--manifest-path")
583 .arg(builder.src.join("compiler/rustc_codegen_cranelift/Cargo.toml"));
584 rustc_cargo_env(builder, &mut cargo, target);
585 self.build_compiler.configure_cargo(&mut cargo);
586
587 let _guard = builder.msg(
588 Kind::Check,
589 "rustc_codegen_cranelift",
590 Mode::Codegen,
591 build_compiler,
592 target,
593 );
594
595 let stamp = build_stamp::codegen_backend_stamp(
596 builder,
597 build_compiler,
598 target,
599 &CodegenBackendKind::Cranelift,
600 )
601 .with_prefix("check");
602
603 run_cargo(
604 builder,
605 cargo,
606 builder.config.free_args.clone(),
607 &stamp,
608 vec![],
609 ArtifactKeepMode::OnlyRmeta,
610 );
611 }
612
613 fn metadata(&self) -> Option<StepMetadata> {
614 Some(
615 StepMetadata::check("rustc_codegen_cranelift", self.target)
616 .built_by(self.build_compiler.build_compiler()),
617 )
618 }
619}
620
621#[derive(Debug, Clone, PartialEq, Eq, Hash)]
623pub struct GccCodegenBackend {
624 build_compiler: CompilerForCheck,
625 target: TargetSelection,
626}
627
628impl CommandLineStep for GccCodegenBackend {
629 type Output = ();
630 const IS_HOST: bool = true;
631
632 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
633 run.alias("rustc_codegen_gcc").alias("cg_gcc")
634 }
635
636 fn is_default_step(_builder: &Builder<'_>) -> bool {
637 true
638 }
639
640 fn make_run(run: RunConfig<'_>) {
641 run.builder.ensure(GccCodegenBackend {
642 build_compiler: prepare_compiler_for_check(run.builder, run.target, Mode::Codegen),
643 target: run.target,
644 });
645 }
646
647 fn run(self, builder: &Builder<'_>) {
648 if builder.build.config.vendor {
650 println!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled.");
651 return;
652 }
653
654 let build_compiler = self.build_compiler.build_compiler();
655 let target = self.target;
656
657 let mut cargo = builder::Cargo::new(
658 builder,
659 build_compiler,
660 Mode::Codegen,
661 SourceType::InTree,
662 target,
663 builder.kind,
664 );
665
666 cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml"));
667 rustc_cargo_env(builder, &mut cargo, target);
668 self.build_compiler.configure_cargo(&mut cargo);
669
670 let _guard =
671 builder.msg(Kind::Check, "rustc_codegen_gcc", Mode::Codegen, build_compiler, target);
672
673 let stamp = build_stamp::codegen_backend_stamp(
674 builder,
675 build_compiler,
676 target,
677 &CodegenBackendKind::Gcc,
678 )
679 .with_prefix("check");
680
681 run_cargo(
682 builder,
683 cargo,
684 builder.config.free_args.clone(),
685 &stamp,
686 vec![],
687 ArtifactKeepMode::OnlyRmeta,
688 );
689 }
690
691 fn metadata(&self) -> Option<StepMetadata> {
692 Some(
693 StepMetadata::check("rustc_codegen_gcc", self.target)
694 .built_by(self.build_compiler.build_compiler()),
695 )
696 }
697}
698
699macro_rules! tool_check_step {
700 (
701 $name:ident {
702 path: $path:literal
704 $(, alt_path: $alt_path:literal )*
705 , mode: $mode:expr
707 $(, allow_features: $allow_features:expr )?
709 $(, enable_features: [$($enable_features:expr),*] )?
711 $(, default_features: $default_features:expr )?
712 $(, default: $default:literal )?
713 $( , )?
714 }
715 ) => {
716 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
717 pub struct $name {
718 compiler: CompilerForCheck,
719 target: TargetSelection,
720 }
721
722 impl CommandLineStep for $name {
723 type Output = ();
724 const IS_HOST: bool = true;
725
726 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
727 run.multi_path(&[$path $(, $alt_path )*])
728 }
729
730 fn is_default_step(_builder: &Builder<'_>) -> bool {
731 true $( && const { $default } )?
733 }
734
735 fn make_run(run: RunConfig<'_>) {
736 let target = run.target;
737 let mode: Mode = $mode;
738
739 let compiler = prepare_compiler_for_check(run.builder, target, mode);
740
741 if mode == Mode::ToolBootstrap && target != run.builder.host_target {
743 println!("WARNING: not checking bootstrap tool {} for target {target} as it is a bootstrap (host-only) tool", stringify!($path));
744 return;
745 };
746
747 run.builder.ensure($name { target, compiler });
748 }
749
750 fn run(self, builder: &Builder<'_>) {
751 let Self { target, compiler } = self;
752 let allow_features = {
753 let mut _value = "";
754 $( _value = $allow_features; )?
755 _value
756 };
757 let extra_features: &[&str] = &[$($($enable_features),*)?];
758 let default_features = {
759 let mut _value = true;
760 $( _value = $default_features; )?
761 _value
762 };
763 let mode: Mode = $mode;
764 run_tool_check_step(builder, compiler, target, $path, mode, allow_features, extra_features, default_features);
765 }
766
767 fn metadata(&self) -> Option<StepMetadata> {
768 Some(StepMetadata::check(stringify!($name), self.target).built_by(self.compiler.build_compiler))
769 }
770 }
771 }
772}
773
774#[allow(clippy::too_many_arguments)]
776fn run_tool_check_step(
777 builder: &Builder<'_>,
778 compiler: CompilerForCheck,
779 target: TargetSelection,
780 path: &str,
781 mode: Mode,
782 allow_features: &str,
783 extra_features: &[&str],
784 default_features: bool,
785) {
786 let display_name = path.rsplit('/').next().unwrap();
787
788 let build_compiler = compiler.build_compiler();
789
790 let extra_features = extra_features.iter().map(|f| f.to_string()).collect::<Vec<String>>();
791 let mut cargo = prepare_tool_cargo(
792 builder,
793 build_compiler,
794 mode,
795 target,
796 builder.kind,
797 path,
798 SourceType::InTree,
803 &extra_features,
804 );
805 cargo.allow_features(allow_features);
806 compiler.configure_cargo(&mut cargo);
807
808 if display_name == "rust-analyzer" {
811 cargo.arg("--bins");
812 cargo.arg("--tests");
813 cargo.arg("--benches");
814 } else {
815 cargo.arg("--all-targets");
816 }
817
818 if !default_features {
819 cargo.arg("--no-default-features");
820 }
821
822 let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, mode, target))
823 .with_prefix(&format!("{display_name}-check"));
824
825 let _guard = builder.msg(builder.kind, display_name, mode, build_compiler, target);
826 run_cargo(
827 builder,
828 cargo,
829 builder.config.free_args.clone(),
830 &stamp,
831 vec![],
832 ArtifactKeepMode::OnlyRmeta,
833 );
834}
835
836tool_check_step!(Rustdoc {
837 path: "src/tools/rustdoc",
838 alt_path: "src/librustdoc",
839 mode: Mode::ToolRustcPrivate
840});
841tool_check_step!(Clippy { path: "src/tools/clippy", mode: Mode::ToolRustcPrivate });
846tool_check_step!(Miri {
847 path: "src/tools/miri",
848 mode: Mode::ToolRustcPrivate,
849 enable_features: ["check_only"],
850});
851tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri", mode: Mode::ToolRustcPrivate });
852tool_check_step!(Priroda { path: "src/tools/miri/priroda", mode: Mode::ToolRustcPrivate });
853tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: Mode::ToolRustcPrivate });
854tool_check_step!(RustAnalyzer {
855 path: "src/tools/rust-analyzer",
856 mode: Mode::ToolRustcPrivate,
857 allow_features: tool::RustAnalyzer::ALLOW_FEATURES,
858 enable_features: ["in-rust-tree"],
859});
860tool_check_step!(MiroptTestTools {
861 path: "src/tools/miropt-test-tools",
862 mode: Mode::ToolBootstrap
863});
864tool_check_step!(TestFloatParse {
866 path: "src/tools/test-float-parse",
867 mode: Mode::ToolStd,
868 allow_features: TEST_FLOAT_PARSE_ALLOW_FEATURES
869});
870tool_check_step!(FeaturesStatusDump {
871 path: "src/tools/features-status-dump",
872 mode: Mode::ToolBootstrap
873});
874
875tool_check_step!(Bootstrap { path: "src/bootstrap", mode: Mode::ToolBootstrap, default: false });
876
877tool_check_step!(RunMakeSupport {
880 path: "src/tools/run-make-support",
881 mode: Mode::ToolBootstrap,
882 default: false
883});
884
885tool_check_step!(CoverageDump {
886 path: "src/tools/coverage-dump",
887 mode: Mode::ToolBootstrap,
888 default: false
889});
890
891tool_check_step!(Compiletest {
894 path: "src/tools/compiletest",
895 mode: Mode::ToolBootstrap,
896 default: false,
897});
898
899tool_check_step!(RustdocGuiTest {
903 path: "src/tools/rustdoc-gui-test",
904 mode: Mode::ToolBootstrap,
905 default: false,
906});
907
908tool_check_step!(Linkchecker {
909 path: "src/tools/linkchecker",
910 mode: Mode::ToolBootstrap,
911 default: false
912});
913
914tool_check_step!(BumpStage0 {
915 path: "src/tools/bump-stage0",
916 mode: Mode::ToolBootstrap,
917 default: false
918});
919
920tool_check_step!(Tidy { path: "src/tools/tidy", mode: Mode::ToolBootstrap, default: false });