bootstrap/core/build_steps/
tool.rs

1//! This module handles building and managing various tools in bootstrap
2//! build system.
3//!
4//! **What It Does**
5//! - Defines how tools are built, configured and installed.
6//! - Manages tool dependencies and build steps.
7//! - Copies built tool binaries to the correct locations.
8//!
9//! Each Rust tool **MUST** utilize `ToolBuild` inside their `Step` logic,
10//! return `ToolBuildResult` and should never prepare `cargo` invocations manually.
11
12use std::path::PathBuf;
13use std::{env, fs};
14
15#[cfg(feature = "tracing")]
16use tracing::instrument;
17
18use crate::core::build_steps::compile::is_lto_stage;
19use crate::core::build_steps::toolstate::ToolState;
20use crate::core::build_steps::{compile, llvm};
21use crate::core::builder;
22use crate::core::builder::{
23    Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step, StepMetadata, cargo_profile_var,
24};
25use crate::core::config::{DebuginfoLevel, RustcLto, TargetSelection};
26use crate::utils::exec::{BootstrapCommand, command};
27use crate::utils::helpers::{add_dylib_path, exe, t};
28use crate::{Compiler, FileType, Kind, Mode, gha};
29
30#[derive(Debug, Clone, Hash, PartialEq, Eq)]
31pub enum SourceType {
32    InTree,
33    Submodule,
34}
35
36#[derive(Debug, Clone, Hash, PartialEq, Eq)]
37pub enum ToolArtifactKind {
38    Binary,
39    Library,
40}
41
42#[derive(Debug, Clone, Hash, PartialEq, Eq)]
43struct ToolBuild {
44    compiler: Compiler,
45    target: TargetSelection,
46    tool: &'static str,
47    path: &'static str,
48    mode: Mode,
49    source_type: SourceType,
50    extra_features: Vec<String>,
51    /// Nightly-only features that are allowed (comma-separated list).
52    allow_features: &'static str,
53    /// Additional arguments to pass to the `cargo` invocation.
54    cargo_args: Vec<String>,
55    /// Whether the tool builds a binary or a library.
56    artifact_kind: ToolArtifactKind,
57}
58
59impl Builder<'_> {
60    #[track_caller]
61    pub(crate) fn msg_tool(
62        &self,
63        kind: Kind,
64        mode: Mode,
65        tool: &str,
66        build_stage: u32,
67        host: &TargetSelection,
68        target: &TargetSelection,
69    ) -> Option<gha::Group> {
70        match mode {
71            // depends on compiler stage, different to host compiler
72            Mode::ToolRustc => self.msg_sysroot_tool(
73                kind,
74                build_stage,
75                format_args!("tool {tool}"),
76                *host,
77                *target,
78            ),
79            // doesn't depend on compiler, same as host compiler
80            _ => self.msg(Kind::Build, build_stage, format_args!("tool {tool}"), *host, *target),
81        }
82    }
83}
84
85/// Result of the tool build process. Each `Step` in this module is responsible
86/// for using this type as `type Output = ToolBuildResult;`
87#[derive(Clone)]
88pub struct ToolBuildResult {
89    /// Artifact path of the corresponding tool that was built.
90    pub tool_path: PathBuf,
91    /// Compiler used to build the tool. For non-`ToolRustc` tools this is equal to `target_compiler`.
92    /// For `ToolRustc` this is one stage before of the `target_compiler`.
93    pub build_compiler: Compiler,
94    /// Target compiler passed to `Step`.
95    pub target_compiler: Compiler,
96}
97
98impl Step for ToolBuild {
99    type Output = ToolBuildResult;
100
101    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
102        run.never()
103    }
104
105    /// Builds a tool in `src/tools`
106    ///
107    /// This will build the specified tool with the specified `host` compiler in
108    /// `stage` into the normal cargo output directory.
109    fn run(mut self, builder: &Builder<'_>) -> ToolBuildResult {
110        let target = self.target;
111        let mut tool = self.tool;
112        let path = self.path;
113
114        let target_compiler = self.compiler;
115        self.compiler = if self.mode == Mode::ToolRustc {
116            get_tool_rustc_compiler(builder, self.compiler)
117        } else {
118            self.compiler
119        };
120
121        match self.mode {
122            Mode::ToolRustc => {
123                // If compiler was forced, its artifacts should be prepared earlier.
124                if !self.compiler.is_forced_compiler() {
125                    builder.std(self.compiler, self.compiler.host);
126                    builder.ensure(compile::Rustc::new(self.compiler, target));
127                }
128            }
129            Mode::ToolStd => {
130                // If compiler was forced, its artifacts should be prepared earlier.
131                if !self.compiler.is_forced_compiler() {
132                    builder.std(self.compiler, target)
133                }
134            }
135            Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs
136            _ => panic!("unexpected Mode for tool build"),
137        }
138
139        // build.tool.TOOL_NAME.features in bootstrap.toml allows specifying which features to
140        // enable for a specific tool. `extra_features` instead is not controlled by the toml and
141        // provides features that are always enabled for a specific tool (e.g. "in-rust-tree" for
142        // rust-analyzer). Finally, `prepare_tool_cargo` might add more features to adapt the build
143        // to the chosen flags (e.g. "all-static" for cargo if `cargo_native_static` is true).
144        let mut features = builder
145            .config
146            .tool
147            .get(self.tool)
148            .and_then(|tool| tool.features.clone())
149            .unwrap_or_default();
150        features.extend(self.extra_features.clone());
151
152        let mut cargo = prepare_tool_cargo(
153            builder,
154            self.compiler,
155            self.mode,
156            target,
157            Kind::Build,
158            path,
159            self.source_type,
160            &features,
161        );
162
163        // The stage0 compiler changes infrequently and does not directly depend on code
164        // in the current working directory. Therefore, caching it with sccache should be
165        // useful.
166        // This is only performed for non-incremental builds, as ccache cannot deal with these.
167        if let Some(ref ccache) = builder.config.ccache
168            && matches!(self.mode, Mode::ToolBootstrap)
169            && !builder.config.incremental
170        {
171            cargo.env("RUSTC_WRAPPER", ccache);
172        }
173
174        // Rustc tools (miri, clippy, cargo, rustfmt, rust-analyzer)
175        // could use the additional optimizations.
176        if self.mode == Mode::ToolRustc && is_lto_stage(&self.compiler) {
177            let lto = match builder.config.rust_lto {
178                RustcLto::Off => Some("off"),
179                RustcLto::Thin => Some("thin"),
180                RustcLto::Fat => Some("fat"),
181                RustcLto::ThinLocal => None,
182            };
183            if let Some(lto) = lto {
184                cargo.env(cargo_profile_var("LTO", &builder.config), lto);
185            }
186        }
187
188        if !self.allow_features.is_empty() {
189            cargo.allow_features(self.allow_features);
190        }
191
192        cargo.args(self.cargo_args);
193
194        let _guard = builder.msg_tool(
195            Kind::Build,
196            self.mode,
197            self.tool,
198            self.compiler.stage,
199            &self.compiler.host,
200            &self.target,
201        );
202
203        // we check this below
204        let build_success = compile::stream_cargo(builder, cargo, vec![], &mut |_| {});
205
206        builder.save_toolstate(
207            tool,
208            if build_success { ToolState::TestFail } else { ToolState::BuildFail },
209        );
210
211        if !build_success {
212            crate::exit!(1);
213        } else {
214            // HACK(#82501): on Windows, the tools directory gets added to PATH when running tests, and
215            // compiletest confuses HTML tidy with the in-tree tidy. Name the in-tree tidy something
216            // different so the problem doesn't come up.
217            if tool == "tidy" {
218                tool = "rust-tidy";
219            }
220            let tool_path = match self.artifact_kind {
221                ToolArtifactKind::Binary => {
222                    copy_link_tool_bin(builder, self.compiler, self.target, self.mode, tool)
223                }
224                ToolArtifactKind::Library => builder
225                    .cargo_out(self.compiler, self.mode, self.target)
226                    .join(format!("lib{tool}.rlib")),
227            };
228
229            ToolBuildResult { tool_path, build_compiler: self.compiler, target_compiler }
230        }
231    }
232}
233
234#[expect(clippy::too_many_arguments)] // FIXME: reduce the number of args and remove this.
235pub fn prepare_tool_cargo(
236    builder: &Builder<'_>,
237    compiler: Compiler,
238    mode: Mode,
239    target: TargetSelection,
240    cmd_kind: Kind,
241    path: &str,
242    source_type: SourceType,
243    extra_features: &[String],
244) -> CargoCommand {
245    let mut cargo = builder::Cargo::new(builder, compiler, mode, source_type, target, cmd_kind);
246
247    let dir = builder.src.join(path);
248    cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
249
250    let mut features = extra_features.to_vec();
251    if builder.build.config.cargo_native_static {
252        if path.ends_with("cargo")
253            || path.ends_with("clippy")
254            || path.ends_with("miri")
255            || path.ends_with("rustfmt")
256        {
257            cargo.env("LIBZ_SYS_STATIC", "1");
258        }
259        if path.ends_with("cargo") {
260            features.push("all-static".to_string());
261        }
262    }
263
264    // clippy tests need to know about the stage sysroot. Set them consistently while building to
265    // avoid rebuilding when running tests.
266    cargo.env("SYSROOT", builder.sysroot(compiler));
267
268    // if tools are using lzma we want to force the build script to build its
269    // own copy
270    cargo.env("LZMA_API_STATIC", "1");
271
272    // CFG_RELEASE is needed by rustfmt (and possibly other tools) which
273    // import rustc-ap-rustc_attr which requires this to be set for the
274    // `#[cfg(version(...))]` attribute.
275    cargo.env("CFG_RELEASE", builder.rust_release());
276    cargo.env("CFG_RELEASE_CHANNEL", &builder.config.channel);
277    cargo.env("CFG_VERSION", builder.rust_version());
278    cargo.env("CFG_RELEASE_NUM", &builder.version);
279    cargo.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
280
281    if let Some(ref ver_date) = builder.rust_info().commit_date() {
282        cargo.env("CFG_VER_DATE", ver_date);
283    }
284
285    if let Some(ref ver_hash) = builder.rust_info().sha() {
286        cargo.env("CFG_VER_HASH", ver_hash);
287    }
288
289    if let Some(description) = &builder.config.description {
290        cargo.env("CFG_VER_DESCRIPTION", description);
291    }
292
293    let info = builder.config.git_info(builder.config.omit_git_hash, &dir);
294    if let Some(sha) = info.sha() {
295        cargo.env("CFG_COMMIT_HASH", sha);
296    }
297
298    if let Some(sha_short) = info.sha_short() {
299        cargo.env("CFG_SHORT_COMMIT_HASH", sha_short);
300    }
301
302    if let Some(date) = info.commit_date() {
303        cargo.env("CFG_COMMIT_DATE", date);
304    }
305
306    if !features.is_empty() {
307        cargo.arg("--features").arg(features.join(", "));
308    }
309
310    // Enable internal lints for clippy and rustdoc
311    // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
312    // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
313    //
314    // NOTE: We unconditionally set this here to avoid recompiling tools between `x check $tool`
315    // and `x test $tool` executions.
316    // See https://github.com/rust-lang/rust/issues/116538
317    cargo.rustflag("-Zunstable-options");
318
319    // NOTE: The root cause of needing `-Zon-broken-pipe=kill` in the first place is because `rustc`
320    // and `rustdoc` doesn't gracefully handle I/O errors due to usages of raw std `println!` macros
321    // which panics upon encountering broken pipes. `-Zon-broken-pipe=kill` just papers over that
322    // and stops rustc/rustdoc ICEing on e.g. `rustc --print=sysroot | false`.
323    //
324    // cargo explicitly does not want the `-Zon-broken-pipe=kill` paper because it does actually use
325    // variants of `println!` that handles I/O errors gracefully. It's also a breaking change for a
326    // spawn process not written in Rust, especially if the language default handler is not
327    // `SIG_IGN`. Thankfully cargo tests will break if we do set the flag.
328    //
329    // For the cargo discussion, see
330    // <https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo/topic/Applying.20.60-Zon-broken-pipe.3Dkill.60.20flags.20in.20bootstrap.3F>.
331    //
332    // For the rustc discussion, see
333    // <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Internal.20lint.20for.20raw.20.60print!.60.20and.20.60println!.60.3F>
334    // for proper solutions.
335    if !path.ends_with("cargo") {
336        // Use an untracked env var `FORCE_ON_BROKEN_PIPE_KILL` here instead of `RUSTFLAGS`.
337        // `RUSTFLAGS` is tracked by cargo. Conditionally omitting `-Zon-broken-pipe=kill` from
338        // `RUSTFLAGS` causes unnecessary tool rebuilds due to cache invalidation from building e.g.
339        // cargo *without* `-Zon-broken-pipe=kill` but then rustdoc *with* `-Zon-broken-pipe=kill`.
340        cargo.env("FORCE_ON_BROKEN_PIPE_KILL", "-Zon-broken-pipe=kill");
341    }
342
343    cargo
344}
345
346/// Handle stage-off logic for `ToolRustc` tools when necessary.
347pub(crate) fn get_tool_rustc_compiler(
348    builder: &Builder<'_>,
349    target_compiler: Compiler,
350) -> Compiler {
351    if target_compiler.is_forced_compiler() {
352        return target_compiler;
353    }
354
355    if builder.download_rustc() && target_compiler.stage == 1 {
356        // We shouldn't drop to stage0 compiler when using CI rustc.
357        return builder.compiler(1, builder.config.host_target);
358    }
359
360    // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
361    // we'd have stageN/bin/rustc and stageN/bin/$rustc_tool be effectively different stage
362    // compilers, which isn't what we want. Rustc tools should be linked in the same way as the
363    // compiler it's paired with, so it must be built with the previous stage compiler.
364    builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.host_target)
365}
366
367/// Links a built tool binary with the given `name` from the build directory to the
368/// tools directory.
369fn copy_link_tool_bin(
370    builder: &Builder<'_>,
371    compiler: Compiler,
372    target: TargetSelection,
373    mode: Mode,
374    name: &str,
375) -> PathBuf {
376    let cargo_out = builder.cargo_out(compiler, mode, target).join(exe(name, target));
377    let bin = builder.tools_dir(compiler).join(exe(name, target));
378    builder.copy_link(&cargo_out, &bin, FileType::Executable);
379    bin
380}
381
382macro_rules! bootstrap_tool {
383    ($(
384        $name:ident, $path:expr, $tool_name:expr
385        $(,is_external_tool = $external:expr)*
386        $(,is_unstable_tool = $unstable:expr)*
387        $(,allow_features = $allow_features:expr)?
388        $(,submodules = $submodules:expr)?
389        $(,artifact_kind = $artifact_kind:expr)?
390        ;
391    )+) => {
392        #[derive(PartialEq, Eq, Clone)]
393        pub enum Tool {
394            $(
395                $name,
396            )+
397        }
398
399        impl<'a> Builder<'a> {
400            pub fn tool_exe(&self, tool: Tool) -> PathBuf {
401                match tool {
402                    $(Tool::$name =>
403                        self.ensure($name {
404                            compiler: self.compiler(0, self.config.host_target),
405                            target: self.config.host_target,
406                        }).tool_path,
407                    )+
408                }
409            }
410        }
411
412        $(
413            #[derive(Debug, Clone, Hash, PartialEq, Eq)]
414        pub struct $name {
415            pub compiler: Compiler,
416            pub target: TargetSelection,
417        }
418
419        impl Step for $name {
420            type Output = ToolBuildResult;
421
422            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
423                run.path($path)
424            }
425
426            fn make_run(run: RunConfig<'_>) {
427                run.builder.ensure($name {
428                    // snapshot compiler
429                    compiler: run.builder.compiler(0, run.builder.config.host_target),
430                    target: run.target,
431                });
432            }
433
434            #[cfg_attr(
435                feature = "tracing",
436                instrument(
437                    level = "debug",
438                    name = $tool_name,
439                    skip_all,
440                ),
441            )]
442            fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
443                $(
444                    for submodule in $submodules {
445                        builder.require_submodule(submodule, None);
446                    }
447                )*
448
449                let is_unstable = false $(|| $unstable)*;
450                let compiletest_wants_stage0 = $tool_name == "compiletest" && builder.config.compiletest_use_stage0_libtest;
451
452                builder.ensure(ToolBuild {
453                    compiler: self.compiler,
454                    target: self.target,
455                    tool: $tool_name,
456                    mode: if is_unstable && !compiletest_wants_stage0 {
457                        // use in-tree libraries for unstable features
458                        Mode::ToolStd
459                    } else {
460                        Mode::ToolBootstrap
461                    },
462                    path: $path,
463                    source_type: if false $(|| $external)* {
464                        SourceType::Submodule
465                    } else {
466                        SourceType::InTree
467                    },
468                    extra_features: vec![],
469                    allow_features: {
470                        let mut _value = "";
471                        $( _value = $allow_features; )?
472                        _value
473                    },
474                    cargo_args: vec![],
475                    artifact_kind: if false $(|| $artifact_kind == ToolArtifactKind::Library)* {
476                        ToolArtifactKind::Library
477                    } else {
478                        ToolArtifactKind::Binary
479                    }
480                })
481            }
482
483            fn metadata(&self) -> Option<StepMetadata> {
484                Some(
485                    StepMetadata::build(stringify!($name), self.target)
486                        .built_by(self.compiler)
487                )
488            }
489        }
490        )+
491    }
492}
493
494pub(crate) const COMPILETEST_ALLOW_FEATURES: &str = "internal_output_capture";
495
496bootstrap_tool!(
497    // This is marked as an external tool because it includes dependencies
498    // from submodules. Trying to keep the lints in sync between all the repos
499    // is a bit of a pain. Unfortunately it means the rustbook source itself
500    // doesn't deny warnings, but it is a relatively small piece of code.
501    Rustbook, "src/tools/rustbook", "rustbook", is_external_tool = true, submodules = SUBMODULES_FOR_RUSTBOOK;
502    UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen";
503    Tidy, "src/tools/tidy", "tidy";
504    Linkchecker, "src/tools/linkchecker", "linkchecker";
505    CargoTest, "src/tools/cargotest", "cargotest";
506    Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES;
507    BuildManifest, "src/tools/build-manifest", "build-manifest";
508    RemoteTestClient, "src/tools/remote-test-client", "remote-test-client";
509    RustInstaller, "src/tools/rust-installer", "rust-installer";
510    RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes";
511    LintDocs, "src/tools/lint-docs", "lint-docs";
512    JsonDocCk, "src/tools/jsondocck", "jsondocck";
513    JsonDocLint, "src/tools/jsondoclint", "jsondoclint";
514    HtmlChecker, "src/tools/html-checker", "html-checker";
515    BumpStage0, "src/tools/bump-stage0", "bump-stage0";
516    ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder";
517    CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata";
518    GenerateCopyright, "src/tools/generate-copyright", "generate-copyright";
519    SuggestTests, "src/tools/suggest-tests", "suggest-tests";
520    GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys";
521    // rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features.
522    RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES;
523    CoverageDump, "src/tools/coverage-dump", "coverage-dump";
524    WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization";
525    UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator";
526    FeaturesStatusDump, "src/tools/features-status-dump", "features-status-dump";
527    OptimizedDist, "src/tools/opt-dist", "opt-dist", submodules = &["src/tools/rustc-perf"];
528    RunMakeSupport, "src/tools/run-make-support", "run_make_support", artifact_kind = ToolArtifactKind::Library;
529);
530
531/// These are the submodules that are required for rustbook to work due to
532/// depending on mdbook plugins.
533pub static SUBMODULES_FOR_RUSTBOOK: &[&str] = &["src/doc/book", "src/doc/reference"];
534
535/// The [rustc-perf](https://github.com/rust-lang/rustc-perf) benchmark suite, which is added
536/// as a submodule at `src/tools/rustc-perf`.
537#[derive(Debug, Clone, Hash, PartialEq, Eq)]
538pub struct RustcPerf {
539    pub compiler: Compiler,
540    pub target: TargetSelection,
541}
542
543impl Step for RustcPerf {
544    /// Path to the built `collector` binary.
545    type Output = ToolBuildResult;
546
547    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
548        run.path("src/tools/rustc-perf")
549    }
550
551    fn make_run(run: RunConfig<'_>) {
552        run.builder.ensure(RustcPerf {
553            compiler: run.builder.compiler(0, run.builder.config.host_target),
554            target: run.target,
555        });
556    }
557
558    fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
559        // We need to ensure the rustc-perf submodule is initialized.
560        builder.require_submodule("src/tools/rustc-perf", None);
561
562        let tool = ToolBuild {
563            compiler: self.compiler,
564            target: self.target,
565            tool: "collector",
566            mode: Mode::ToolBootstrap,
567            path: "src/tools/rustc-perf",
568            source_type: SourceType::Submodule,
569            extra_features: Vec::new(),
570            allow_features: "",
571            // Only build the collector package, which is used for benchmarking through
572            // a CLI.
573            cargo_args: vec!["-p".to_string(), "collector".to_string()],
574            artifact_kind: ToolArtifactKind::Binary,
575        };
576        let res = builder.ensure(tool.clone());
577        // We also need to symlink the `rustc-fake` binary to the corresponding directory,
578        // because `collector` expects it in the same directory.
579        copy_link_tool_bin(builder, tool.compiler, tool.target, tool.mode, "rustc-fake");
580
581        res
582    }
583}
584
585#[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
586pub struct ErrorIndex {
587    pub compiler: Compiler,
588}
589
590impl ErrorIndex {
591    pub fn command(builder: &Builder<'_>) -> BootstrapCommand {
592        // Error-index-generator links with the rustdoc library, so we need to add `rustc_lib_paths`
593        // for rustc_private and libLLVM.so, and `sysroot_lib` for libstd, etc.
594        let host = builder.config.host_target;
595        let compiler = builder.compiler_for(builder.top_stage, host, host);
596        let mut cmd = command(builder.ensure(ErrorIndex { compiler }).tool_path);
597        let mut dylib_paths = builder.rustc_lib_paths(compiler);
598        dylib_paths.push(builder.sysroot_target_libdir(compiler, compiler.host));
599        add_dylib_path(dylib_paths, &mut cmd);
600        cmd
601    }
602}
603
604impl Step for ErrorIndex {
605    type Output = ToolBuildResult;
606
607    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
608        run.path("src/tools/error_index_generator")
609    }
610
611    fn make_run(run: RunConfig<'_>) {
612        // NOTE: This `make_run` isn't used in normal situations, only if you
613        // manually build the tool with `x.py build
614        // src/tools/error-index-generator` which almost nobody does.
615        // Normally, `x.py test` or `x.py doc` will use the
616        // `ErrorIndex::command` function instead.
617        let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.host_target);
618        run.builder.ensure(ErrorIndex { compiler });
619    }
620
621    fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
622        builder.ensure(ToolBuild {
623            compiler: self.compiler,
624            target: self.compiler.host,
625            tool: "error_index_generator",
626            mode: Mode::ToolRustc,
627            path: "src/tools/error_index_generator",
628            source_type: SourceType::InTree,
629            extra_features: Vec::new(),
630            allow_features: "",
631            cargo_args: Vec::new(),
632            artifact_kind: ToolArtifactKind::Binary,
633        })
634    }
635}
636
637#[derive(Debug, Clone, Hash, PartialEq, Eq)]
638pub struct RemoteTestServer {
639    pub compiler: Compiler,
640    pub target: TargetSelection,
641}
642
643impl Step for RemoteTestServer {
644    type Output = ToolBuildResult;
645
646    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
647        run.path("src/tools/remote-test-server")
648    }
649
650    fn make_run(run: RunConfig<'_>) {
651        run.builder.ensure(RemoteTestServer {
652            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
653            target: run.target,
654        });
655    }
656
657    fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
658        builder.ensure(ToolBuild {
659            compiler: self.compiler,
660            target: self.target,
661            tool: "remote-test-server",
662            mode: Mode::ToolStd,
663            path: "src/tools/remote-test-server",
664            source_type: SourceType::InTree,
665            extra_features: Vec::new(),
666            allow_features: "",
667            cargo_args: Vec::new(),
668            artifact_kind: ToolArtifactKind::Binary,
669        })
670    }
671}
672
673#[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
674pub struct Rustdoc {
675    /// This should only ever be 0 or 2.
676    /// We sometimes want to reference the "bootstrap" rustdoc, which is why this option is here.
677    pub compiler: Compiler,
678}
679
680impl Step for Rustdoc {
681    type Output = ToolBuildResult;
682    const DEFAULT: bool = true;
683    const ONLY_HOSTS: bool = true;
684
685    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
686        run.path("src/tools/rustdoc").path("src/librustdoc")
687    }
688
689    fn make_run(run: RunConfig<'_>) {
690        run.builder
691            .ensure(Rustdoc { compiler: run.builder.compiler(run.builder.top_stage, run.target) });
692    }
693
694    fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
695        let target_compiler = self.compiler;
696        let target = target_compiler.host;
697
698        if target_compiler.stage == 0 {
699            if !target_compiler.is_snapshot(builder) {
700                panic!("rustdoc in stage 0 must be snapshot rustdoc");
701            }
702
703            return ToolBuildResult {
704                tool_path: builder.initial_rustdoc.clone(),
705                build_compiler: target_compiler,
706                target_compiler,
707            };
708        }
709
710        let bin_rustdoc = || {
711            let sysroot = builder.sysroot(target_compiler);
712            let bindir = sysroot.join("bin");
713            t!(fs::create_dir_all(&bindir));
714            let bin_rustdoc = bindir.join(exe("rustdoc", target_compiler.host));
715            let _ = fs::remove_file(&bin_rustdoc);
716            bin_rustdoc
717        };
718
719        // If CI rustc is enabled and we haven't modified the rustdoc sources,
720        // use the precompiled rustdoc from CI rustc's sysroot to speed up bootstrapping.
721        if builder.download_rustc()
722            && target_compiler.stage > 0
723            && builder.rust_info().is_managed_git_subrepository()
724        {
725            let files_to_track = &["src/librustdoc", "src/tools/rustdoc", "src/rustdoc-json-types"];
726
727            // Check if unchanged
728            if !builder.config.has_changes_from_upstream(files_to_track) {
729                let precompiled_rustdoc = builder
730                    .config
731                    .ci_rustc_dir()
732                    .join("bin")
733                    .join(exe("rustdoc", target_compiler.host));
734
735                let bin_rustdoc = bin_rustdoc();
736                builder.copy_link(&precompiled_rustdoc, &bin_rustdoc, FileType::Executable);
737
738                return ToolBuildResult {
739                    tool_path: bin_rustdoc,
740                    build_compiler: target_compiler,
741                    target_compiler,
742                };
743            }
744        }
745
746        // The presence of `target_compiler` ensures that the necessary libraries (codegen backends,
747        // compiler libraries, ...) are built. Rustdoc does not require the presence of any
748        // libraries within sysroot_libdir (i.e., rustlib), though doctests may want it (since
749        // they'll be linked to those libraries). As such, don't explicitly `ensure` any additional
750        // libraries here. The intuition here is that If we've built a compiler, we should be able
751        // to build rustdoc.
752        //
753        let mut extra_features = Vec::new();
754        if builder.config.jemalloc(target) {
755            extra_features.push("jemalloc".to_string());
756        }
757
758        let ToolBuildResult { tool_path, build_compiler, target_compiler } =
759            builder.ensure(ToolBuild {
760                compiler: target_compiler,
761                target,
762                // Cargo adds a number of paths to the dylib search path on windows, which results in
763                // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
764                // rustdoc a different name.
765                tool: "rustdoc_tool_binary",
766                mode: Mode::ToolRustc,
767                path: "src/tools/rustdoc",
768                source_type: SourceType::InTree,
769                extra_features,
770                allow_features: "",
771                cargo_args: Vec::new(),
772                artifact_kind: ToolArtifactKind::Binary,
773            });
774
775        // don't create a stage0-sysroot/bin directory.
776        if target_compiler.stage > 0 {
777            if builder.config.rust_debuginfo_level_tools == DebuginfoLevel::None {
778                // Due to LTO a lot of debug info from C++ dependencies such as jemalloc can make it into
779                // our final binaries
780                compile::strip_debug(builder, target, &tool_path);
781            }
782            let bin_rustdoc = bin_rustdoc();
783            builder.copy_link(&tool_path, &bin_rustdoc, FileType::Executable);
784            ToolBuildResult { tool_path: bin_rustdoc, build_compiler, target_compiler }
785        } else {
786            ToolBuildResult { tool_path, build_compiler, target_compiler }
787        }
788    }
789
790    fn metadata(&self) -> Option<StepMetadata> {
791        Some(
792            StepMetadata::build("rustdoc", self.compiler.host)
793                // rustdoc is ToolRustc, so stage N rustdoc is built by stage N-1 rustc
794                // FIXME: make this stage deduction automatic somehow
795                // FIXME: log the compiler that actually built ToolRustc steps
796                .stage(self.compiler.stage.saturating_sub(1)),
797        )
798    }
799}
800
801#[derive(Debug, Clone, Hash, PartialEq, Eq)]
802pub struct Cargo {
803    pub compiler: Compiler,
804    pub target: TargetSelection,
805}
806
807impl Step for Cargo {
808    type Output = ToolBuildResult;
809    const DEFAULT: bool = true;
810    const ONLY_HOSTS: bool = true;
811
812    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
813        let builder = run.builder;
814        run.path("src/tools/cargo").default_condition(builder.tool_enabled("cargo"))
815    }
816
817    fn make_run(run: RunConfig<'_>) {
818        run.builder.ensure(Cargo {
819            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
820            target: run.target,
821        });
822    }
823
824    fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
825        builder.build.require_submodule("src/tools/cargo", None);
826
827        builder.ensure(ToolBuild {
828            compiler: self.compiler,
829            target: self.target,
830            tool: "cargo",
831            mode: Mode::ToolRustc,
832            path: "src/tools/cargo",
833            source_type: SourceType::Submodule,
834            extra_features: Vec::new(),
835            allow_features: "",
836            cargo_args: Vec::new(),
837            artifact_kind: ToolArtifactKind::Binary,
838        })
839    }
840}
841
842#[derive(Debug, Clone, Hash, PartialEq, Eq)]
843pub struct LldWrapper {
844    pub build_compiler: Compiler,
845    pub target_compiler: Compiler,
846}
847
848impl Step for LldWrapper {
849    type Output = ToolBuildResult;
850
851    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
852        run.never()
853    }
854
855    #[cfg_attr(
856        feature = "tracing",
857        instrument(
858            level = "debug",
859            name = "LldWrapper::run",
860            skip_all,
861            fields(build_compiler = ?self.build_compiler, target_compiler = ?self.target_compiler),
862        ),
863    )]
864    fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
865        if builder.config.dry_run() {
866            return ToolBuildResult {
867                tool_path: Default::default(),
868                build_compiler: self.build_compiler,
869                target_compiler: self.target_compiler,
870            };
871        }
872
873        let target = self.target_compiler.host;
874
875        let tool_result = builder.ensure(ToolBuild {
876            compiler: self.build_compiler,
877            target,
878            tool: "lld-wrapper",
879            mode: Mode::ToolStd,
880            path: "src/tools/lld-wrapper",
881            source_type: SourceType::InTree,
882            extra_features: Vec::new(),
883            allow_features: "",
884            cargo_args: Vec::new(),
885            artifact_kind: ToolArtifactKind::Binary,
886        });
887
888        let libdir_bin = builder.sysroot_target_bindir(self.target_compiler, target);
889        t!(fs::create_dir_all(&libdir_bin));
890
891        let lld_install = builder.ensure(llvm::Lld { target });
892        let src_exe = exe("lld", target);
893        let dst_exe = exe("rust-lld", target);
894
895        builder.copy_link(
896            &lld_install.join("bin").join(src_exe),
897            &libdir_bin.join(dst_exe),
898            FileType::Executable,
899        );
900        let self_contained_lld_dir = libdir_bin.join("gcc-ld");
901        t!(fs::create_dir_all(&self_contained_lld_dir));
902
903        for name in crate::LLD_FILE_NAMES {
904            builder.copy_link(
905                &tool_result.tool_path,
906                &self_contained_lld_dir.join(exe(name, target)),
907                FileType::Executable,
908            );
909        }
910
911        tool_result
912    }
913}
914
915#[derive(Debug, Clone, Hash, PartialEq, Eq)]
916pub struct RustAnalyzer {
917    pub compiler: Compiler,
918    pub target: TargetSelection,
919}
920
921impl RustAnalyzer {
922    pub const ALLOW_FEATURES: &'static str = "rustc_private,proc_macro_internals,proc_macro_diagnostic,proc_macro_span,proc_macro_span_shrink,proc_macro_def_site";
923}
924
925impl Step for RustAnalyzer {
926    type Output = ToolBuildResult;
927    const DEFAULT: bool = true;
928    const ONLY_HOSTS: bool = true;
929
930    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
931        let builder = run.builder;
932        run.path("src/tools/rust-analyzer").default_condition(builder.tool_enabled("rust-analyzer"))
933    }
934
935    fn make_run(run: RunConfig<'_>) {
936        run.builder.ensure(RustAnalyzer {
937            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
938            target: run.target,
939        });
940    }
941
942    fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
943        builder.ensure(ToolBuild {
944            compiler: self.compiler,
945            target: self.target,
946            tool: "rust-analyzer",
947            mode: Mode::ToolRustc,
948            path: "src/tools/rust-analyzer",
949            extra_features: vec!["in-rust-tree".to_owned()],
950            source_type: SourceType::InTree,
951            allow_features: RustAnalyzer::ALLOW_FEATURES,
952            cargo_args: Vec::new(),
953            artifact_kind: ToolArtifactKind::Binary,
954        })
955    }
956}
957
958#[derive(Debug, Clone, Hash, PartialEq, Eq)]
959pub struct RustAnalyzerProcMacroSrv {
960    pub compiler: Compiler,
961    pub target: TargetSelection,
962}
963
964impl Step for RustAnalyzerProcMacroSrv {
965    type Output = Option<ToolBuildResult>;
966    const DEFAULT: bool = true;
967    const ONLY_HOSTS: bool = true;
968
969    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
970        let builder = run.builder;
971        // Allow building `rust-analyzer-proc-macro-srv` both as part of the `rust-analyzer` and as a stand-alone tool.
972        run.path("src/tools/rust-analyzer")
973            .path("src/tools/rust-analyzer/crates/proc-macro-srv-cli")
974            .default_condition(
975                builder.tool_enabled("rust-analyzer")
976                    || builder.tool_enabled("rust-analyzer-proc-macro-srv"),
977            )
978    }
979
980    fn make_run(run: RunConfig<'_>) {
981        run.builder.ensure(RustAnalyzerProcMacroSrv {
982            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
983            target: run.target,
984        });
985    }
986
987    fn run(self, builder: &Builder<'_>) -> Option<ToolBuildResult> {
988        let tool_result = builder.ensure(ToolBuild {
989            compiler: self.compiler,
990            target: self.target,
991            tool: "rust-analyzer-proc-macro-srv",
992            mode: Mode::ToolRustc,
993            path: "src/tools/rust-analyzer/crates/proc-macro-srv-cli",
994            extra_features: vec!["in-rust-tree".to_owned()],
995            source_type: SourceType::InTree,
996            allow_features: RustAnalyzer::ALLOW_FEATURES,
997            cargo_args: Vec::new(),
998            artifact_kind: ToolArtifactKind::Binary,
999        });
1000
1001        // Copy `rust-analyzer-proc-macro-srv` to `<sysroot>/libexec/`
1002        // so that r-a can use it.
1003        let libexec_path = builder.sysroot(self.compiler).join("libexec");
1004        t!(fs::create_dir_all(&libexec_path));
1005        builder.copy_link(
1006            &tool_result.tool_path,
1007            &libexec_path.join("rust-analyzer-proc-macro-srv"),
1008            FileType::Executable,
1009        );
1010
1011        Some(tool_result)
1012    }
1013}
1014
1015#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1016pub struct LlvmBitcodeLinker {
1017    pub compiler: Compiler,
1018    pub target: TargetSelection,
1019    pub extra_features: Vec<String>,
1020}
1021
1022impl Step for LlvmBitcodeLinker {
1023    type Output = ToolBuildResult;
1024    const DEFAULT: bool = true;
1025    const ONLY_HOSTS: bool = true;
1026
1027    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1028        let builder = run.builder;
1029        run.path("src/tools/llvm-bitcode-linker")
1030            .default_condition(builder.tool_enabled("llvm-bitcode-linker"))
1031    }
1032
1033    fn make_run(run: RunConfig<'_>) {
1034        run.builder.ensure(LlvmBitcodeLinker {
1035            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
1036            extra_features: Vec::new(),
1037            target: run.target,
1038        });
1039    }
1040
1041    #[cfg_attr(
1042        feature = "tracing",
1043        instrument(level = "debug", name = "LlvmBitcodeLinker::run", skip_all)
1044    )]
1045    fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
1046        let tool_result = builder.ensure(ToolBuild {
1047            compiler: self.compiler,
1048            target: self.target,
1049            tool: "llvm-bitcode-linker",
1050            mode: Mode::ToolRustc,
1051            path: "src/tools/llvm-bitcode-linker",
1052            source_type: SourceType::InTree,
1053            extra_features: self.extra_features,
1054            allow_features: "",
1055            cargo_args: Vec::new(),
1056            artifact_kind: ToolArtifactKind::Binary,
1057        });
1058
1059        if tool_result.target_compiler.stage > 0 {
1060            let bindir_self_contained = builder
1061                .sysroot(tool_result.target_compiler)
1062                .join(format!("lib/rustlib/{}/bin/self-contained", self.target.triple));
1063            t!(fs::create_dir_all(&bindir_self_contained));
1064            let bin_destination = bindir_self_contained
1065                .join(exe("llvm-bitcode-linker", tool_result.target_compiler.host));
1066            builder.copy_link(&tool_result.tool_path, &bin_destination, FileType::Executable);
1067            ToolBuildResult {
1068                tool_path: bin_destination,
1069                build_compiler: tool_result.build_compiler,
1070                target_compiler: tool_result.target_compiler,
1071            }
1072        } else {
1073            tool_result
1074        }
1075    }
1076}
1077
1078#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1079pub struct LibcxxVersionTool {
1080    pub target: TargetSelection,
1081}
1082
1083#[expect(dead_code)]
1084#[derive(Debug, Clone)]
1085pub enum LibcxxVersion {
1086    Gnu(usize),
1087    Llvm(usize),
1088}
1089
1090impl Step for LibcxxVersionTool {
1091    type Output = LibcxxVersion;
1092    const DEFAULT: bool = false;
1093    const ONLY_HOSTS: bool = true;
1094
1095    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1096        run.never()
1097    }
1098
1099    fn run(self, builder: &Builder<'_>) -> LibcxxVersion {
1100        let out_dir = builder.out.join(self.target.to_string()).join("libcxx-version");
1101        let executable = out_dir.join(exe("libcxx-version", self.target));
1102
1103        // This is a sanity-check specific step, which means it is frequently called (when using
1104        // CI LLVM), and compiling `src/tools/libcxx-version/main.cpp` at the beginning of the bootstrap
1105        // invocation adds a fair amount of overhead to the process (see https://github.com/rust-lang/rust/issues/126423).
1106        // Therefore, we want to avoid recompiling this file unnecessarily.
1107        if !executable.exists() {
1108            if !out_dir.exists() {
1109                t!(fs::create_dir_all(&out_dir));
1110            }
1111
1112            let compiler = builder.cxx(self.target).unwrap();
1113            let mut cmd = command(compiler);
1114
1115            cmd.arg("-o")
1116                .arg(&executable)
1117                .arg(builder.src.join("src/tools/libcxx-version/main.cpp"));
1118
1119            cmd.run(builder);
1120
1121            if !executable.exists() {
1122                panic!("Something went wrong. {} is not present", executable.display());
1123            }
1124        }
1125
1126        let version_output = command(executable).run_capture_stdout(builder).stdout();
1127
1128        let version_str = version_output.split_once("version:").unwrap().1;
1129        let version = version_str.trim().parse::<usize>().unwrap();
1130
1131        if version_output.starts_with("libstdc++") {
1132            LibcxxVersion::Gnu(version)
1133        } else if version_output.starts_with("libc++") {
1134            LibcxxVersion::Llvm(version)
1135        } else {
1136            panic!("Coudln't recognize the standard library version.");
1137        }
1138    }
1139}
1140
1141macro_rules! tool_extended {
1142    (
1143        $name:ident {
1144            path: $path:expr,
1145            tool_name: $tool_name:expr,
1146            stable: $stable:expr
1147            $( , add_bins_to_sysroot: $add_bins_to_sysroot:expr )?
1148            $( , add_features: $add_features:expr )?
1149            $( , )?
1150        }
1151    ) => {
1152        #[derive(Debug, Clone, Hash, PartialEq, Eq)]
1153        pub struct $name {
1154            pub compiler: Compiler,
1155            pub target: TargetSelection,
1156        }
1157
1158        impl Step for $name {
1159            type Output = ToolBuildResult;
1160            const DEFAULT: bool = true; // Overridden by `should_run_tool_build_step`
1161            const ONLY_HOSTS: bool = true;
1162
1163            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1164                should_run_tool_build_step(
1165                    run,
1166                    $tool_name,
1167                    $path,
1168                    $stable,
1169                )
1170            }
1171
1172            fn make_run(run: RunConfig<'_>) {
1173                run.builder.ensure($name {
1174                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
1175                    target: run.target,
1176                });
1177            }
1178
1179            fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
1180                let Self { compiler, target } = self;
1181                run_tool_build_step(
1182                    builder,
1183                    compiler,
1184                    target,
1185                    $tool_name,
1186                    $path,
1187                    None $( .or(Some(&$add_bins_to_sysroot)) )?,
1188                    None $( .or(Some($add_features)) )?,
1189                )
1190            }
1191
1192            fn metadata(&self) -> Option<StepMetadata> {
1193                // FIXME: refactor extended tool steps to make the build_compiler explicit,
1194                // it is offset by one now for rustc tools
1195                Some(
1196                    StepMetadata::build($tool_name, self.target)
1197                        .built_by(self.compiler.with_stage(self.compiler.stage.saturating_sub(1)))
1198                        .stage(self.compiler.stage)
1199                )
1200            }
1201        }
1202    }
1203}
1204
1205fn should_run_tool_build_step<'a>(
1206    run: ShouldRun<'a>,
1207    tool_name: &'static str,
1208    path: &'static str,
1209    stable: bool,
1210) -> ShouldRun<'a> {
1211    let builder = run.builder;
1212    run.path(path).default_condition(
1213        builder.config.extended
1214            && builder.config.tools.as_ref().map_or(
1215                // By default, on nightly/dev enable all tools, else only
1216                // build stable tools.
1217                stable || builder.build.unstable_features(),
1218                // If `tools` is set, search list for this tool.
1219                |tools| {
1220                    tools.iter().any(|tool| match tool.as_ref() {
1221                        "clippy" => tool_name == "clippy-driver",
1222                        x => tool_name == x,
1223                    })
1224                },
1225            ),
1226    )
1227}
1228
1229fn run_tool_build_step(
1230    builder: &Builder<'_>,
1231    compiler: Compiler,
1232    target: TargetSelection,
1233    tool_name: &'static str,
1234    path: &'static str,
1235    add_bins_to_sysroot: Option<&[&str]>,
1236    add_features: Option<fn(&Builder<'_>, TargetSelection, &mut Vec<String>)>,
1237) -> ToolBuildResult {
1238    let mut extra_features = Vec::new();
1239    if let Some(func) = add_features {
1240        func(builder, target, &mut extra_features);
1241    }
1242
1243    let ToolBuildResult { tool_path, build_compiler, target_compiler } =
1244        builder.ensure(ToolBuild {
1245            compiler,
1246            target,
1247            tool: tool_name,
1248            mode: Mode::ToolRustc,
1249            path,
1250            extra_features,
1251            source_type: SourceType::InTree,
1252            allow_features: "",
1253            cargo_args: vec![],
1254            artifact_kind: ToolArtifactKind::Binary,
1255        });
1256
1257    if let Some(add_bins_to_sysroot) = add_bins_to_sysroot
1258        && !add_bins_to_sysroot.is_empty()
1259        && target_compiler.stage > 0
1260    {
1261        let bindir = builder.sysroot(target_compiler).join("bin");
1262        t!(fs::create_dir_all(&bindir));
1263
1264        for add_bin in add_bins_to_sysroot {
1265            let bin_destination = bindir.join(exe(add_bin, target_compiler.host));
1266            builder.copy_link(&tool_path, &bin_destination, FileType::Executable);
1267        }
1268
1269        // Return a path into the bin dir.
1270        let path = bindir.join(exe(tool_name, target_compiler.host));
1271        ToolBuildResult { tool_path: path, build_compiler, target_compiler }
1272    } else {
1273        ToolBuildResult { tool_path, build_compiler, target_compiler }
1274    }
1275}
1276
1277tool_extended!(Cargofmt {
1278    path: "src/tools/rustfmt",
1279    tool_name: "cargo-fmt",
1280    stable: true,
1281    add_bins_to_sysroot: ["cargo-fmt"]
1282});
1283tool_extended!(CargoClippy {
1284    path: "src/tools/clippy",
1285    tool_name: "cargo-clippy",
1286    stable: true,
1287    add_bins_to_sysroot: ["cargo-clippy"]
1288});
1289tool_extended!(Clippy {
1290    path: "src/tools/clippy",
1291    tool_name: "clippy-driver",
1292    stable: true,
1293    add_bins_to_sysroot: ["clippy-driver"],
1294    add_features: |builder, target, features| {
1295        if builder.config.jemalloc(target) {
1296            features.push("jemalloc".to_string());
1297        }
1298    }
1299});
1300tool_extended!(Miri {
1301    path: "src/tools/miri",
1302    tool_name: "miri",
1303    stable: false,
1304    add_bins_to_sysroot: ["miri"]
1305});
1306tool_extended!(CargoMiri {
1307    path: "src/tools/miri/cargo-miri",
1308    tool_name: "cargo-miri",
1309    stable: false,
1310    add_bins_to_sysroot: ["cargo-miri"]
1311});
1312tool_extended!(Rustfmt {
1313    path: "src/tools/rustfmt",
1314    tool_name: "rustfmt",
1315    stable: true,
1316    add_bins_to_sysroot: ["rustfmt"]
1317});
1318
1319#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1320pub struct TestFloatParse {
1321    pub host: TargetSelection,
1322}
1323
1324impl TestFloatParse {
1325    pub const ALLOW_FEATURES: &'static str = "f16,cfg_target_has_reliable_f16_f128";
1326}
1327
1328impl Step for TestFloatParse {
1329    type Output = ToolBuildResult;
1330    const ONLY_HOSTS: bool = true;
1331    const DEFAULT: bool = false;
1332
1333    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1334        run.path("src/tools/test-float-parse")
1335    }
1336
1337    fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
1338        let bootstrap_host = builder.config.host_target;
1339        let compiler = builder.compiler(builder.top_stage, bootstrap_host);
1340
1341        builder.ensure(ToolBuild {
1342            compiler,
1343            target: bootstrap_host,
1344            tool: "test-float-parse",
1345            mode: Mode::ToolStd,
1346            path: "src/tools/test-float-parse",
1347            source_type: SourceType::InTree,
1348            extra_features: Vec::new(),
1349            allow_features: Self::ALLOW_FEATURES,
1350            cargo_args: Vec::new(),
1351            artifact_kind: ToolArtifactKind::Binary,
1352        })
1353    }
1354}
1355
1356impl Builder<'_> {
1357    /// Gets a `BootstrapCommand` which is ready to run `tool` in `stage` built for
1358    /// `host`.
1359    pub fn tool_cmd(&self, tool: Tool) -> BootstrapCommand {
1360        let mut cmd = command(self.tool_exe(tool));
1361        let compiler = self.compiler(0, self.config.host_target);
1362        let host = &compiler.host;
1363        // Prepares the `cmd` provided to be able to run the `compiler` provided.
1364        //
1365        // Notably this munges the dynamic library lookup path to point to the
1366        // right location to run `compiler`.
1367        let mut lib_paths: Vec<PathBuf> =
1368            vec![self.cargo_out(compiler, Mode::ToolBootstrap, *host).join("deps")];
1369
1370        // On MSVC a tool may invoke a C compiler (e.g., compiletest in run-make
1371        // mode) and that C compiler may need some extra PATH modification. Do
1372        // so here.
1373        if compiler.host.is_msvc() {
1374            let curpaths = env::var_os("PATH").unwrap_or_default();
1375            let curpaths = env::split_paths(&curpaths).collect::<Vec<_>>();
1376            for (k, v) in self.cc[&compiler.host].env() {
1377                if k != "PATH" {
1378                    continue;
1379                }
1380                for path in env::split_paths(v) {
1381                    if !curpaths.contains(&path) {
1382                        lib_paths.push(path);
1383                    }
1384                }
1385            }
1386        }
1387
1388        add_dylib_path(lib_paths, &mut cmd);
1389
1390        // Provide a RUSTC for this command to use.
1391        cmd.env("RUSTC", &self.initial_rustc);
1392
1393        cmd
1394    }
1395}