Skip to main content

bootstrap/core/build_steps/
check.rs

1//! Implementation of compiling the compiler and standard library, in "check"-based modes.
2
3use std::fs;
4use std::path::{Path, PathBuf};
5
6use crate::core::backend::CodegenBackendKind;
7use crate::core::build_steps::compile::{
8    ArtifactKeepMode, add_to_sysroot, run_cargo, rustc_cargo, std_cargo, 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::compiler::Compiler;
20use crate::core::config::TargetSelection;
21use crate::core::session::Mode;
22use crate::utils::build_stamp::{self, BuildStamp};
23use crate::utils::helpers::t;
24
25/// Allows individual check-step instances to keep track of whether they
26/// represent `cargo check` or `cargo fix`, independently of [`Builder::kind`].
27#[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    /// Compiler that will check this std.
45    pub build_compiler: Compiler,
46    pub target: TargetSelection,
47    /// Whether to build only a subset of crates.
48    ///
49    /// This shouldn't be used from other steps; see the comment on [`compile::Rustc`].
50    ///
51    /// [`compile::Rustc`]: crate::core::build_steps::compile::Rustc
52    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            // libstd doesn't have any important build scripts and can't have any proc macros
85            return;
86        }
87
88        // Explicitly pass -p for all dependencies crates -- this will force cargo
89        // to also check the tests/benches/examples for these crates, rather
90        // than just the leaf crate.
91        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.kind, Kind::Fix) {
115            // By default, cargo tries to fix all targets. Tell it not to fix tests until we've added `test` to the sysroot.
116            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        // don't check test dependencies if we haven't built libtest
141        if !self.crates.iter().any(|krate| krate == "test") {
142            return check_stamp;
143        }
144
145        // Then run cargo again, once we've put the rmeta files for the library
146        // crates into the sysroot. This is needed because e.g., core's tests
147        // depend on `libtest` -- Cargo presumes it will exist, but it doesn't
148        // since we initialize with an empty sysroot.
149        //
150        // Currently only the "libtest" tree of crates does this.
151        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/// Represents a proof that rustc was **checked**.
188/// Contains directories with .rmeta files generated by checking rustc for a specific
189/// target.
190#[derive(Debug, Clone, PartialEq, Eq, Hash)]
191struct RmetaSysroot {
192    host_dir: PathBuf,
193    target_dir: PathBuf,
194}
195
196impl RmetaSysroot {
197    /// Copy rmeta artifacts from the given `stamp` into a sysroot located at `directory`.
198    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    /// Configure the given cargo invocation so that the compiled crate will be able to use
214    /// rustc .rmeta artifacts that were previously generated.
215    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/// Checks rustc using the given `build_compiler` for the given `target`, and produces
225/// a sysroot in the build directory that stores the generated .rmeta files.
226///
227/// This step exists so that we can store the generated .rmeta artifacts into a separate
228/// directory, instead of copying them into the sysroot of `build_compiler`, which would
229/// "pollute" it (that is especially problematic for the external stage0 rustc).
230#[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        // Check rustc
247        let stamp = Rustc::check_rustc_for_preparing_sysroot(builder, &self);
248
249        let build_compiler = self.build_compiler.build_compiler();
250
251        // Copy the generated rmeta artifacts to a separate directory
252        let dir = builder
253            .config
254            .out
255            .join(build_compiler.host)
256            .join(format!("stage{}-rustc-rmeta-artifacts", build_compiler.stage + 1));
257        RmetaSysroot::from_stamp(builder, stamp, self.target, &dir)
258    }
259}
260
261/// Checks std using the given `build_compiler` for the given `target`, and produces
262/// a sysroot in the build directory that stores the generated .rmeta files.
263///
264/// This step exists so that we can store the generated .rmeta artifacts into a separate
265/// directory, instead of copying them into the sysroot of `build_compiler`, which would
266/// "pollute" it (that is especially problematic for the external stage0 rustc).
267#[derive(Debug, Clone, PartialEq, Eq, Hash)]
268struct PrepareStdRmetaSysroot {
269    build_compiler: Compiler,
270    target: TargetSelection,
271}
272
273impl PrepareStdRmetaSysroot {
274    fn new(build_compiler: Compiler, target: TargetSelection) -> Self {
275        Self { build_compiler, target }
276    }
277}
278
279impl Step for PrepareStdRmetaSysroot {
280    type Output = RmetaSysroot;
281
282    fn run(self, builder: &Builder<'_>) -> Self::Output {
283        // Check std
284        let stamp = builder.ensure(Std {
285            build_compiler: self.build_compiler,
286            target: self.target,
287            crates: vec![],
288        });
289
290        // Copy the generated rmeta artifacts to a separate directory
291        let dir = builder
292            .config
293            .out
294            .join(self.build_compiler.host)
295            .join(format!("stage{}-std-rmeta-artifacts", self.build_compiler.stage));
296
297        RmetaSysroot::from_stamp(builder, stamp, self.target, &dir)
298    }
299}
300
301/// Checks rustc using `build_compiler`.
302#[derive(Debug, Clone, PartialEq, Eq, Hash)]
303pub struct Rustc {
304    check_kind: CheckKind,
305
306    /// Compiler that will check this rustc.
307    build_compiler: CompilerForCheck,
308    target: TargetSelection,
309
310    /// Whether to build only a subset of crates.
311    ///
312    /// This shouldn't be used from other steps; see the comment on [`compile::Rustc`].
313    ///
314    /// [`compile::Rustc`]: crate::core::build_steps::compile::Rustc
315    crates: Vec<String>,
316}
317
318impl Rustc {
319    fn check_rustc_for_preparing_sysroot(
320        builder: &Builder<'_>,
321        prepare: &PrepareRustcRmetaSysroot,
322    ) -> BuildStamp {
323        builder.ensure(Rustc {
324            // We specifically want `cargo check`, not the current bootstrap subcommand.
325            check_kind: CheckKind::Check,
326            build_compiler: prepare.build_compiler.clone(),
327            target: prepare.target,
328            crates: vec![],
329        })
330    }
331}
332
333impl CommandLineStep for Rustc {
334    type Output = BuildStamp;
335    const IS_HOST: bool = true;
336
337    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
338        run.crate_or_deps("rustc-main").path("compiler")
339    }
340
341    fn is_default_step(_builder: &Builder<'_>) -> bool {
342        true
343    }
344
345    fn make_run(run: RunConfig<'_>) {
346        let check_kind = match run.builder.kind {
347            Kind::Check => CheckKind::Check,
348            Kind::Fix => CheckKind::Fix,
349            kind => panic!("unexpected kind for `check::Rustc`: {kind:?}"),
350        };
351
352        let target = run.target;
353        let build_compiler = prepare_compiler_for_check(run.builder, target, Mode::Rustc);
354        let crates = run.make_run_crates(Alias::Compiler);
355
356        run.builder.ensure(Rustc { check_kind, build_compiler, target, crates });
357    }
358
359    /// Check the compiler.
360    ///
361    /// This will check the compiler for a particular stage of the build using
362    /// the `compiler` targeting the `target` architecture. The artifacts
363    /// created will also be linked into the sysroot directory.
364    ///
365    /// If we check a stage 2 compiler, we will have to first build a stage 1 compiler to check it.
366    fn run(self, builder: &Builder<'_>) -> Self::Output {
367        let build_compiler = self.build_compiler.build_compiler;
368        let target = self.target;
369
370        let mut cargo = builder::Cargo::new(
371            builder,
372            build_compiler,
373            Mode::Rustc,
374            SourceType::InTree,
375            target,
376            self.check_kind.to_kind(),
377        );
378
379        rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
380        self.build_compiler.configure_cargo(&mut cargo);
381
382        // Explicitly pass -p for all compiler crates -- this will force cargo
383        // to also check the tests/benches/examples for these crates, rather
384        // than just the leaf crate.
385        for krate in &*self.crates {
386            cargo.arg("-p").arg(krate);
387        }
388
389        let _guard = builder.msg(
390            self.check_kind.to_kind(),
391            format_args!("compiler artifacts{}", crate_description(&self.crates)),
392            Mode::Rustc,
393            self.build_compiler.build_compiler(),
394            target,
395        );
396
397        let stamp =
398            build_stamp::librustc_stamp(builder, build_compiler, target).with_prefix("check");
399
400        run_cargo(
401            builder,
402            cargo,
403            builder.config.free_args.clone(),
404            &stamp,
405            vec![],
406            ArtifactKeepMode::OnlyRmeta,
407        );
408
409        stamp
410    }
411
412    fn metadata(&self) -> Option<StepMetadata> {
413        let mut metadata = StepMetadata::new("rustc", self.target, self.check_kind.to_kind())
414            .built_by(self.build_compiler.build_compiler());
415        if !self.crates.is_empty() {
416            metadata = metadata.with_metadata(format!("({} crates)", self.crates.len()));
417        }
418        Some(metadata)
419    }
420}
421
422/// Represents a compiler that can check something.
423///
424/// If the compiler was created for `Mode::ToolRustcPrivate` or `Mode::Codegen`, it will also contain
425/// .rmeta artifacts from rustc that was already checked using `build_compiler`.
426///
427/// All steps that use this struct in a "general way" (i.e. they don't know exactly what kind of
428/// thing is being built) should call `configure_cargo` to ensure that the rmeta artifacts are
429/// properly linked, if present.
430#[derive(Debug, Clone, PartialEq, Eq, Hash)]
431pub struct CompilerForCheck {
432    build_compiler: Compiler,
433    rustc_rmeta_sysroot: Option<RmetaSysroot>,
434    std_rmeta_sysroot: Option<RmetaSysroot>,
435}
436
437impl CompilerForCheck {
438    pub fn build_compiler(&self) -> Compiler {
439        self.build_compiler
440    }
441
442    /// If there are any rustc rmeta artifacts available, configure the Cargo invocation
443    /// so that the artifact being built can find them.
444    pub fn configure_cargo(&self, cargo: &mut Cargo) {
445        if let Some(sysroot) = &self.rustc_rmeta_sysroot {
446            sysroot.configure_cargo(cargo);
447        }
448        if let Some(sysroot) = &self.std_rmeta_sysroot {
449            sysroot.configure_cargo(cargo);
450        }
451    }
452}
453
454/// Prepare the standard library for checking something (that requires stdlib) using
455/// `build_compiler`.
456fn prepare_std(
457    builder: &Builder<'_>,
458    build_compiler: Compiler,
459    target: TargetSelection,
460) -> Option<RmetaSysroot> {
461    // We need to build the host stdlib even if we only check, to compile build scripts and proc
462    // macros
463    builder.std(build_compiler, builder.host_target);
464
465    // If we're cross-compiling, we generate the rmeta files for the given target
466    // This check has to be here, because if we generate both .so and .rmeta files, rustc will fail,
467    // as it will have multiple candidates for linking.
468    if builder.host_target != target {
469        Some(builder.ensure(PrepareStdRmetaSysroot::new(build_compiler, target)))
470    } else {
471        None
472    }
473}
474
475/// Prepares a compiler that will check something with the given `mode`.
476pub fn prepare_compiler_for_check(
477    builder: &Builder<'_>,
478    target: TargetSelection,
479    mode: Mode,
480) -> CompilerForCheck {
481    let host = builder.host_target;
482
483    let mut rustc_rmeta_sysroot = None;
484    let mut std_rmeta_sysroot = None;
485    let build_compiler = match mode {
486        Mode::ToolBootstrap => builder.compiler(0, host),
487        // We could also only check std here and use `prepare_std`, but `ToolTarget` is currently
488        // only used for running in-tree Clippy on bootstrap tools, so it does not seem worth it to
489        // optimize it. Therefore, here we build std for the target, instead of just checking it.
490        Mode::ToolTarget => get_tool_target_compiler(builder, ToolTargetBuildMode::Build(target)),
491        Mode::ToolStd => {
492            if builder.config.compile_time_deps {
493                // When --compile-time-deps is passed, we can't use any rustc
494                // other than the bootstrap compiler. Luckily build scripts and
495                // proc macros for tools are unlikely to need nightly.
496                builder.compiler(0, host)
497            } else {
498                // These tools require the local standard library to be checked
499                let build_compiler = builder.compiler(builder.top_stage, host);
500                std_rmeta_sysroot = prepare_std(builder, build_compiler, target);
501                build_compiler
502            }
503        }
504        Mode::ToolRustcPrivate | Mode::Codegen => {
505            // Check Rustc to produce the required rmeta artifacts for rustc_private, and then
506            // return the build compiler that was used to check rustc.
507            // We do not need to check examples/tests/etc. of Rustc for rustc_private, so we pass
508            // an empty set of crates, which will avoid using `cargo -p`.
509            let compiler_for_rustc = prepare_compiler_for_check(builder, target, Mode::Rustc);
510            rustc_rmeta_sysroot = Some(
511                builder.ensure(PrepareRustcRmetaSysroot::new(compiler_for_rustc.clone(), target)),
512            );
513            let build_compiler = compiler_for_rustc.build_compiler();
514
515            // To check a rustc_private tool, we also need to check std that it will link to
516            std_rmeta_sysroot = prepare_std(builder, build_compiler, target);
517            build_compiler
518        }
519        Mode::Rustc => {
520            // This is a horrible hack, because we actually change the compiler stage numbering
521            // here. If you do `x check --stage 1 --host FOO`, we build stage 1 host rustc,
522            // and use that to check stage 1 FOO rustc (which actually makes that stage 2 FOO
523            // rustc).
524            //
525            // FIXME: remove this and either fix cross-compilation check on stage 2 (which has a
526            // myriad of other problems) or disable cross-checking on stage 1.
527            let stage = if host == target { builder.top_stage - 1 } else { builder.top_stage };
528            let build_compiler = builder.compiler(stage, host);
529
530            // To check rustc, we need to check std that it will link to
531            std_rmeta_sysroot = prepare_std(builder, build_compiler, target);
532            build_compiler
533        }
534        Mode::Std => {
535            // When checking std stage N, we want to do it with the stage N compiler
536            // Note: we don't need to build the host stdlib here, because when compiling std, the
537            // stage 0 stdlib is used to compile build scripts and proc macros.
538            builder.compiler(builder.top_stage, host)
539        }
540    };
541    CompilerForCheck { build_compiler, rustc_rmeta_sysroot, std_rmeta_sysroot }
542}
543
544/// Check the Cranelift codegen backend.
545#[derive(Debug, Clone, PartialEq, Eq, Hash)]
546pub struct CraneliftCodegenBackend {
547    build_compiler: CompilerForCheck,
548    target: TargetSelection,
549}
550
551impl CommandLineStep for CraneliftCodegenBackend {
552    type Output = ();
553    const IS_HOST: bool = true;
554
555    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
556        run.alias("rustc_codegen_cranelift").alias("cg_clif")
557    }
558
559    fn is_default_step(_builder: &Builder<'_>) -> bool {
560        true
561    }
562
563    fn make_run(run: RunConfig<'_>) {
564        run.builder.ensure(CraneliftCodegenBackend {
565            build_compiler: prepare_compiler_for_check(run.builder, run.target, Mode::Codegen),
566            target: run.target,
567        });
568    }
569
570    fn run(self, builder: &Builder<'_>) {
571        let build_compiler = self.build_compiler.build_compiler();
572        let target = self.target;
573
574        let mut cargo = builder::Cargo::new(
575            builder,
576            build_compiler,
577            Mode::Codegen,
578            SourceType::InTree,
579            target,
580            builder.kind,
581        );
582
583        cargo
584            .arg("--manifest-path")
585            .arg(builder.src.join("compiler/rustc_codegen_cranelift/Cargo.toml"));
586        self.build_compiler.configure_cargo(&mut cargo);
587
588        let _guard = builder.msg(
589            Kind::Check,
590            "rustc_codegen_cranelift",
591            Mode::Codegen,
592            build_compiler,
593            target,
594        );
595
596        let stamp = build_stamp::codegen_backend_stamp(
597            builder,
598            build_compiler,
599            target,
600            &CodegenBackendKind::Cranelift,
601        )
602        .with_prefix("check");
603
604        run_cargo(
605            builder,
606            cargo,
607            builder.config.free_args.clone(),
608            &stamp,
609            vec![],
610            ArtifactKeepMode::OnlyRmeta,
611        );
612    }
613
614    fn metadata(&self) -> Option<StepMetadata> {
615        Some(
616            StepMetadata::check("rustc_codegen_cranelift", self.target)
617                .built_by(self.build_compiler.build_compiler()),
618        )
619    }
620}
621
622/// Check the GCC codegen backend.
623#[derive(Debug, Clone, PartialEq, Eq, Hash)]
624pub struct GccCodegenBackend {
625    build_compiler: CompilerForCheck,
626    target: TargetSelection,
627}
628
629impl CommandLineStep for GccCodegenBackend {
630    type Output = ();
631    const IS_HOST: bool = true;
632
633    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
634        run.alias("rustc_codegen_gcc").alias("cg_gcc")
635    }
636
637    fn is_default_step(_builder: &Builder<'_>) -> bool {
638        true
639    }
640
641    fn make_run(run: RunConfig<'_>) {
642        run.builder.ensure(GccCodegenBackend {
643            build_compiler: prepare_compiler_for_check(run.builder, run.target, Mode::Codegen),
644            target: run.target,
645        });
646    }
647
648    fn run(self, builder: &Builder<'_>) {
649        // FIXME: remove once https://github.com/rust-lang/rust/issues/112393 is resolved
650        if builder.sess.config.vendor {
651            println!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled.");
652            return;
653        }
654
655        let build_compiler = self.build_compiler.build_compiler();
656        let target = self.target;
657
658        let mut cargo = builder::Cargo::new(
659            builder,
660            build_compiler,
661            Mode::Codegen,
662            SourceType::InTree,
663            target,
664            builder.kind,
665        );
666
667        cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml"));
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            // The part of this path after the final '/' is also used as a display name.
703            path: $path:literal
704            $(, alt_path: $alt_path:literal )*
705            // `Mode` to use when checking this tool
706            , mode: $mode:expr
707            // Subset of nightly features that are allowed to be used when checking
708            $(, allow_features: $allow_features:expr )?
709            // Features that should be enabled when checking
710            $(, 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                // Most of the tool-checks using this macro are run by default.
732                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                // It doesn't make sense to cross-check bootstrap tools
742                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/// Used by the implementation of `Step::run` in `tool_check_step!`.
775#[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        // Currently, all of the tools that use this macro/function are in-tree.
799        // If support for out-of-tree tools is re-added in the future, those
800        // steps should probably be marked non-default so that the default
801        // checks aren't affected by toolstate being broken.
802        SourceType::InTree,
803        &extra_features,
804    );
805    cargo.allow_features(allow_features);
806    compiler.configure_cargo(&mut cargo);
807
808    // FIXME: check bootstrap doesn't currently work when multiple targets are checked
809    // FIXME: rust-analyzer does not work with --all-targets
810    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});
841// Clippy, miri and Rustfmt are hybrids. They are external tools, but use a git subtree instead
842// of a submodule. Since the SourceType only drives the deny-warnings
843// behavior, treat it as in-tree so that any new warnings in clippy will be
844// rejected.
845tool_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});
864// We want to test the local std
865tool_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
877// `run-make-support` will be built as part of suitable run-make compiletest test steps, but support
878// check to make it easier to work on.
879tool_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
891// Compiletest is implicitly "checked" when it gets built in order to run tests,
892// so this is mainly for people working on compiletest to run locally.
893tool_check_step!(Compiletest {
894    path: "src/tools/compiletest",
895    mode: Mode::ToolBootstrap,
896    default: false,
897});
898
899// As with compiletest, rustdoc-gui-test is automatically built when running
900// relevant tests. So being able to check it is mainly useful for people
901// working on on rustdoc-gui-test itself, or on its compiletest dependency.
902tool_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
920// Tidy is implicitly checked when `./x test tidy` is executed
921// (if you set a pre-push hook, the command is called).
922// So this is mainly for people working on tidy.
923tool_check_step!(Tidy { path: "src/tools/tidy", mode: Mode::ToolBootstrap, default: false });