src/bootstrap/src/core/build_steps/compile.rs RUST 2,932 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 2,932.
1//! Implementation of compiling various phases of the compiler and standard2//! library.3//!4//! This module contains some of the real meat in the bootstrap build system5//! which is where Cargo is used to compile the standard library, libtest, and6//! the compiler. This module is also responsible for assembling the sysroot as it7//! goes along from the output of the previous stage.89use std::borrow::Cow;10use std::collections::{BTreeMap, HashMap, HashSet};11use std::ffi::OsStr;12use std::io::BufReader;13use std::io::prelude::*;14use std::path::{Path, PathBuf};15use std::time::SystemTime;16use std::{env, fs, str};1718use serde_derive::Deserialize;19#[cfg(feature = "tracing")]20use tracing::span;2122use crate::core::build_steps::gcc::{Gcc, GccOutput, GccTargetPair};23use crate::core::build_steps::tool::{RustcPrivateCompilers, SourceType, copy_lld_artifacts};24use crate::core::build_steps::{dist, llvm};25use crate::core::builder;26use crate::core::builder::{27    Builder, Cargo, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description,28};29use crate::core::config::toml::target::DefaultLinuxLinkerOverride;30use crate::core::config::{31    CompilerBuiltins, DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection,32};33use crate::utils::build_stamp;34use crate::utils::build_stamp::BuildStamp;35use crate::utils::exec::command;36use crate::utils::helpers::{37    exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,38};39use crate::{40    CLang, CodegenBackendKind, Compiler, DependencyType, FileType, GitRepo, LLVM_TOOLS, Mode,41    debug, trace,42};4344/// Build a standard library for the given `target` using the given `build_compiler`.45#[derive(Debug, Clone, PartialEq, Eq, Hash)]46pub struct Std {47    pub target: TargetSelection,48    /// Compiler that builds the standard library.49    pub build_compiler: Compiler,50    /// Whether to build only a subset of crates in the standard library.51    ///52    /// This shouldn't be used from other steps; see the comment on [`Rustc`].53    crates: Vec<String>,54    /// When using download-rustc, we need to use a new build of `std` for running unit tests of Std itself,55    /// but we need to use the downloaded copy of std for linking to rustdoc. Allow this to be overridden by `builder.ensure` from other steps.56    force_recompile: bool,57    extra_rust_args: &'static [&'static str],58    is_for_mir_opt_tests: bool,59}6061impl Std {62    pub fn new(build_compiler: Compiler, target: TargetSelection) -> Self {63        Self {64            target,65            build_compiler,66            crates: Default::default(),67            force_recompile: false,68            extra_rust_args: &[],69            is_for_mir_opt_tests: false,70        }71    }7273    pub fn force_recompile(mut self, force_recompile: bool) -> Self {74        self.force_recompile = force_recompile;75        self76    }7778    #[expect(clippy::wrong_self_convention)]79    pub fn is_for_mir_opt_tests(mut self, is_for_mir_opt_tests: bool) -> Self {80        self.is_for_mir_opt_tests = is_for_mir_opt_tests;81        self82    }8384    pub fn extra_rust_args(mut self, extra_rust_args: &'static [&'static str]) -> Self {85        self.extra_rust_args = extra_rust_args;86        self87    }8889    fn copy_extra_objects(90        &self,91        builder: &Builder<'_>,92        compiler: &Compiler,93        target: TargetSelection,94    ) -> Vec<(PathBuf, DependencyType)> {95        let mut deps = Vec::new();96        if !self.is_for_mir_opt_tests {97            deps.extend(copy_third_party_objects(builder, compiler, target));98            deps.extend(copy_self_contained_objects(builder, compiler, target));99        }100        deps101    }102103    /// Returns true if the standard library should be uplifted from stage 1.104    ///105    /// Uplifting is enabled if we're building a stage2+ libstd and full bootstrap is106    /// disabled.107    pub fn should_be_uplifted_from_stage_1(builder: &Builder<'_>, stage: u32) -> bool {108        stage > 1 && !builder.config.full_bootstrap109    }110}111112impl Step for Std {113    /// Build stamp of std, if it was indeed built or uplifted.114    type Output = Option<BuildStamp>;115116    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {117        run.crate_or_deps("sysroot").path("library")118    }119120    fn is_default_step(_builder: &Builder<'_>) -> bool {121        true122    }123124    fn make_run(run: RunConfig<'_>) {125        let crates = std_crates_for_run_make(&run);126        let builder = run.builder;127128        // Force compilation of the standard library from source if the `library` is modified. This allows129        // library team to compile the standard library without needing to compile the compiler with130        // the `rust.download-rustc=true` option.131        let force_recompile = builder.rust_info().is_managed_git_subrepository()132            && builder.download_rustc()133            && builder.config.has_changes_from_upstream(&["library"]);134135        trace!("is managed git repo: {}", builder.rust_info().is_managed_git_subrepository());136        trace!("download_rustc: {}", builder.download_rustc());137        trace!(force_recompile);138139        run.builder.ensure(Std {140            // Note: we don't use compiler_for_std here, so that `x build library --stage 2`141            // builds a stage2 rustc.142            build_compiler: run.builder.compiler(run.builder.top_stage, builder.host_target),143            target: run.target,144            crates,145            force_recompile,146            extra_rust_args: &[],147            is_for_mir_opt_tests: false,148        });149    }150151    /// Builds the standard library.152    ///153    /// This will build the standard library for a particular stage of the build154    /// using the `compiler` targeting the `target` architecture. The artifacts155    /// created will also be linked into the sysroot directory.156    fn run(self, builder: &Builder<'_>) -> Self::Output {157        let target = self.target;158159        // In most cases, we already have the std ready to be used for stage 0.160        // However, if we are doing a local rebuild (so the build compiler can compile the standard161        // library even on stage 0), and we're cross-compiling (so the stage0 standard library for162        // *target* is not available), we still allow the stdlib to be built here.163        if self.build_compiler.stage == 0164            && !(builder.local_rebuild && target != builder.host_target)165        {166            let compiler = self.build_compiler;167            builder.ensure(StdLink::from_std(self, compiler));168169            return None;170        }171172        let build_compiler = if builder.download_rustc() && self.force_recompile {173            // When there are changes in the library tree with CI-rustc, we want to build174            // the stageN library and that requires using stageN-1 compiler.175            builder176                .compiler(self.build_compiler.stage.saturating_sub(1), builder.config.host_target)177        } else {178            self.build_compiler179        };180181        // When using `download-rustc`, we already have artifacts for the host available. Don't182        // recompile them.183        if builder.download_rustc()184            && builder.config.is_host_target(target)185            && !self.force_recompile186        {187            let sysroot =188                builder.ensure(Sysroot { compiler: build_compiler, force_recompile: false });189            cp_rustc_component_to_ci_sysroot(190                builder,191                &sysroot,192                builder.config.ci_rust_std_contents(),193            );194            return None;195        }196197        if builder.config.keep_stage.contains(&build_compiler.stage)198            || builder.config.keep_stage_std.contains(&build_compiler.stage)199        {200            trace!(keep_stage = ?builder.config.keep_stage);201            trace!(keep_stage_std = ?builder.config.keep_stage_std);202203            builder.info("WARNING: Using a potentially old libstd. This may not behave well.");204205            builder.ensure(StartupObjects { compiler: build_compiler, target });206207            self.copy_extra_objects(builder, &build_compiler, target);208209            builder.ensure(StdLink::from_std(self, build_compiler));210            return Some(build_stamp::libstd_stamp(builder, build_compiler, target));211        }212213        let mut target_deps = builder.ensure(StartupObjects { compiler: build_compiler, target });214215        // Stage of the stdlib that we're building216        let stage = build_compiler.stage;217218        if Self::should_be_uplifted_from_stage_1(builder, build_compiler.stage) {219            let build_compiler_for_std_to_uplift = builder.compiler(1, builder.host_target);220            let stage_1_stamp = builder.std(build_compiler_for_std_to_uplift, target);221222            let msg = if build_compiler_for_std_to_uplift.host == target {223                format!(224                    "Uplifting library (stage{} -> stage{stage})",225                    build_compiler_for_std_to_uplift.stage226                )227            } else {228                format!(229                    "Uplifting library (stage{}:{} -> stage{stage}:{target})",230                    build_compiler_for_std_to_uplift.stage, build_compiler_for_std_to_uplift.host,231                )232            };233234            builder.info(&msg);235236            // Even if we're not building std this stage, the new sysroot must237            // still contain the third party objects needed by various targets.238            self.copy_extra_objects(builder, &build_compiler, target);239240            builder.ensure(StdLink::from_std(self, build_compiler_for_std_to_uplift));241            return stage_1_stamp;242        }243244        target_deps.extend(self.copy_extra_objects(builder, &build_compiler, target));245246        // We build a sysroot for mir-opt tests using the same trick that Miri does: A check build247        // with -Zalways-encode-mir. This frees us from the need to have a target linker, and the248        // fact that this is a check build integrates nicely with run_cargo.249        let mut cargo = if self.is_for_mir_opt_tests {250            trace!("building special sysroot for mir-opt tests");251            let mut cargo = builder::Cargo::new_for_mir_opt_tests(252                builder,253                build_compiler,254                Mode::Std,255                SourceType::InTree,256                target,257                Kind::Check,258            );259            cargo.rustflag("-Zalways-encode-mir");260            cargo.arg("--manifest-path").arg(builder.src.join("library/sysroot/Cargo.toml"));261            cargo262        } else {263            trace!("building regular sysroot");264            let mut cargo = builder::Cargo::new(265                builder,266                build_compiler,267                Mode::Std,268                SourceType::InTree,269                target,270                Kind::Build,271            );272            std_cargo(builder, target, &mut cargo, &self.crates);273            cargo274        };275276        // See src/bootstrap/synthetic_targets.rs277        if target.is_synthetic() {278            cargo.env("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET", "1");279        }280        for rustflag in self.extra_rust_args.iter() {281            cargo.rustflag(rustflag);282        }283284        let _guard = builder.msg(285            Kind::Build,286            format_args!("library artifacts{}", crate_description(&self.crates)),287            Mode::Std,288            build_compiler,289            target,290        );291292        let stamp = build_stamp::libstd_stamp(builder, build_compiler, target);293        run_cargo(294            builder,295            cargo,296            vec![],297            &stamp,298            target_deps,299            if self.is_for_mir_opt_tests {300                ArtifactKeepMode::OnlyRmeta301            } else {302                // We use -Zno-embed-metadata for the standard library303                ArtifactKeepMode::BothRlibAndRmeta304            },305        );306307        builder.ensure(StdLink::from_std(308            self,309            builder.compiler(build_compiler.stage, builder.config.host_target),310        ));311        Some(stamp)312    }313314    fn metadata(&self) -> Option<StepMetadata> {315        Some(StepMetadata::build("std", self.target).built_by(self.build_compiler))316    }317}318319fn copy_and_stamp(320    builder: &Builder<'_>,321    libdir: &Path,322    sourcedir: &Path,323    name: &str,324    target_deps: &mut Vec<(PathBuf, DependencyType)>,325    dependency_type: DependencyType,326) {327    let target = libdir.join(name);328    builder.copy_link(&sourcedir.join(name), &target, FileType::Regular);329330    target_deps.push((target, dependency_type));331}332333fn copy_llvm_libunwind(builder: &Builder<'_>, target: TargetSelection, libdir: &Path) -> PathBuf {334    let libunwind_path = builder.ensure(llvm::Libunwind { target });335    let libunwind_source = libunwind_path.join("libunwind.a");336    let libunwind_target = libdir.join("libunwind.a");337    builder.copy_link(&libunwind_source, &libunwind_target, FileType::NativeLibrary);338    libunwind_target339}340341/// Copies third party objects needed by various targets.342fn copy_third_party_objects(343    builder: &Builder<'_>,344    compiler: &Compiler,345    target: TargetSelection,346) -> Vec<(PathBuf, DependencyType)> {347    let mut target_deps = vec![];348349    if builder.config.needs_sanitizer_runtime_built(target) && compiler.stage != 0 {350        // The sanitizers are only copied in stage1 or above,351        // to avoid creating dependency on LLVM.352        target_deps.extend(353            copy_sanitizers(builder, compiler, target)354                .into_iter()355                .map(|d| (d, DependencyType::Target)),356        );357    }358359    if target == "x86_64-fortanix-unknown-sgx"360        || builder.config.llvm_libunwind(target) == LlvmLibunwind::InTree361            && (target.contains("linux")362                || target.contains("fuchsia")363                || target.contains("aix")364                || target.contains("hexagon"))365    {366        let libunwind_path =367            copy_llvm_libunwind(builder, target, &builder.sysroot_target_libdir(*compiler, target));368        target_deps.push((libunwind_path, DependencyType::Target));369    }370371    target_deps372}373374/// Copies third party objects needed by various targets for self-contained linkage.375fn copy_self_contained_objects(376    builder: &Builder<'_>,377    compiler: &Compiler,378    target: TargetSelection,379) -> Vec<(PathBuf, DependencyType)> {380    let libdir_self_contained =381        builder.sysroot_target_libdir(*compiler, target).join("self-contained");382    t!(fs::create_dir_all(&libdir_self_contained));383    let mut target_deps = vec![];384385    // Copies the libc and CRT objects.386    //387    // rustc historically provides a more self-contained installation for musl targets388    // not requiring the presence of a native musl toolchain. For example, it can fall back389    // to using gcc from a glibc-targeting toolchain for linking.390    // To do that we have to distribute musl startup objects as a part of Rust toolchain391    // and link with them manually in the self-contained mode.392    if target.needs_crt_begin_end() {393        let srcdir = builder.musl_libdir(target).unwrap_or_else(|| {394            panic!("Target {:?} does not have a \"musl-libdir\" key", target.triple)395        });396        if !target.starts_with("wasm32") {397            for &obj in &["libc.a", "crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {398                copy_and_stamp(399                    builder,400                    &libdir_self_contained,401                    &srcdir,402                    obj,403                    &mut target_deps,404                    DependencyType::TargetSelfContained,405                );406            }407            let crt_path = builder.ensure(llvm::CrtBeginEnd { target });408            for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] {409                let src = crt_path.join(obj);410                let target = libdir_self_contained.join(obj);411                builder.copy_link(&src, &target, FileType::NativeLibrary);412                target_deps.push((target, DependencyType::TargetSelfContained));413            }414        } else {415            // For wasm32 targets, we need to copy the libc.a and crt1-command.o files from the416            // musl-libdir, but we don't need the other files.417            for &obj in &["libc.a", "crt1-command.o"] {418                copy_and_stamp(419                    builder,420                    &libdir_self_contained,421                    &srcdir,422                    obj,423                    &mut target_deps,424                    DependencyType::TargetSelfContained,425                );426            }427        }428        if !target.starts_with("s390x") {429            let libunwind_path = copy_llvm_libunwind(builder, target, &libdir_self_contained);430            target_deps.push((libunwind_path, DependencyType::TargetSelfContained));431        }432    } else if target.contains("-wasi") {433        let srcdir = builder.wasi_libdir(target).unwrap_or_else(|| {434            panic!(435                "Target {:?} does not have a \"wasi-root\" key in bootstrap.toml \436                    or `$WASI_SDK_PATH` set",437                target.triple438            )439        });440441        // wasm32-wasip3 doesn't exist in wasi-libc yet, so instead use libs442        // from the wasm32-wasip2 target. Once wasi-libc supports wasip3 this443        // should be deleted and the native objects should be used.444        let srcdir = if target == "wasm32-wasip3" {445            assert!(!srcdir.exists(), "wasip3 support is in wasi-libc, this should be updated now");446            builder.wasi_libdir(TargetSelection::from_user("wasm32-wasip2")).unwrap()447        } else {448            srcdir449        };450        for &obj in &["libc.a", "crt1-command.o", "crt1-reactor.o"] {451            copy_and_stamp(452                builder,453                &libdir_self_contained,454                &srcdir,455                obj,456                &mut target_deps,457                DependencyType::TargetSelfContained,458            );459        }460    } else if target.is_windows_gnu() || target.is_windows_gnullvm() {461        for obj in ["crt2.o", "dllcrt2.o"].iter() {462            let src = compiler_file(builder, &builder.cc(target), target, CLang::C, obj);463            let dst = libdir_self_contained.join(obj);464            builder.copy_link(&src, &dst, FileType::NativeLibrary);465            target_deps.push((dst, DependencyType::TargetSelfContained));466        }467    }468469    target_deps470}471472/// Resolves standard library crates for `Std::run_make` for any build kind (like check, doc,473/// build, clippy, etc.).474pub fn std_crates_for_run_make(run: &RunConfig<'_>) -> Vec<String> {475    let mut crates = run.make_run_crates(builder::Alias::Library);476477    // For no_std targets, we only want to check core and alloc478    // Regardless of core/alloc being selected explicitly or via the "library" default alias,479    // we only want to keep these two crates.480    // The set of no_std crates should be kept in sync with what `Builder::std_cargo` does.481    // Note: an alternative design would be to return an enum from this function (Default vs Subset)482    // of crates. However, several steps currently pass `-p <package>` even if all crates are483    // selected, because Cargo behaves differently in that case. To keep that behavior without484    // making further changes, we pre-filter the no-std crates here.485    let target_is_no_std = run.builder.no_std(run.target).unwrap_or(false);486    if target_is_no_std {487        crates.retain(|c| c == "core" || c == "alloc");488    }489    crates490}491492/// Tries to find LLVM's `compiler-rt` source directory, for building `library/profiler_builtins`.493///494/// Normally it lives in the `src/llvm-project` submodule, but if we will be using a495/// downloaded copy of CI LLVM, then we try to use the `compiler-rt` sources from496/// there instead, which lets us avoid checking out the LLVM submodule.497fn compiler_rt_for_profiler(builder: &Builder<'_>) -> PathBuf {498    // Try to use `compiler-rt` sources from downloaded CI LLVM, if possible.499    if builder.config.llvm_from_ci {500        // CI LLVM might not have been downloaded yet, so try to download it now.501        builder.config.maybe_download_ci_llvm();502        let ci_llvm_compiler_rt = builder.config.ci_llvm_root().join("compiler-rt");503        if ci_llvm_compiler_rt.exists() {504            return ci_llvm_compiler_rt;505        }506    }507508    // Otherwise, fall back to requiring the LLVM submodule.509    builder.require_submodule("src/llvm-project", {510        Some("The `build.profiler` config option requires `compiler-rt` sources from LLVM.")511    });512    builder.src.join("src/llvm-project/compiler-rt")513}514515/// Configure cargo to compile the standard library, adding appropriate env vars516/// and such.517pub fn std_cargo(518    builder: &Builder<'_>,519    target: TargetSelection,520    cargo: &mut Cargo,521    crates: &[String],522) {523    // rustc already ensures that it builds with the minimum deployment524    // target, so ideally we shouldn't need to do anything here.525    //526    // However, `cc` currently defaults to a higher version for backwards527    // compatibility, which means that compiler-rt, which is built via528    // compiler-builtins' build script, gets built with a higher deployment529    // target. This in turn causes warnings while linking, and is generally530    // a compatibility hazard.531    //532    // So, at least until https://github.com/rust-lang/cc-rs/issues/1171, or533    // perhaps https://github.com/rust-lang/cargo/issues/13115 is resolved, we534    // explicitly set the deployment target environment variables to avoid535    // this issue.536    //537    // This place also serves as an extension point if we ever wanted to raise538    // rustc's default deployment target while keeping the prebuilt `std` at539    // a lower version, so it's kinda nice to have in any case.540    if target.contains("apple") && !builder.config.dry_run() {541        // Query rustc for the deployment target, and the associated env var.542        // The env var is one of the standard `*_DEPLOYMENT_TARGET` vars, i.e.543        // `MACOSX_DEPLOYMENT_TARGET`, `IPHONEOS_DEPLOYMENT_TARGET`, etc.544        let mut cmd = builder.rustc_cmd(cargo.compiler());545        cmd.arg("--target").arg(target.rustc_target_arg());546        // FIXME(#152709): -Zunstable-options is to handle JSON targets.547        // Remove when JSON targets are stabilized.548        cmd.arg("-Zunstable-options").env("RUSTC_BOOTSTRAP", "1");549        cmd.arg("--print=deployment-target");550        let output = cmd.run_capture_stdout(builder).stdout();551552        let (env_var, value) = output.split_once('=').unwrap();553        // Unconditionally set the env var (if it was set in the environment554        // already, rustc should've picked that up).555        cargo.env(env_var.trim(), value.trim());556557        // Allow CI to override the deployment target for `std` on macOS.558        //559        // This is useful because we might want the host tooling LLVM, `rustc`560        // and Cargo to have a different deployment target than `std` itself561        // (currently, these two versions are the same, but in the past, we562        // supported macOS 10.7 for user code and macOS 10.8 in host tooling).563        //564        // It is not necessary on the other platforms, since only macOS has565        // support for host tooling.566        if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {567            cargo.env("MACOSX_DEPLOYMENT_TARGET", target);568        }569    }570571    // Paths needed by `library/profiler_builtins/build.rs`.572    if let Some(path) = builder.config.profiler_path(target) {573        cargo.env("LLVM_PROFILER_RT_LIB", path);574    } else if builder.config.profiler_enabled(target) {575        let compiler_rt = compiler_rt_for_profiler(builder);576        // Currently this is separate from the env var used by `compiler_builtins`577        // (below) so that adding support for CI LLVM here doesn't risk breaking578        // the compiler builtins. But they could be unified if desired.579        cargo.env("RUST_COMPILER_RT_FOR_PROFILER", compiler_rt);580    }581582    // Determine if we're going to compile in optimized C intrinsics to583    // the `compiler-builtins` crate. These intrinsics live in LLVM's584    // `compiler-rt` repository.585    //586    // Note that this shouldn't affect the correctness of `compiler-builtins`,587    // but only its speed. Some intrinsics in C haven't been translated to Rust588    // yet but that's pretty rare. Other intrinsics have optimized589    // implementations in C which have only had slower versions ported to Rust,590    // so we favor the C version where we can, but it's not critical.591    //592    // If `compiler-rt` is available ensure that the `c` feature of the593    // `compiler-builtins` crate is enabled and it's configured to learn where594    // `compiler-rt` is located.595    let compiler_builtins_c_feature = match builder.config.optimized_compiler_builtins(target) {596        CompilerBuiltins::LinkLLVMBuiltinsLib(path) => {597            cargo.env("LLVM_COMPILER_RT_LIB", path);598            " compiler-builtins-c"599        }600        CompilerBuiltins::BuildLLVMFuncs => {601            // NOTE: this interacts strangely with `llvm-has-rust-patches`. In that case, we enforce602            // `submodules = false`, so this is a no-op. But, the user could still decide to603            //  manually use an in-tree submodule.604            //605            // NOTE: if we're using system llvm, we'll end up building a version of `compiler-rt`606            // that doesn't match the LLVM we're linking to. That's probably ok? At least, the607            // difference wasn't enforced before. There's a comment in the compiler_builtins build608            // script that makes me nervous, though:609            // https://github.com/rust-lang/compiler-builtins/blob/31ee4544dbe47903ce771270d6e3bea8654e9e50/build.rs#L575-L579610            builder.require_submodule(611                "src/llvm-project",612                Some(613                    "The `build.optimized-compiler-builtins` config option \614                     requires `compiler-rt` sources from LLVM.",615                ),616            );617            let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt");618            if !builder.config.dry_run() {619                // This assertion would otherwise trigger during tests if `llvm-project` is not620                // checked out.621                assert!(compiler_builtins_root.exists());622            }623624            // The path to `compiler-rt` is also used by `profiler_builtins` (above),625            // so if you're changing something here please also change that as appropriate.626            cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root);627            " compiler-builtins-c"628        }629        CompilerBuiltins::BuildRustOnly => "",630    };631632    for krate in crates {633        cargo.args(["-p", krate]);634    }635636    let mut features = String::new();637638    if builder.no_std(target) == Some(true) {639        features += " compiler-builtins-mem";640        if !target.starts_with("bpf") {641            features.push_str(compiler_builtins_c_feature);642        }643644        // for no-std targets we only compile a few no_std crates645        if crates.is_empty() {646            cargo.args(["-p", "alloc"]);647        }648        cargo649            .arg("--manifest-path")650            .arg(builder.src.join("library/alloc/Cargo.toml"))651            .arg("--features")652            .arg(features);653    } else {654        features += &builder.std_features(target);655        features.push_str(compiler_builtins_c_feature);656657        cargo658            .arg("--features")659            .arg(features)660            .arg("--manifest-path")661            .arg(builder.src.join("library/sysroot/Cargo.toml"));662663        // Help the libc crate compile by assisting it in finding various664        // sysroot native libraries.665        if target.contains("musl")666            && let Some(p) = builder.musl_libdir(target)667        {668            let root = format!("native={}", p.to_str().unwrap());669            cargo.rustflag("-L").rustflag(&root);670        }671672        if target.contains("-wasi")673            && let Some(dir) = builder.wasi_libdir(target)674        {675            let root = format!("native={}", dir.to_str().unwrap());676            cargo.rustflag("-L").rustflag(&root);677        }678    }679680    if builder.config.rust_lto == RustcLto::Off {681        cargo.rustflag("-Clto=off");682    }683684    // By default, rustc does not include unwind tables unless they are required685    // for a particular target. They are not required by RISC-V targets, but686    // compiling the standard library with them means that users can get687    // backtraces without having to recompile the standard library themselves.688    //689    // This choice was discussed in https://github.com/rust-lang/rust/pull/69890690    if target.contains("riscv") {691        cargo.rustflag("-Cforce-unwind-tables=yes");692    }693694    let html_root =695        format!("-Zcrate-attr=doc(html_root_url=\"{}/\")", builder.doc_rust_lang_org_channel(),);696    cargo.rustflag(&html_root);697    cargo.rustdocflag(&html_root);698699    cargo.rustdocflag("-Zcrate-attr=warn(rust_2018_idioms)");700}701702/// Link all libstd rlibs/dylibs into a sysroot of `target_compiler`.703///704/// Links those artifacts generated by `compiler` to the `stage` compiler's705/// sysroot for the specified `host` and `target`.706///707/// Note that this assumes that `compiler` has already generated the libstd708/// libraries for `target`, and this method will find them in the relevant709/// output directory.710#[derive(Debug, Clone, PartialEq, Eq, Hash)]711pub struct StdLink {712    pub compiler: Compiler,713    pub target_compiler: Compiler,714    pub target: TargetSelection,715    /// Not actually used; only present to make sure the cache invalidation is correct.716    crates: Vec<String>,717    /// See [`Std::force_recompile`].718    force_recompile: bool,719}720721impl StdLink {722    pub fn from_std(std: Std, host_compiler: Compiler) -> Self {723        Self {724            compiler: host_compiler,725            target_compiler: std.build_compiler,726            target: std.target,727            crates: std.crates,728            force_recompile: std.force_recompile,729        }730    }731}732733impl Step for StdLink {734    type Output = ();735736    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {737        run.never()738    }739740    /// Link all libstd rlibs/dylibs into the sysroot location.741    ///742    /// Links those artifacts generated by `compiler` to the `stage` compiler's743    /// sysroot for the specified `host` and `target`.744    ///745    /// Note that this assumes that `compiler` has already generated the libstd746    /// libraries for `target`, and this method will find them in the relevant747    /// output directory.748    fn run(self, builder: &Builder<'_>) {749        let compiler = self.compiler;750        let target_compiler = self.target_compiler;751        let target = self.target;752753        // NOTE: intentionally does *not* check `target == builder.build` to avoid having to add the same check in `test::Crate`.754        let (libdir, hostdir) = if !self.force_recompile && builder.download_rustc() {755            // NOTE: copies part of `sysroot_libdir` to avoid having to add a new `force_recompile` argument there too756            let lib = builder.sysroot_libdir_relative(self.compiler);757            let sysroot = builder.ensure(crate::core::build_steps::compile::Sysroot {758                compiler: self.compiler,759                force_recompile: self.force_recompile,760            });761            let libdir = sysroot.join(lib).join("rustlib").join(target).join("lib");762            let hostdir = sysroot.join(lib).join("rustlib").join(compiler.host).join("lib");763            (libdir, hostdir)764        } else {765            let libdir = builder.sysroot_target_libdir(target_compiler, target);766            let hostdir = builder.sysroot_target_libdir(target_compiler, compiler.host);767            (libdir, hostdir)768        };769770        let is_downloaded_beta_stage0 = builder771            .build772            .config773            .initial_rustc774            .starts_with(builder.out.join(compiler.host).join("stage0/bin"));775776        // Special case for stage0, to make `rustup toolchain link` and `x dist --stage 0`777        // work for stage0-sysroot. We only do this if the stage0 compiler comes from beta,778        // and is not set to a custom path.779        if compiler.stage == 0 && is_downloaded_beta_stage0 {780            // Copy bin files from stage0/bin to stage0-sysroot/bin781            let sysroot = builder.out.join(compiler.host).join("stage0-sysroot");782783            let host = compiler.host;784            let stage0_bin_dir = builder.out.join(host).join("stage0/bin");785            let sysroot_bin_dir = sysroot.join("bin");786            t!(fs::create_dir_all(&sysroot_bin_dir));787            builder.cp_link_r(&stage0_bin_dir, &sysroot_bin_dir);788789            let stage0_lib_dir = builder.out.join(host).join("stage0/lib");790            t!(fs::create_dir_all(sysroot.join("lib")));791            builder.cp_link_r(&stage0_lib_dir, &sysroot.join("lib"));792793            // Copy codegen-backends from stage0794            let sysroot_codegen_backends = builder.sysroot_codegen_backends(compiler);795            t!(fs::create_dir_all(&sysroot_codegen_backends));796            let stage0_codegen_backends = builder797                .out798                .join(host)799                .join("stage0/lib/rustlib")800                .join(host)801                .join("codegen-backends");802            if stage0_codegen_backends.exists() {803                builder.cp_link_r(&stage0_codegen_backends, &sysroot_codegen_backends);804            }805        } else if compiler.stage == 0 {806            let sysroot = builder.out.join(compiler.host.triple).join("stage0-sysroot");807808            if builder.local_rebuild {809                // On local rebuilds this path might be a symlink to the project root,810                // which can be read-only (e.g., on CI). So remove it before copying811                // the stage0 lib.812                let _ = fs::remove_dir_all(sysroot.join("lib/rustlib/src/rust"));813            }814815            builder.cp_link_r(&builder.initial_sysroot.join("lib"), &sysroot.join("lib"));816        } else {817            if builder.download_rustc() {818                // Ensure there are no CI-rustc std artifacts.819                let _ = fs::remove_dir_all(&libdir);820                let _ = fs::remove_dir_all(&hostdir);821            }822823            add_to_sysroot(824                builder,825                &libdir,826                &hostdir,827                &build_stamp::libstd_stamp(builder, compiler, target),828            );829        }830    }831}832833/// Copies sanitizer runtime libraries into target libdir.834fn copy_sanitizers(835    builder: &Builder<'_>,836    compiler: &Compiler,837    target: TargetSelection,838) -> Vec<PathBuf> {839    let runtimes: Vec<llvm::SanitizerRuntime> = builder.ensure(llvm::Sanitizers { target });840841    if builder.config.dry_run() {842        return Vec::new();843    }844845    let mut target_deps = Vec::new();846    let libdir = builder.sysroot_target_libdir(*compiler, target);847848    for runtime in &runtimes {849        let dst = libdir.join(&runtime.name);850        builder.copy_link(&runtime.path, &dst, FileType::NativeLibrary);851852        // The `aarch64-apple-ios-macabi` and `x86_64-apple-ios-macabi` are also supported for853        // sanitizers, but they share a sanitizer runtime with `${arch}-apple-darwin`, so we do854        // not list them here to rename and sign the runtime library.855        if target == "x86_64-apple-darwin"856            || target == "aarch64-apple-darwin"857            || target == "aarch64-apple-ios"858            || target == "aarch64-apple-ios-sim"859            || target == "x86_64-apple-ios"860        {861            // Update the library’s install name to reflect that it has been renamed.862            apple_darwin_update_library_name(builder, &dst, &format!("@rpath/{}", runtime.name));863            // Upon renaming the install name, the code signature of the file will invalidate,864            // so we will sign it again.865            apple_darwin_sign_file(builder, &dst);866        }867868        target_deps.push(dst);869    }870871    target_deps872}873874fn apple_darwin_update_library_name(builder: &Builder<'_>, library_path: &Path, new_name: &str) {875    command("install_name_tool").arg("-id").arg(new_name).arg(library_path).run(builder);876}877878fn apple_darwin_sign_file(builder: &Builder<'_>, file_path: &Path) {879    command("codesign")880        .arg("-f") // Force to rewrite the existing signature881        .arg("-s")882        .arg("-")883        .arg(file_path)884        .run(builder);885}886887#[derive(Debug, Clone, PartialEq, Eq, Hash)]888pub struct StartupObjects {889    pub compiler: Compiler,890    pub target: TargetSelection,891}892893impl Step for StartupObjects {894    type Output = Vec<(PathBuf, DependencyType)>;895896    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {897        run.path("library/rtstartup")898    }899900    fn make_run(run: RunConfig<'_>) {901        run.builder.ensure(StartupObjects {902            compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),903            target: run.target,904        });905    }906907    /// Builds and prepare startup objects like rsbegin.o and rsend.o908    ///909    /// These are primarily used on Windows right now for linking executables/dlls.910    /// They don't require any library support as they're just plain old object911    /// files, so we just use the nightly snapshot compiler to always build them (as912    /// no other compilers are guaranteed to be available).913    fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> {914        let for_compiler = self.compiler;915        let target = self.target;916        // Even though no longer necessary on x86_64, they are kept for now to917        // avoid potential issues in downstream crates.918        if !target.is_windows_gnu() {919            return vec![];920        }921922        let mut target_deps = vec![];923924        let src_dir = &builder.src.join("library").join("rtstartup");925        let dst_dir = &builder.native_dir(target).join("rtstartup");926        let sysroot_dir = &builder.sysroot_target_libdir(for_compiler, target);927        t!(fs::create_dir_all(dst_dir));928929        for file in &["rsbegin", "rsend"] {930            let src_file = &src_dir.join(file.to_string() + ".rs");931            let dst_file = &dst_dir.join(file.to_string() + ".o");932            if !up_to_date(src_file, dst_file) {933                let mut cmd = command(&builder.initial_rustc);934                cmd.env("RUSTC_BOOTSTRAP", "1");935                if !builder.local_rebuild {936                    // a local_rebuild compiler already has stage1 features937                    cmd.arg("--cfg").arg("bootstrap");938                }939                cmd.arg("--target")940                    .arg(target.rustc_target_arg())941                    .arg("--emit=obj")942                    .arg("-o")943                    .arg(dst_file)944                    .arg(src_file)945                    .run(builder);946            }947948            let obj = sysroot_dir.join((*file).to_string() + ".o");949            builder.copy_link(dst_file, &obj, FileType::NativeLibrary);950            target_deps.push((obj, DependencyType::Target));951        }952953        target_deps954    }955}956957fn cp_rustc_component_to_ci_sysroot(builder: &Builder<'_>, sysroot: &Path, contents: Vec<String>) {958    let ci_rustc_dir = builder.config.ci_rustc_dir();959960    for file in contents {961        let src = ci_rustc_dir.join(&file);962        let dst = sysroot.join(file);963        if src.is_dir() {964            t!(fs::create_dir_all(dst));965        } else {966            builder.copy_link(&src, &dst, FileType::Regular);967        }968    }969}970971/// Represents information about a built rustc.972#[derive(Clone, Debug)]973pub struct BuiltRustc {974    /// The compiler that actually built this *rustc*.975    /// This can be different from the *build_compiler* passed to the `Rustc` step because of976    /// uplifting.977    pub build_compiler: Compiler,978}979980/// Build rustc using the passed `build_compiler`.981///982/// - Makes sure that `build_compiler` has a standard library prepared for its host target,983///   so that it can compile build scripts and proc macros when building this `rustc`.984/// - Makes sure that `build_compiler` has a standard library prepared for `target`,985///   so that the built `rustc` can *link to it* and use it at runtime.986#[derive(Debug, Clone, PartialEq, Eq, Hash)]987pub struct Rustc {988    /// The target on which rustc will run (its host).989    pub target: TargetSelection,990    /// The **previous** compiler used to compile this rustc.991    pub build_compiler: Compiler,992    /// Whether to build a subset of crates, rather than the whole compiler.993    ///994    /// This should only be requested by the user, not used within bootstrap itself.995    /// Using it within bootstrap can lead to confusing situation where lints are replayed996    /// in two different steps.997    crates: Vec<String>,998}9991000impl Rustc {1001    pub fn new(build_compiler: Compiler, target: TargetSelection) -> Self {1002        Self { target, build_compiler, crates: Default::default() }1003    }1004}10051006impl Step for Rustc {1007    type Output = BuiltRustc;1008    const IS_HOST: bool = true;10091010    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1011        let mut crates = run.builder.in_tree_crates("rustc-main", None);1012        for (i, krate) in crates.iter().enumerate() {1013            // We can't allow `build rustc` as an alias for this Step, because that's reserved by `Assemble`.1014            // Ideally Assemble would use `build compiler` instead, but that seems too confusing to be worth the breaking change.1015            if krate.name == "rustc-main" {1016                crates.swap_remove(i);1017                break;1018            }1019        }1020        run.crates(crates)1021    }10221023    fn is_default_step(_builder: &Builder<'_>) -> bool {1024        false1025    }10261027    fn make_run(run: RunConfig<'_>) {1028        // If only `compiler` was passed, do not run this step.1029        // Instead the `Assemble` step will take care of compiling Rustc.1030        if run.builder.paths == vec![PathBuf::from("compiler")] {1031            return;1032        }10331034        let crates = run.cargo_crates_in_set();1035        run.builder.ensure(Rustc {1036            build_compiler: run1037                .builder1038                .compiler(run.builder.top_stage.saturating_sub(1), run.build_triple()),1039            target: run.target,1040            crates,1041        });1042    }10431044    /// Builds the compiler.1045    ///1046    /// This will build the compiler for a particular stage of the build using1047    /// the `build_compiler` targeting the `target` architecture. The artifacts1048    /// created will also be linked into the sysroot directory.1049    fn run(self, builder: &Builder<'_>) -> Self::Output {1050        let build_compiler = self.build_compiler;1051        let target = self.target;10521053        // NOTE: the ABI of the stage0 compiler is different from the ABI of the downloaded compiler,1054        // so its artifacts can't be reused.1055        if builder.download_rustc() && build_compiler.stage != 0 {1056            trace!(stage = build_compiler.stage, "`download_rustc` requested");10571058            let sysroot =1059                builder.ensure(Sysroot { compiler: build_compiler, force_recompile: false });1060            cp_rustc_component_to_ci_sysroot(1061                builder,1062                &sysroot,1063                builder.config.ci_rustc_dev_contents(),1064            );1065            return BuiltRustc { build_compiler };1066        }10671068        // Build a standard library for `target` using the `build_compiler`.1069        // This will be the standard library that the rustc which we build *links to*.1070        builder.std(build_compiler, target);10711072        if builder.config.keep_stage.contains(&build_compiler.stage) {1073            trace!(stage = build_compiler.stage, "`keep-stage` requested");10741075            builder.info("WARNING: Using a potentially old librustc. This may not behave well.");1076            builder.info("WARNING: Use `--keep-stage-std` if you want to rebuild the compiler when it changes");1077            builder.ensure(RustcLink::from_rustc(self));10781079            return BuiltRustc { build_compiler };1080        }10811082        // The stage of the compiler that we're building1083        let stage = build_compiler.stage + 1;10841085        // If we are building a stage3+ compiler, and full bootstrap is disabled, and we have a1086        // previous rustc available, we will uplift a compiler from a previous stage.1087        // We do not allow cross-compilation uplifting here, because there it can be quite tricky1088        // to figure out which stage actually built the rustc that should be uplifted.1089        if build_compiler.stage >= 21090            && !builder.config.full_bootstrap1091            && target == builder.host_target1092        {1093            // Here we need to determine the **build compiler** that built the stage that we will1094            // be uplifting. We cannot uplift stage 1, as it has a different ABI than stage 2+,1095            // so we always uplift the stage2 compiler (compiled with stage 1).1096            let uplift_build_compiler = builder.compiler(1, build_compiler.host);10971098            let msg = format!("Uplifting rustc from stage2 to stage{stage})");1099            builder.info(&msg);11001101            // Here the compiler that built the rlibs (`uplift_build_compiler`) can be different1102            // from the compiler whose sysroot should be modified in this step. So we need to copy1103            // the (previously built) rlibs into the correct sysroot.1104            builder.ensure(RustcLink::from_build_compiler_and_sysroot(1105                // This is the compiler that actually built the rustc rlibs1106                uplift_build_compiler,1107                // We copy the rlibs into the sysroot of `build_compiler`1108                build_compiler,1109                target,1110                self.crates,1111            ));11121113            // Here we have performed an uplift, so we return the actual build compiler that "built"1114            // this rustc.1115            return BuiltRustc { build_compiler: uplift_build_compiler };1116        }11171118        // Build a standard library for the current host target using the `build_compiler`.1119        // This standard library will be used when building `rustc` for compiling1120        // build scripts and proc macros.1121        // If we are not cross-compiling, the Std build above will be the same one as the one we1122        // prepare here.1123        builder.std(1124            builder.compiler(self.build_compiler.stage, builder.config.host_target),1125            builder.config.host_target,1126        );11271128        let mut cargo = builder::Cargo::new(1129            builder,1130            build_compiler,1131            Mode::Rustc,1132            SourceType::InTree,1133            target,1134            Kind::Build,1135        );11361137        rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);11381139        // NB: all RUSTFLAGS should be added to `rustc_cargo()` so they will be1140        // consistently applied by check/doc/test modes too.11411142        for krate in &*self.crates {1143            cargo.arg("-p").arg(krate);1144        }11451146        if builder.build.config.enable_bolt_settings && build_compiler.stage == 1 {1147            // Relocations are required for BOLT to work.1148            cargo.env("RUSTC_BOLT_LINK_FLAGS", "1");1149        }11501151        let _guard = builder.msg(1152            Kind::Build,1153            format_args!("compiler artifacts{}", crate_description(&self.crates)),1154            Mode::Rustc,1155            build_compiler,1156            target,1157        );1158        let stamp = build_stamp::librustc_stamp(builder, build_compiler, target);11591160        run_cargo(1161            builder,1162            cargo,1163            vec![],1164            &stamp,1165            vec![],1166            ArtifactKeepMode::Custom(Box::new(|filename| {1167                if filename.contains("jemalloc_sys")1168                    || filename.contains("rustc_public_bridge")1169                    || filename.contains("rustc_public")1170                {1171                    // jemalloc_sys and rustc_public_bridge are not linked into librustc_driver.so,1172                    // so we need to distribute them as rlib to be able to use them.1173                    filename.ends_with(".rlib")1174                } else {1175                    // Distribute the rest of the rustc crates as rmeta files only to reduce1176                    // the tarball sizes by about 50%. The object files are linked into1177                    // librustc_driver.so, so it is still possible to link against them.1178                    filename.ends_with(".rmeta")1179                }1180            })),1181        );11821183        let target_root_dir = stamp.path().parent().unwrap();1184        // When building `librustc_driver.so` (like `libLLVM.so`) on linux, it can contain1185        // unexpected debuginfo from dependencies, for example from the C++ standard library used in1186        // our LLVM wrapper. Unless we're explicitly requesting `librustc_driver` to be built with1187        // debuginfo (via the debuginfo level of the executables using it): strip this debuginfo1188        // away after the fact.1189        if builder.config.rust_debuginfo_level_rustc == DebuginfoLevel::None1190            && builder.config.rust_debuginfo_level_tools == DebuginfoLevel::None1191        {1192            let rustc_driver = target_root_dir.join("librustc_driver.so");1193            strip_debug(builder, target, &rustc_driver);1194        }11951196        if builder.config.rust_debuginfo_level_rustc == DebuginfoLevel::None {1197            // Due to LTO a lot of debug info from C++ dependencies such as jemalloc can make it into1198            // our final binaries1199            strip_debug(builder, target, &target_root_dir.join("rustc-main"));1200        }12011202        builder.ensure(RustcLink::from_rustc(self));1203        BuiltRustc { build_compiler }1204    }12051206    fn metadata(&self) -> Option<StepMetadata> {1207        Some(StepMetadata::build("rustc", self.target).built_by(self.build_compiler))1208    }1209}12101211pub fn rustc_cargo(1212    builder: &Builder<'_>,1213    cargo: &mut Cargo,1214    target: TargetSelection,1215    build_compiler: &Compiler,1216    crates: &[String],1217) {1218    cargo1219        .arg("--features")1220        .arg(builder.rustc_features(builder.kind, target, crates))1221        .arg("--manifest-path")1222        .arg(builder.src.join("compiler/rustc/Cargo.toml"));12231224    cargo.rustdocflag("-Zcrate-attr=warn(rust_2018_idioms)");12251226    // If the rustc output is piped to e.g. `head -n1` we want the process to be killed, rather than1227    // having an error bubble up and cause a panic.1228    //1229    // FIXME(jieyouxu): this flag is load-bearing for rustc to not ICE on broken pipes, because1230    // rustc internally sometimes uses std `println!` -- but std `println!` by default will panic on1231    // broken pipes, and uncaught panics will manifest as an ICE. The compiler *should* handle this1232    // properly, but this flag is set in the meantime to paper over the I/O errors.1233    //1234    // See <https://github.com/rust-lang/rust/issues/131059> for details.1235    //1236    // Also see the discussion for properly handling I/O errors related to broken pipes, i.e. safe1237    // variants of `println!` in1238    // <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Internal.20lint.20for.20raw.20.60print!.60.20and.20.60println!.60.3F>.1239    cargo.rustflag("-Zon-broken-pipe=kill");12401241    // Building with protected visibility reduces the number of dynamic relocations needed, giving1242    // us a faster startup time. However GNU ld < 2.40 will error if we try to link a shared object1243    // with direct references to protected symbols, so for now we only use protected symbols if1244    // linking with LLD is enabled.1245    if builder.build.config.bootstrap_override_lld.is_used() {1246        cargo.rustflag("-Zdefault-visibility=protected");1247    }12481249    if is_lto_stage(build_compiler) {1250        match builder.config.rust_lto {1251            RustcLto::Thin | RustcLto::Fat => {1252                // Since using LTO for optimizing dylibs is currently experimental,1253                // we need to pass -Zdylib-lto.1254                cargo.rustflag("-Zdylib-lto");1255                // Cargo by default passes `-Cembed-bitcode=no` and doesn't pass `-Clto` when1256                // compiling dylibs (and their dependencies), even when LTO is enabled for the1257                // crate. Therefore, we need to override `-Clto` and `-Cembed-bitcode` here.1258                let lto_type = match builder.config.rust_lto {1259                    RustcLto::Thin => "thin",1260                    RustcLto::Fat => "fat",1261                    _ => unreachable!(),1262                };1263                cargo.rustflag(&format!("-Clto={lto_type}"));1264                cargo.rustflag("-Cembed-bitcode=yes");1265            }1266            RustcLto::ThinLocal => { /* Do nothing, this is the default */ }1267            RustcLto::Off => {1268                cargo.rustflag("-Clto=off");1269            }1270        }1271    } else if builder.config.rust_lto == RustcLto::Off {1272        cargo.rustflag("-Clto=off");1273    }12741275    // With LLD, we can use ICF (identical code folding) to reduce the executable size1276    // of librustc_driver/rustc and to improve i-cache utilization.1277    //1278    // -Wl,[link options] doesn't work on MSVC. However, /OPT:ICF (technically /OPT:REF,ICF)1279    // is already on by default in MSVC optimized builds, which is interpreted as --icf=all:1280    // https://github.com/llvm/llvm-project/blob/3329cec2f79185bafd678f310fafadba2a8c76d2/lld/COFF/Driver.cpp#L17461281    // https://github.com/rust-lang/rust/blob/f22819bcce4abaff7d1246a56eec493418f9f4ee/compiler/rustc_codegen_ssa/src/back/linker.rs#L8271282    if builder.config.bootstrap_override_lld.is_used() && !build_compiler.host.is_msvc() {1283        cargo.rustflag("-Clink-args=-Wl,--icf=all");1284    }12851286    if builder.config.rust_profile_use.is_some() && builder.config.rust_profile_generate.is_some() {1287        panic!("Cannot use and generate PGO profiles at the same time");1288    }1289    let is_collecting = if let Some(path) = &builder.config.rust_profile_generate {1290        if build_compiler.stage == 1 {1291            cargo.rustflag(&format!("-Cprofile-generate={path}"));1292            // Apparently necessary to avoid overflowing the counters during1293            // a Cargo build profile1294            cargo.rustflag("-Cllvm-args=-vp-counters-per-site=4");1295            true1296        } else {1297            false1298        }1299    } else if let Some(path) = &builder.config.rust_profile_use {1300        if build_compiler.stage == 1 {1301            cargo.rustflag(&format!("-Cprofile-use={path}"));1302            if builder.is_verbose() {1303                cargo.rustflag("-Cllvm-args=-pgo-warn-missing-function");1304            }1305            true1306        } else {1307            false1308        }1309    } else {1310        false1311    };1312    if is_collecting {1313        // Ensure paths to Rust sources are relative, not absolute.1314        cargo.rustflag(&format!(1315            "-Cllvm-args=-static-func-strip-dirname-prefix={}",1316            builder.config.src.components().count()1317        ));1318    }13191320    // The stage0 compiler changes infrequently and does not directly depend on code1321    // in the current working directory. Therefore, caching it with sccache should be1322    // useful.1323    // This is only performed for non-incremental builds, as ccache cannot deal with these.1324    if let Some(ref ccache) = builder.config.ccache1325        && build_compiler.stage == 01326        && !builder.config.incremental1327    {1328        cargo.env("RUSTC_WRAPPER", ccache);1329    }13301331    rustc_cargo_env(builder, cargo, target);1332}13331334pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) {1335    // Set some configuration variables picked up by build scripts and1336    // the compiler alike1337    cargo1338        .env("CFG_RELEASE", builder.rust_release())1339        .env("CFG_RELEASE_CHANNEL", &builder.config.channel)1340        .env("CFG_VERSION", builder.rust_version());13411342    // Some tools like Cargo detect their own git information in build scripts. When omit-git-hash1343    // is enabled in bootstrap.toml, we pass this environment variable to tell build scripts to avoid1344    // detecting git information on their own.1345    if builder.config.omit_git_hash {1346        cargo.env("CFG_OMIT_GIT_HASH", "1");1347    }13481349    cargo.env("CFG_DEFAULT_CODEGEN_BACKEND", builder.config.default_codegen_backend(target).name());13501351    let libdir_relative = builder.config.libdir_relative().unwrap_or_else(|| Path::new("lib"));1352    let target_config = builder.config.target_config.get(&target);13531354    cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);13551356    if let Some(ref ver_date) = builder.rust_info().commit_date() {1357        cargo.env("CFG_VER_DATE", ver_date);1358    }1359    if let Some(ref ver_hash) = builder.rust_info().sha() {1360        cargo.env("CFG_VER_HASH", ver_hash);1361    }1362    if !builder.unstable_features() {1363        cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1");1364    }13651366    // Prefer the current target's own default_linker, else a globally1367    // specified one.1368    if let Some(s) = target_config.and_then(|c| c.default_linker.as_ref()) {1369        cargo.env("CFG_DEFAULT_LINKER", s);1370    } else if let Some(ref s) = builder.config.rustc_default_linker {1371        cargo.env("CFG_DEFAULT_LINKER", s);1372    }13731374    // Enable rustc's env var to use a linker override on Linux when requested.1375    if let Some(linker) = target_config.map(|c| c.default_linker_linux_override) {1376        match linker {1377            DefaultLinuxLinkerOverride::Off => {}1378            DefaultLinuxLinkerOverride::SelfContainedLldCc => {1379                cargo.env("CFG_DEFAULT_LINKER_SELF_CONTAINED_LLD_CC", "1");1380            }1381        }1382    }13831384    // The host this new compiler will *run* on.1385    cargo.env("CFG_COMPILER_HOST_TRIPLE", target.triple);13861387    if builder.config.rust_verify_llvm_ir {1388        cargo.env("RUSTC_VERIFY_LLVM_IR", "1");1389    }13901391    // These conditionals represent a tension between three forces:1392    // - For non-check builds, we need to define some LLVM-related environment1393    //   variables, requiring LLVM to have been built.1394    // - For check builds, we want to avoid building LLVM if possible.1395    // - Check builds and non-check builds should have the same environment if1396    //   possible, to avoid unnecessary rebuilds due to cache-busting.1397    //1398    // Therefore we try to avoid building LLVM for check builds, but only if1399    // building LLVM would be expensive. If "building" LLVM is cheap1400    // (i.e. it's already built or is downloadable), we prefer to maintain a1401    // consistent environment between check and non-check builds.1402    if builder.config.llvm_enabled(target) {1403        let building_llvm_is_expensive =1404            crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target, false)1405                .should_build();14061407        let skip_llvm = (builder.kind == Kind::Check) && building_llvm_is_expensive;1408        if !skip_llvm {1409            rustc_llvm_env(builder, cargo, target)1410        }1411    }14121413    // See also the "JEMALLOC_SYS_WITH_LG_PAGE" setting in the tool build step.1414    if builder.config.jemalloc(target) && env::var_os("JEMALLOC_SYS_WITH_LG_PAGE").is_none() {1415        // Build jemalloc on AArch64 with support for page sizes up to 64K1416        // See: https://github.com/rust-lang/rust/pull/1350811417        if target.starts_with("aarch64") {1418            cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "16");1419        }1420        // Build jemalloc on LoongArch with support for page sizes up to 16K1421        else if target.starts_with("loongarch") {1422            cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "14");1423        }1424    }1425}14261427/// Pass down configuration from the LLVM build into the build of1428/// rustc_llvm and rustc_codegen_llvm.1429///1430/// Note that this has the side-effect of _building LLVM_, which is sometimes1431/// unwanted (e.g. for check builds).1432fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) {1433    if builder.config.is_rust_llvm(target) {1434        cargo.env("LLVM_RUSTLLVM", "1");1435    }1436    if builder.config.llvm_enzyme {1437        cargo.env("LLVM_ENZYME", "1");1438    }1439    let llvm::LlvmResult { host_llvm_config, .. } = builder.ensure(llvm::Llvm { target });1440    if builder.config.llvm_offload {1441        builder.ensure(llvm::OmpOffload { target });1442        cargo.env("LLVM_OFFLOAD", "1");1443    }14441445    cargo.env("LLVM_CONFIG", &host_llvm_config);14461447    // Some LLVM linker flags (-L and -l) may be needed to link `rustc_llvm`. Its build script1448    // expects these to be passed via the `LLVM_LINKER_FLAGS` env variable, separated by1449    // whitespace.1450    //1451    // For example:1452    // - on windows, when `clang-cl` is used with instrumentation, we need to manually add1453    // clang's runtime library resource directory so that the profiler runtime library can be1454    // found. This is to avoid the linker errors about undefined references to1455    // `__llvm_profile_instrument_memop` when linking `rustc_driver`.1456    let mut llvm_linker_flags = String::new();1457    if builder.config.llvm_profile_generate1458        && target.is_msvc()1459        && let Some(ref clang_cl_path) = builder.config.llvm_clang_cl1460    {1461        // Add clang's runtime library directory to the search path1462        let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path);1463        llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display()));1464    }14651466    // The config can also specify its own llvm linker flags.1467    if let Some(ref s) = builder.config.llvm_ldflags {1468        if !llvm_linker_flags.is_empty() {1469            llvm_linker_flags.push(' ');1470        }1471        llvm_linker_flags.push_str(s);1472    }14731474    // Set the linker flags via the env var that `rustc_llvm`'s build script will read.1475    if !llvm_linker_flags.is_empty() {1476        cargo.env("LLVM_LINKER_FLAGS", llvm_linker_flags);1477    }14781479    // Building with a static libstdc++ is only supported on Linux and windows-gnu* right now,1480    // not for MSVC or macOS1481    if builder.config.llvm_static_stdcpp1482        && !target.contains("freebsd")1483        && !target.is_msvc()1484        && !target.contains("apple")1485        && !target.contains("solaris")1486    {1487        let libstdcxx_name =1488            if target.contains("windows-gnullvm") { "libc++.a" } else { "libstdc++.a" };1489        let file = compiler_file(1490            builder,1491            &builder.cxx(target).unwrap(),1492            target,1493            CLang::Cxx,1494            libstdcxx_name,1495        );1496        cargo.env("LLVM_STATIC_STDCPP", file);1497    }1498    if builder.llvm_link_shared() {1499        cargo.env("LLVM_LINK_SHARED", "1");1500    }1501    if builder.config.llvm_use_libcxx {1502        cargo.env("LLVM_USE_LIBCXX", "1");1503    }1504    if builder.config.llvm_assertions {1505        cargo.env("LLVM_ASSERTIONS", "1");1506    }1507}15081509/// `RustcLink` copies compiler rlibs from a rustc build into a compiler sysroot.1510/// It works with (potentially up to) three compilers:1511/// - `build_compiler` is a compiler that built rustc rlibs1512/// - `sysroot_compiler` is a compiler into whose sysroot we will copy the rlibs1513///   - In most situations, `build_compiler` == `sysroot_compiler`1514/// - `target_compiler` is the compiler whose rlibs were built. It is not represented explicitly1515///   in this step, rather we just read the rlibs from a rustc build stamp of `build_compiler`.1516///1517/// This is necessary for tools using `rustc_private`, where the previous compiler will build1518/// a tool against the next compiler.1519/// To build a tool against a compiler, the rlibs of that compiler that it links against1520/// must be in the sysroot of the compiler that's doing the compiling.1521#[derive(Debug, Clone, PartialEq, Eq, Hash)]1522struct RustcLink {1523    /// This compiler **built** some rustc, whose rlibs we will copy into a sysroot.1524    build_compiler: Compiler,1525    /// This is the compiler into whose sysroot we want to copy the built rlibs.1526    /// In most cases, it will correspond to `build_compiler`.1527    sysroot_compiler: Compiler,1528    target: TargetSelection,1529    /// Not actually used; only present to make sure the cache invalidation is correct.1530    crates: Vec<String>,1531}15321533impl RustcLink {1534    /// Copy rlibs from the build compiler that build this `rustc` into the sysroot of that1535    /// build compiler.1536    fn from_rustc(rustc: Rustc) -> Self {1537        Self {1538            build_compiler: rustc.build_compiler,1539            sysroot_compiler: rustc.build_compiler,1540            target: rustc.target,1541            crates: rustc.crates,1542        }1543    }15441545    /// Copy rlibs **built** by `build_compiler` into the sysroot of `sysroot_compiler`.1546    fn from_build_compiler_and_sysroot(1547        build_compiler: Compiler,1548        sysroot_compiler: Compiler,1549        target: TargetSelection,1550        crates: Vec<String>,1551    ) -> Self {1552        Self { build_compiler, sysroot_compiler, target, crates }1553    }1554}15551556impl Step for RustcLink {1557    type Output = ();15581559    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1560        run.never()1561    }15621563    /// Same as `StdLink`, only for librustc1564    fn run(self, builder: &Builder<'_>) {1565        let build_compiler = self.build_compiler;1566        let sysroot_compiler = self.sysroot_compiler;1567        let target = self.target;1568        add_to_sysroot(1569            builder,1570            &builder.sysroot_target_libdir(sysroot_compiler, target),1571            &builder.sysroot_target_libdir(sysroot_compiler, sysroot_compiler.host),1572            &build_stamp::librustc_stamp(builder, build_compiler, target),1573        );1574    }1575}15761577/// Set of `libgccjit` dylibs that can be used by `cg_gcc` to compile code for a set of targets.1578/// `libgccjit` requires a separate build for each `(host, target)` pair.1579/// So if you are on linux-x64 and build for linux-aarch64, you will need at least:1580/// - linux-x64 -> linux-x64 libgccjit (for building host code like proc macros)1581/// - linux-x64 -> linux-aarch64 libgccjit (for the aarch64 target code)1582#[derive(Clone)]1583pub struct GccDylibSet {1584    dylibs: BTreeMap<GccTargetPair, GccOutput>,1585}15861587impl GccDylibSet {1588    /// Build a set of libgccjit dylibs that will be executed on `host` and will generate code for1589    /// each specified target.1590    pub fn build(1591        builder: &Builder<'_>,1592        host: TargetSelection,1593        targets: Vec<TargetSelection>,1594    ) -> Self {1595        let dylibs = targets1596            .iter()1597            .map(|t| GccTargetPair::for_target_pair(host, *t))1598            .map(|target_pair| (target_pair, builder.ensure(Gcc { target_pair })))1599            .collect();1600        Self { dylibs }1601    }16021603    /// Install the libgccjit dylibs to the corresponding target directories of the given compiler.1604    /// cg_gcc know how to search for the libgccjit dylibs in these directories, according to the1605    /// (host, target) pair that is being compiled by rustc and cg_gcc.1606    pub fn install_to(&self, builder: &Builder<'_>, compiler: Compiler) {1607        if builder.config.dry_run() {1608            return;1609        }16101611        // <rustc>/lib/<host-target>/codegen-backends1612        let cg_sysroot = builder.sysroot_codegen_backends(compiler);16131614        for (target_pair, libgccjit) in &self.dylibs {1615            assert_eq!(1616                target_pair.host(),1617                compiler.host,1618                "Trying to install libgccjit ({target_pair}) to a compiler with a different host ({})",1619                compiler.host1620            );1621            let libgccjit_path = libgccjit.libgccjit();16221623            // If we build libgccjit ourselves, then `libgccjit` can actually be a symlink.1624            // In that case, we have to resolve it first, otherwise we'd create a symlink to a1625            // symlink, which wouldn't work.1626            let libgccjit_path = t!(1627                libgccjit_path.canonicalize(),1628                format!("Cannot find libgccjit at {}", libgccjit_path.display())1629            );16301631            let dst = cg_sysroot.join(libgccjit_path_relative_to_cg_dir(target_pair, libgccjit));1632            t!(std::fs::create_dir_all(dst.parent().unwrap()));1633            builder.copy_link(&libgccjit_path, &dst, FileType::NativeLibrary);1634        }1635    }1636}16371638/// Returns a path where libgccjit.so should be stored, **relative** to the1639/// **codegen backend directory**.1640pub fn libgccjit_path_relative_to_cg_dir(1641    target_pair: &GccTargetPair,1642    libgccjit: &GccOutput,1643) -> PathBuf {1644    let target_filename = libgccjit.libgccjit().file_name().unwrap().to_str().unwrap();16451646    // <cg-dir>/lib/<target>/libgccjit.so1647    Path::new("lib").join(target_pair.target()).join(target_filename)1648}16491650/// Output of the `compile::GccCodegenBackend` step.1651///1652/// It contains a build stamp with the path to the built cg_gcc dylib.1653#[derive(Clone)]1654pub struct GccCodegenBackendOutput {1655    stamp: BuildStamp,1656}16571658impl GccCodegenBackendOutput {1659    pub fn stamp(&self) -> &BuildStamp {1660        &self.stamp1661    }1662}16631664/// Builds the GCC codegen backend (`cg_gcc`).1665/// Note that this **does not** build libgccjit, which is a dependency of cg_gcc.1666/// That has to be built separately, because a separate copy of libgccjit is required1667/// for each (host, target) compilation pair.1668/// cg_gcc goes to great lengths to ensure that it does not *directly* link to libgccjit,1669/// so we respect that here and allow building cg_gcc without building libgccjit itself.1670#[derive(Debug, Clone, PartialEq, Eq, Hash)]1671pub struct GccCodegenBackend {1672    compilers: RustcPrivateCompilers,1673    target: TargetSelection,1674}16751676impl GccCodegenBackend {1677    /// Build `cg_gcc` that will run on the given host target.1678    pub fn for_target(compilers: RustcPrivateCompilers, target: TargetSelection) -> Self {1679        Self { compilers, target }1680    }1681}16821683impl Step for GccCodegenBackend {1684    type Output = GccCodegenBackendOutput;16851686    const IS_HOST: bool = true;16871688    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1689        run.alias("rustc_codegen_gcc").alias("cg_gcc")1690    }16911692    fn make_run(run: RunConfig<'_>) {1693        let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target);1694        run.builder.ensure(GccCodegenBackend::for_target(compilers, run.target));1695    }16961697    fn run(self, builder: &Builder<'_>) -> Self::Output {1698        let host = self.compilers.target();1699        let build_compiler = self.compilers.build_compiler();17001701        let stamp = build_stamp::codegen_backend_stamp(1702            builder,1703            build_compiler,1704            host,1705            &CodegenBackendKind::Gcc,1706        );17071708        if builder.config.keep_stage.contains(&build_compiler.stage) && stamp.path().exists() {1709            trace!("`keep-stage` requested");1710            builder.info(1711                "WARNING: Using a potentially old codegen backend. \1712                This may not behave well.",1713            );1714            // Codegen backends are linked separately from this step today, so we don't do1715            // anything here.1716            return GccCodegenBackendOutput { stamp };1717        }17181719        let mut cargo = builder::Cargo::new(1720            builder,1721            build_compiler,1722            Mode::Codegen,1723            SourceType::InTree,1724            host,1725            Kind::Build,1726        );1727        cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml"));1728        rustc_cargo_env(builder, &mut cargo, host);17291730        let _guard =1731            builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, host);1732        let files = run_cargo(builder, cargo, vec![], &stamp, vec![], ArtifactKeepMode::OnlyRlib);17331734        GccCodegenBackendOutput {1735            stamp: write_codegen_backend_stamp(stamp, files, builder.config.dry_run()),1736        }1737    }17381739    fn metadata(&self) -> Option<StepMetadata> {1740        Some(1741            StepMetadata::build("rustc_codegen_gcc", self.compilers.target())1742                .built_by(self.compilers.build_compiler()),1743        )1744    }1745}17461747#[derive(Debug, Clone, PartialEq, Eq, Hash)]1748pub struct CraneliftCodegenBackend {1749    pub compilers: RustcPrivateCompilers,1750}17511752impl Step for CraneliftCodegenBackend {1753    type Output = BuildStamp;1754    const IS_HOST: bool = true;17551756    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1757        run.alias("rustc_codegen_cranelift").alias("cg_clif")1758    }17591760    fn make_run(run: RunConfig<'_>) {1761        run.builder.ensure(CraneliftCodegenBackend {1762            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),1763        });1764    }17651766    fn run(self, builder: &Builder<'_>) -> Self::Output {1767        let target = self.compilers.target();1768        let build_compiler = self.compilers.build_compiler();17691770        let stamp = build_stamp::codegen_backend_stamp(1771            builder,1772            build_compiler,1773            target,1774            &CodegenBackendKind::Cranelift,1775        );17761777        if builder.config.keep_stage.contains(&build_compiler.stage) {1778            trace!("`keep-stage` requested");1779            builder.info(1780                "WARNING: Using a potentially old codegen backend. \1781                This may not behave well.",1782            );1783            // Codegen backends are linked separately from this step today, so we don't do1784            // anything here.1785            return stamp;1786        }17871788        let mut cargo = builder::Cargo::new(1789            builder,1790            build_compiler,1791            Mode::Codegen,1792            SourceType::InTree,1793            target,1794            Kind::Build,1795        );1796        cargo1797            .arg("--manifest-path")1798            .arg(builder.src.join("compiler/rustc_codegen_cranelift/Cargo.toml"));1799        rustc_cargo_env(builder, &mut cargo, target);18001801        let _guard = builder.msg(1802            Kind::Build,1803            "codegen backend cranelift",1804            Mode::Codegen,1805            build_compiler,1806            target,1807        );1808        let files = run_cargo(builder, cargo, vec![], &stamp, vec![], ArtifactKeepMode::OnlyRlib);1809        write_codegen_backend_stamp(stamp, files, builder.config.dry_run())1810    }18111812    fn metadata(&self) -> Option<StepMetadata> {1813        Some(1814            StepMetadata::build("rustc_codegen_cranelift", self.compilers.target())1815                .built_by(self.compilers.build_compiler()),1816        )1817    }1818}18191820/// Write filtered `files` into the passed build stamp and returns it.1821fn write_codegen_backend_stamp(1822    mut stamp: BuildStamp,1823    files: Vec<PathBuf>,1824    dry_run: bool,1825) -> BuildStamp {1826    if dry_run {1827        return stamp;1828    }18291830    let mut files = files.into_iter().filter(|f| {1831        let filename = f.file_name().unwrap().to_str().unwrap();1832        is_dylib(f) && filename.contains("rustc_codegen_")1833    });1834    let codegen_backend = match files.next() {1835        Some(f) => f,1836        None => panic!("no dylibs built for codegen backend?"),1837    };1838    if let Some(f) = files.next() {1839        panic!("codegen backend built two dylibs:\n{}\n{}", codegen_backend.display(), f.display());1840    }18411842    let codegen_backend = codegen_backend.to_str().unwrap();1843    stamp = stamp.add_stamp(codegen_backend);1844    t!(stamp.write());1845    stamp1846}18471848/// Creates the `codegen-backends` folder for a compiler that's about to be1849/// assembled as a complete compiler.1850///1851/// This will take the codegen artifacts recorded in the given `stamp` and link them1852/// into an appropriate location for `target_compiler` to be a functional1853/// compiler.1854fn copy_codegen_backends_to_sysroot(1855    builder: &Builder<'_>,1856    stamp: BuildStamp,1857    target_compiler: Compiler,1858) {1859    // Note that this step is different than all the other `*Link` steps in1860    // that it's not assembling a bunch of libraries but rather is primarily1861    // moving the codegen backend into place. The codegen backend of rustc is1862    // not linked into the main compiler by default but is rather dynamically1863    // selected at runtime for inclusion.1864    //1865    // Here we're looking for the output dylib of the `CodegenBackend` step and1866    // we're copying that into the `codegen-backends` folder.1867    let dst = builder.sysroot_codegen_backends(target_compiler);1868    t!(fs::create_dir_all(&dst), dst);18691870    if builder.config.dry_run() {1871        return;1872    }18731874    if stamp.path().exists() {1875        let file = get_codegen_backend_file(&stamp);1876        builder.copy_link(1877            &file,1878            &dst.join(normalize_codegen_backend_name(builder, &file)),1879            FileType::NativeLibrary,1880        );1881    }1882}18831884/// Gets the path to a dynamic codegen backend library from its build stamp.1885pub fn get_codegen_backend_file(stamp: &BuildStamp) -> PathBuf {1886    PathBuf::from(t!(fs::read_to_string(stamp.path())))1887}18881889/// Normalize the name of a dynamic codegen backend library.1890pub fn normalize_codegen_backend_name(builder: &Builder<'_>, path: &Path) -> String {1891    let filename = path.file_name().unwrap().to_str().unwrap();1892    // change e.g. `librustc_codegen_cranelift-xxxxxx.so` to1893    // `librustc_codegen_cranelift-release.so`1894    let dash = filename.find('-').unwrap();1895    let dot = filename.find('.').unwrap();1896    format!("{}-{}{}", &filename[..dash], builder.rust_release(), &filename[dot..])1897}18981899pub fn compiler_file(1900    builder: &Builder<'_>,1901    compiler: &Path,1902    target: TargetSelection,1903    c: CLang,1904    file: &str,1905) -> PathBuf {1906    if builder.config.dry_run() {1907        return PathBuf::new();1908    }1909    let mut cmd = command(compiler);1910    cmd.args(builder.cc_handled_clags(target, c));1911    cmd.args(builder.cc_unhandled_cflags(target, GitRepo::Rustc, c));1912    cmd.arg(format!("-print-file-name={file}"));1913    let out = cmd.run_capture_stdout(builder).stdout();1914    PathBuf::from(out.trim())1915}19161917#[derive(Debug, Clone, PartialEq, Eq, Hash)]1918pub struct Sysroot {1919    pub compiler: Compiler,1920    /// See [`Std::force_recompile`].1921    force_recompile: bool,1922}19231924impl Sysroot {1925    pub(crate) fn new(compiler: Compiler) -> Self {1926        Sysroot { compiler, force_recompile: false }1927    }1928}19291930impl Step for Sysroot {1931    type Output = PathBuf;19321933    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1934        run.never()1935    }19361937    /// Returns the sysroot that `compiler` is supposed to use.1938    /// For the stage0 compiler, this is stage0-sysroot (because of the initial std build).1939    /// For all other stages, it's the same stage directory that the compiler lives in.1940    fn run(self, builder: &Builder<'_>) -> PathBuf {1941        let compiler = self.compiler;1942        let host_dir = builder.out.join(compiler.host);19431944        let sysroot_dir = |stage| {1945            if stage == 0 {1946                host_dir.join("stage0-sysroot")1947            } else if self.force_recompile && stage == compiler.stage {1948                host_dir.join(format!("stage{stage}-test-sysroot"))1949            } else if builder.download_rustc() && compiler.stage != builder.top_stage {1950                host_dir.join("ci-rustc-sysroot")1951            } else {1952                host_dir.join(format!("stage{stage}"))1953            }1954        };1955        let sysroot = sysroot_dir(compiler.stage);1956        trace!(stage = ?compiler.stage, ?sysroot);19571958        builder.do_if_verbose(|| {1959            println!("Removing sysroot {} to avoid caching bugs", sysroot.display())1960        });1961        let _ = fs::remove_dir_all(&sysroot);1962        t!(fs::create_dir_all(&sysroot));19631964        // In some cases(see https://github.com/rust-lang/rust/issues/109314), when the stage01965        // compiler relies on more recent version of LLVM than the stage0 compiler, it may not1966        // be able to locate the correct LLVM in the sysroot. This situation typically occurs1967        // when we upgrade LLVM version while the stage0 compiler continues to use an older version.1968        //1969        // Make sure to add the correct version of LLVM into the stage0 sysroot.1970        if compiler.stage == 0 {1971            dist::maybe_install_llvm_target(builder, compiler.host, &sysroot);1972        }19731974        // If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0.1975        if builder.download_rustc() && compiler.stage != 0 {1976            assert_eq!(1977                builder.config.host_target, compiler.host,1978                "Cross-compiling is not yet supported with `download-rustc`",1979            );19801981            // #102002, cleanup old toolchain folders when using download-rustc so people don't use them by accident.1982            for stage in 0..=2 {1983                if stage != compiler.stage {1984                    let dir = sysroot_dir(stage);1985                    if !dir.ends_with("ci-rustc-sysroot") {1986                        let _ = fs::remove_dir_all(dir);1987                    }1988                }1989            }19901991            // Copy the compiler into the correct sysroot.1992            // NOTE(#108767): We intentionally don't copy `rustc-dev` artifacts until they're requested with `builder.ensure(Rustc)`.1993            // This fixes an issue where we'd have multiple copies of libc in the sysroot with no way to tell which to load.1994            // There are a few quirks of bootstrap that interact to make this reliable:1995            // 1. The order `Step`s are run is hard-coded in `builder.rs` and not configurable. This1996            //    avoids e.g. reordering `test::UiFulldeps` before `test::Ui` and causing the latter to1997            //    fail because of duplicate metadata.1998            // 2. The sysroot is deleted and recreated between each invocation, so running `x test1999            //    ui-fulldeps && x test ui` can't cause failures.2000            let mut filtered_files = Vec::new();

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.