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