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