src/bootstrap/src/core/build_steps/compile.rs RUST 2,946 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 2,946.
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        if srcdir.join("eh").exists() {461            copy_and_stamp(462                builder,463                &libdir_self_contained,464                &srcdir.join("eh"),465                "libunwind.a",466                &mut target_deps,467                DependencyType::TargetSelfContained,468            );469        }470    } else if target.is_windows_gnu() || target.is_windows_gnullvm() {471        for obj in ["crt2.o", "dllcrt2.o"].iter() {472            let src = compiler_file(builder, &builder.cc(target), target, CLang::C, obj);473            let dst = libdir_self_contained.join(obj);474            builder.copy_link(&src, &dst, FileType::NativeLibrary);475            target_deps.push((dst, DependencyType::TargetSelfContained));476        }477    }478479    target_deps480}481482/// Resolves standard library crates for `Std::run_make` for any build kind (like check, doc,483/// build, clippy, etc.).484pub fn std_crates_for_run_make(run: &RunConfig<'_>) -> Vec<String> {485    let mut crates = run.make_run_crates(builder::Alias::Library);486487    // For no_std targets, we only want to check core and alloc488    // Regardless of core/alloc being selected explicitly or via the "library" default alias,489    // we only want to keep these two crates.490    // The set of no_std crates should be kept in sync with what `Builder::std_cargo` does.491    // Note: an alternative design would be to return an enum from this function (Default vs Subset)492    // of crates. However, several steps currently pass `-p <package>` even if all crates are493    // selected, because Cargo behaves differently in that case. To keep that behavior without494    // making further changes, we pre-filter the no-std crates here.495    let target_is_no_std = run.builder.no_std(run.target).unwrap_or(false);496    if target_is_no_std {497        crates.retain(|c| c == "core" || c == "alloc");498    }499    crates500}501502/// Tries to find LLVM's `compiler-rt` source directory, for building `library/profiler_builtins`.503///504/// Normally it lives in the `src/llvm-project` submodule, but if we will be using a505/// downloaded copy of CI LLVM, then we try to use the `compiler-rt` sources from506/// there instead, which lets us avoid checking out the LLVM submodule.507fn compiler_rt_for_profiler(builder: &Builder<'_>) -> PathBuf {508    // Try to use `compiler-rt` sources from downloaded CI LLVM, if possible.509    if builder.config.llvm_from_ci {510        // CI LLVM might not have been downloaded yet, so try to download it now.511        builder.config.maybe_download_ci_llvm();512        let ci_llvm_compiler_rt = builder.config.ci_llvm_root().join("compiler-rt");513        if ci_llvm_compiler_rt.exists() {514            return ci_llvm_compiler_rt;515        }516    }517518    // Otherwise, fall back to requiring the LLVM submodule.519    builder.require_submodule("src/llvm-project", {520        Some("The `build.profiler` config option requires `compiler-rt` sources from LLVM.")521    });522    builder.src.join("src/llvm-project/compiler-rt")523}524525/// Configure cargo to compile the standard library, adding appropriate env vars526/// and such.527pub fn std_cargo(528    builder: &Builder<'_>,529    target: TargetSelection,530    cargo: &mut Cargo,531    crates: &[String],532) {533    // rustc already ensures that it builds with the minimum deployment534    // target, so ideally we shouldn't need to do anything here.535    //536    // However, `cc` currently defaults to a higher version for backwards537    // compatibility, which means that compiler-rt, which is built via538    // compiler-builtins' build script, gets built with a higher deployment539    // target. This in turn causes warnings while linking, and is generally540    // a compatibility hazard.541    //542    // So, at least until https://github.com/rust-lang/cc-rs/issues/1171, or543    // perhaps https://github.com/rust-lang/cargo/issues/13115 is resolved, we544    // explicitly set the deployment target environment variables to avoid545    // this issue.546    //547    // This place also serves as an extension point if we ever wanted to raise548    // rustc's default deployment target while keeping the prebuilt `std` at549    // a lower version, so it's kinda nice to have in any case.550    if target.contains("apple") && !builder.config.dry_run() {551        // Query rustc for the deployment target, and the associated env var.552        // The env var is one of the standard `*_DEPLOYMENT_TARGET` vars, i.e.553        // `MACOSX_DEPLOYMENT_TARGET`, `IPHONEOS_DEPLOYMENT_TARGET`, etc.554        let mut cmd = builder.rustc_cmd(cargo.compiler());555        cmd.arg("--target").arg(target.rustc_target_arg());556        // FIXME(#152709): -Zunstable-options is to handle JSON targets.557        // Remove when JSON targets are stabilized.558        cmd.arg("-Zunstable-options").env("RUSTC_BOOTSTRAP", "1");559        cmd.arg("--print=deployment-target");560        let output = cmd.run_capture_stdout(builder).stdout();561562        let (env_var, value) = output.split_once('=').unwrap();563        // Unconditionally set the env var (if it was set in the environment564        // already, rustc should've picked that up).565        cargo.env(env_var.trim(), value.trim());566567        // Allow CI to override the deployment target for `std` on macOS.568        //569        // This is useful because we might want the host tooling LLVM, `rustc`570        // and Cargo to have a different deployment target than `std` itself571        // (currently, these two versions are the same, but in the past, we572        // supported macOS 10.7 for user code and macOS 10.8 in host tooling).573        //574        // It is not necessary on the other platforms, since only macOS has575        // support for host tooling.576        if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {577            cargo.env("MACOSX_DEPLOYMENT_TARGET", target);578        }579    }580581    // Paths needed by `library/profiler_builtins/build.rs`.582    if let Some(path) = builder.config.profiler_path(target) {583        cargo.env("LLVM_PROFILER_RT_LIB", path);584    } else if builder.config.profiler_enabled(target) {585        let compiler_rt = compiler_rt_for_profiler(builder);586        // Currently this is separate from the env var used by `compiler_builtins`587        // (below) so that adding support for CI LLVM here doesn't risk breaking588        // the compiler builtins. But they could be unified if desired.589        cargo.env("RUST_COMPILER_RT_FOR_PROFILER", compiler_rt);590    }591592    // Determine if we're going to compile in optimized C intrinsics to593    // the `compiler-builtins` crate. These intrinsics live in LLVM's594    // `compiler-rt` repository.595    //596    // Note that this shouldn't affect the correctness of `compiler-builtins`,597    // but only its speed. Some intrinsics in C haven't been translated to Rust598    // yet but that's pretty rare. Other intrinsics have optimized599    // implementations in C which have only had slower versions ported to Rust,600    // so we favor the C version where we can, but it's not critical.601    //602    // If `compiler-rt` is available ensure that the `c` feature of the603    // `compiler-builtins` crate is enabled and it's configured to learn where604    // `compiler-rt` is located.605    let compiler_builtins_c_feature = match builder.config.optimized_compiler_builtins(target) {606        CompilerBuiltins::LinkLLVMBuiltinsLib(path) => {607            cargo.env("LLVM_COMPILER_RT_LIB", path);608            " compiler-builtins-c"609        }610        CompilerBuiltins::BuildLLVMFuncs => {611            // NOTE: this interacts strangely with `llvm-has-rust-patches`. In that case, we enforce612            // `submodules = false`, so this is a no-op. But, the user could still decide to613            //  manually use an in-tree submodule.614            //615            // NOTE: if we're using system llvm, we'll end up building a version of `compiler-rt`616            // that doesn't match the LLVM we're linking to. That's probably ok? At least, the617            // difference wasn't enforced before. There's a comment in the compiler_builtins build618            // script that makes me nervous, though:619            // https://github.com/rust-lang/compiler-builtins/blob/31ee4544dbe47903ce771270d6e3bea8654e9e50/build.rs#L575-L579620            builder.require_submodule(621                "src/llvm-project",622                Some(623                    "The `build.optimized-compiler-builtins` config option \624                     requires `compiler-rt` sources from LLVM.",625                ),626            );627            let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt");628            if !builder.config.dry_run() {629                // This assertion would otherwise trigger during tests if `llvm-project` is not630                // checked out.631                assert!(compiler_builtins_root.exists());632            }633634            // The path to `compiler-rt` is also used by `profiler_builtins` (above),635            // so if you're changing something here please also change that as appropriate.636            cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root);637            " compiler-builtins-c"638        }639        CompilerBuiltins::BuildRustOnly => "",640    };641642    for krate in crates {643        cargo.args(["-p", krate]);644    }645646    let mut features = String::new();647648    if builder.no_std(target) == Some(true) {649        features += " compiler-builtins-mem";650        if !target.starts_with("bpf") {651            features.push_str(compiler_builtins_c_feature);652        }653654        // for no-std targets we only compile a few no_std crates655        if crates.is_empty() {656            cargo.args(["-p", "alloc"]);657        }658        cargo659            .arg("--manifest-path")660            .arg(builder.src.join("library/alloc/Cargo.toml"))661            .arg("--features")662            .arg(features);663    } else {664        features += &builder.std_features(target);665        features.push_str(compiler_builtins_c_feature);666667        cargo668            .arg("--features")669            .arg(features)670            .arg("--manifest-path")671            .arg(builder.src.join("library/sysroot/Cargo.toml"));672673        // Help the libc crate compile by assisting it in finding various674        // sysroot native libraries.675        if target.contains("musl")676            && let Some(p) = builder.musl_libdir(target)677        {678            let root = format!("native={}", p.to_str().unwrap());679            cargo.rustflag("-L").rustflag(&root);680        }681682        if target.contains("-wasi")683            && let Some(dir) = builder.wasi_libdir(target)684        {685            let root = format!("native={}", dir.to_str().unwrap());686            cargo.rustflag("-L").rustflag(&root);687        }688    }689690    if builder.config.rust_lto == RustcLto::Off {691        cargo.rustflag("-Clto=off");692    }693694    // By default, rustc does not include unwind tables unless they are required695    // for a particular target. They are not required by RISC-V targets, but696    // compiling the standard library with them means that users can get697    // backtraces without having to recompile the standard library themselves.698    //699    // This choice was discussed in https://github.com/rust-lang/rust/pull/69890700    if target.contains("riscv") {701        cargo.rustflag("-Cforce-unwind-tables=yes");702    }703704    let html_root =705        format!("-Zcrate-attr=doc(html_root_url=\"{}/\")", builder.doc_rust_lang_org_channel(),);706    cargo.rustflag(&html_root);707    cargo.rustdocflag(&html_root);708709    cargo.rustdocflag("-Zcrate-attr=warn(rust_2018_idioms)");710}711712/// Link all libstd rlibs/dylibs into a sysroot of `target_compiler`.713///714/// Links those artifacts generated by `compiler` to the `stage` compiler's715/// sysroot for the specified `host` and `target`.716///717/// Note that this assumes that `compiler` has already generated the libstd718/// libraries for `target`, and this method will find them in the relevant719/// output directory.720#[derive(Debug, Clone, PartialEq, Eq, Hash)]721pub struct StdLink {722    pub compiler: Compiler,723    pub target_compiler: Compiler,724    pub target: TargetSelection,725    /// Not actually used; only present to make sure the cache invalidation is correct.726    crates: Vec<String>,727    /// See [`Std::force_recompile`].728    force_recompile: bool,729}730731impl StdLink {732    pub fn from_std(std: Std, host_compiler: Compiler) -> Self {733        Self {734            compiler: host_compiler,735            target_compiler: std.build_compiler,736            target: std.target,737            crates: std.crates,738            force_recompile: std.force_recompile,739        }740    }741}742743impl Step for StdLink {744    type Output = ();745746    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {747        run.never()748    }749750    /// Link all libstd rlibs/dylibs into the sysroot location.751    ///752    /// Links those artifacts generated by `compiler` to the `stage` compiler's753    /// sysroot for the specified `host` and `target`.754    ///755    /// Note that this assumes that `compiler` has already generated the libstd756    /// libraries for `target`, and this method will find them in the relevant757    /// output directory.758    fn run(self, builder: &Builder<'_>) {759        let compiler = self.compiler;760        let target_compiler = self.target_compiler;761        let target = self.target;762763        // NOTE: intentionally does *not* check `target == builder.build` to avoid having to add the same check in `test::Crate`.764        let (libdir, hostdir) = if !self.force_recompile && builder.download_rustc() {765            // NOTE: copies part of `sysroot_libdir` to avoid having to add a new `force_recompile` argument there too766            let lib = builder.sysroot_libdir_relative(self.compiler);767            let sysroot = builder.ensure(crate::core::build_steps::compile::Sysroot {768                compiler: self.compiler,769                force_recompile: self.force_recompile,770            });771            let libdir = sysroot.join(lib).join("rustlib").join(target).join("lib");772            let hostdir = sysroot.join(lib).join("rustlib").join(compiler.host).join("lib");773            (libdir, hostdir)774        } else {775            let libdir = builder.sysroot_target_libdir(target_compiler, target);776            let hostdir = builder.sysroot_target_libdir(target_compiler, compiler.host);777            (libdir, hostdir)778        };779780        let is_downloaded_beta_stage0 = builder781            .build782            .config783            .initial_rustc784            .starts_with(builder.out.join(compiler.host).join("stage0/bin"));785786        // Special case for stage0, to make `rustup toolchain link` and `x dist --stage 0`787        // work for stage0-sysroot. We only do this if the stage0 compiler comes from beta,788        // and is not set to a custom path.789        if compiler.stage == 0 && is_downloaded_beta_stage0 {790            // Copy bin files from stage0/bin to stage0-sysroot/bin791            let sysroot = builder.out.join(compiler.host).join("stage0-sysroot");792793            let host = compiler.host;794            let stage0_bin_dir = builder.out.join(host).join("stage0/bin");795            let sysroot_bin_dir = sysroot.join("bin");796            t!(fs::create_dir_all(&sysroot_bin_dir));797            builder.cp_link_r(&stage0_bin_dir, &sysroot_bin_dir);798799            let stage0_lib_dir = builder.out.join(host).join("stage0/lib");800            t!(fs::create_dir_all(sysroot.join("lib")));801            builder.cp_link_r(&stage0_lib_dir, &sysroot.join("lib"));802803            // Copy codegen-backends from stage0804            let sysroot_codegen_backends = builder.sysroot_codegen_backends(compiler);805            t!(fs::create_dir_all(&sysroot_codegen_backends));806            let stage0_codegen_backends = builder807                .out808                .join(host)809                .join("stage0/lib/rustlib")810                .join(host)811                .join("codegen-backends");812            if stage0_codegen_backends.exists() {813                builder.cp_link_r(&stage0_codegen_backends, &sysroot_codegen_backends);814            }815        } else if compiler.stage == 0 {816            let sysroot = builder.out.join(compiler.host.triple).join("stage0-sysroot");817818            if builder.local_rebuild {819                // On local rebuilds this path might be a symlink to the project root,820                // which can be read-only (e.g., on CI). So remove it before copying821                // the stage0 lib.822                let _ = fs::remove_dir_all(sysroot.join("lib/rustlib/src/rust"));823            }824825            builder.cp_link_r(&builder.initial_sysroot.join("lib"), &sysroot.join("lib"));826        } else {827            if builder.download_rustc() {828                // Ensure there are no CI-rustc std artifacts.829                let _ = fs::remove_dir_all(&libdir);830                let _ = fs::remove_dir_all(&hostdir);831            }832833            add_to_sysroot(834                builder,835                &libdir,836                &hostdir,837                &build_stamp::libstd_stamp(builder, compiler, target),838            );839        }840    }841}842843/// Copies sanitizer runtime libraries into target libdir.844fn copy_sanitizers(845    builder: &Builder<'_>,846    compiler: &Compiler,847    target: TargetSelection,848) -> Vec<PathBuf> {849    let runtimes: Vec<llvm::SanitizerRuntime> = builder.ensure(llvm::Sanitizers { target });850851    if builder.config.dry_run() {852        return Vec::new();853    }854855    let mut target_deps = Vec::new();856    let libdir = builder.sysroot_target_libdir(*compiler, target);857858    for runtime in &runtimes {859        let dst = libdir.join(&runtime.name);860        builder.copy_link(&runtime.path, &dst, FileType::NativeLibrary);861862        // The `aarch64-apple-ios-macabi` and `x86_64-apple-ios-macabi` are also supported for863        // sanitizers, but they share a sanitizer runtime with `${arch}-apple-darwin`, so we do864        // not list them here to rename and sign the runtime library.865        if target == "x86_64-apple-darwin"866            || target == "aarch64-apple-darwin"867            || target == "aarch64-apple-ios"868            || target == "aarch64-apple-ios-sim"869            || target == "x86_64-apple-ios"870        {871            // Update the library’s install name to reflect that it has been renamed.872            apple_darwin_update_library_name(builder, &dst, &format!("@rpath/{}", runtime.name));873            // Upon renaming the install name, the code signature of the file will invalidate,874            // so we will sign it again.875            apple_darwin_sign_file(builder, &dst);876        }877878        target_deps.push(dst);879    }880881    target_deps882}883884fn apple_darwin_update_library_name(builder: &Builder<'_>, library_path: &Path, new_name: &str) {885    command("install_name_tool").arg("-id").arg(new_name).arg(library_path).run(builder);886}887888fn apple_darwin_sign_file(builder: &Builder<'_>, file_path: &Path) {889    command("codesign")890        .arg("-f") // Force to rewrite the existing signature891        .arg("-s")892        .arg("-")893        .arg(file_path)894        .run(builder);895}896897#[derive(Debug, Clone, PartialEq, Eq, Hash)]898pub struct StartupObjects {899    pub compiler: Compiler,900    pub target: TargetSelection,901}902903impl Step for StartupObjects {904    type Output = Vec<(PathBuf, DependencyType)>;905906    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {907        run.path("library/rtstartup")908    }909910    fn make_run(run: RunConfig<'_>) {911        run.builder.ensure(StartupObjects {912            compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),913            target: run.target,914        });915    }916917    /// Builds and prepare startup objects like rsbegin.o and rsend.o918    ///919    /// These are primarily used on Windows right now for linking executables/dlls.920    /// They don't require any library support as they're just plain old object921    /// files, so we just use the nightly snapshot compiler to always build them (as922    /// no other compilers are guaranteed to be available).923    fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> {924        let for_compiler = self.compiler;925        let target = self.target;926        // Even though no longer necessary on x86_64, they are kept for now to927        // avoid potential issues in downstream crates.928        if !target.is_windows_gnu() {929            return vec![];930        }931932        let mut target_deps = vec![];933934        let src_dir = &builder.src.join("library").join("rtstartup");935        let dst_dir = &builder.native_dir(target).join("rtstartup");936        let sysroot_dir = &builder.sysroot_target_libdir(for_compiler, target);937        t!(fs::create_dir_all(dst_dir));938939        for file in &["rsbegin", "rsend"] {940            let src_file = &src_dir.join(file.to_string() + ".rs");941            let dst_file = &dst_dir.join(file.to_string() + ".o");942            if !up_to_date(src_file, dst_file) {943                let mut cmd = command(&builder.initial_rustc);944                cmd.env("RUSTC_BOOTSTRAP", "1");945                if !builder.local_rebuild {946                    // a local_rebuild compiler already has stage1 features947                    cmd.arg("--cfg").arg("bootstrap");948                }949                cmd.arg("--target")950                    .arg(target.rustc_target_arg())951                    .arg("--emit=obj")952                    .arg("-o")953                    .arg(dst_file)954                    .arg(src_file)955                    .run(builder);956            }957958            let obj = sysroot_dir.join((*file).to_string() + ".o");959            builder.copy_link(dst_file, &obj, FileType::NativeLibrary);960            target_deps.push((obj, DependencyType::Target));961        }962963        target_deps964    }965}966967fn cp_rustc_component_to_ci_sysroot(builder: &Builder<'_>, sysroot: &Path, contents: Vec<String>) {968    let ci_rustc_dir = builder.config.ci_rustc_dir();969970    for file in contents {971        let src = ci_rustc_dir.join(&file);972        let dst = sysroot.join(file);973        if src.is_dir() {974            t!(fs::create_dir_all(dst));975        } else {976            builder.copy_link(&src, &dst, FileType::Regular);977        }978    }979}980981/// Represents information about a built rustc.982#[derive(Clone, Debug)]983pub struct BuiltRustc {984    /// The compiler that actually built this *rustc*.985    /// This can be different from the *build_compiler* passed to the `Rustc` step because of986    /// uplifting.987    pub build_compiler: Compiler,988}989990/// Build rustc using the passed `build_compiler`.991///992/// - Makes sure that `build_compiler` has a standard library prepared for its host target,993///   so that it can compile build scripts and proc macros when building this `rustc`.994/// - Makes sure that `build_compiler` has a standard library prepared for `target`,995///   so that the built `rustc` can *link to it* and use it at runtime.996#[derive(Debug, Clone, PartialEq, Eq, Hash)]997pub struct Rustc {998    /// The target on which rustc will run (its host).999    pub target: TargetSelection,1000    /// The **previous** compiler used to compile this rustc.1001    pub build_compiler: Compiler,1002    /// Whether to build a subset of crates, rather than the whole compiler.1003    ///1004    /// This should only be requested by the user, not used within bootstrap itself.1005    /// Using it within bootstrap can lead to confusing situation where lints are replayed1006    /// in two different steps.1007    crates: Vec<String>,1008}10091010impl Rustc {1011    pub fn new(build_compiler: Compiler, target: TargetSelection) -> Self {1012        Self { target, build_compiler, crates: Default::default() }1013    }1014}10151016impl Step for Rustc {1017    type Output = BuiltRustc;1018    const IS_HOST: bool = true;10191020    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1021        let mut crates = run.builder.in_tree_crates("rustc-main", None);1022        for (i, krate) in crates.iter().enumerate() {1023            // We can't allow `build rustc` as an alias for this Step, because that's reserved by `Assemble`.1024            // Ideally Assemble would use `build compiler` instead, but that seems too confusing to be worth the breaking change.1025            if krate.name == "rustc-main" {1026                crates.swap_remove(i);1027                break;1028            }1029        }1030        run.crates(crates)1031    }10321033    fn is_default_step(_builder: &Builder<'_>) -> bool {1034        false1035    }10361037    fn make_run(run: RunConfig<'_>) {1038        // If only `compiler` was passed, do not run this step.1039        // Instead the `Assemble` step will take care of compiling Rustc.1040        if run.builder.paths == vec![PathBuf::from("compiler")] {1041            return;1042        }10431044        let crates = run.cargo_crates_in_set();1045        run.builder.ensure(Rustc {1046            build_compiler: run1047                .builder1048                .compiler(run.builder.top_stage.saturating_sub(1), run.build_triple()),1049            target: run.target,1050            crates,1051        });1052    }10531054    /// Builds the compiler.1055    ///1056    /// This will build the compiler for a particular stage of the build using1057    /// the `build_compiler` targeting the `target` architecture. The artifacts1058    /// created will also be linked into the sysroot directory.1059    fn run(self, builder: &Builder<'_>) -> Self::Output {1060        let build_compiler = self.build_compiler;1061        let target = self.target;10621063        // NOTE: the ABI of the stage0 compiler is different from the ABI of the downloaded compiler,1064        // so its artifacts can't be reused.1065        if builder.download_rustc() && build_compiler.stage != 0 {1066            trace!(stage = build_compiler.stage, "`download_rustc` requested");10671068            let sysroot =1069                builder.ensure(Sysroot { compiler: build_compiler, force_recompile: false });1070            cp_rustc_component_to_ci_sysroot(1071                builder,1072                &sysroot,1073                builder.config.ci_rustc_dev_contents(),1074            );1075            return BuiltRustc { build_compiler };1076        }10771078        // Build a standard library for `target` using the `build_compiler`.1079        // This will be the standard library that the rustc which we build *links to*.1080        builder.std(build_compiler, target);10811082        if builder.config.keep_stage.contains(&build_compiler.stage) {1083            trace!(stage = build_compiler.stage, "`keep-stage` requested");10841085            builder.info("WARNING: Using a potentially old librustc. This may not behave well.");1086            builder.info("WARNING: Use `--keep-stage-std` if you want to rebuild the compiler when it changes");1087            builder.ensure(RustcLink::from_rustc(self));10881089            return BuiltRustc { build_compiler };1090        }10911092        // The stage of the compiler that we're building1093        let stage = build_compiler.stage + 1;10941095        // If we are building a stage3+ compiler, and full bootstrap is disabled, and we have a1096        // previous rustc available, we will uplift a compiler from a previous stage.1097        // We do not allow cross-compilation uplifting here, because there it can be quite tricky1098        // to figure out which stage actually built the rustc that should be uplifted.1099        if build_compiler.stage >= 21100            && !builder.config.full_bootstrap1101            && target == builder.host_target1102        {1103            // Here we need to determine the **build compiler** that built the stage that we will1104            // be uplifting. We cannot uplift stage 1, as it has a different ABI than stage 2+,1105            // so we always uplift the stage2 compiler (compiled with stage 1).1106            let uplift_build_compiler = builder.compiler(1, build_compiler.host);11071108            let msg = format!("Uplifting rustc from stage2 to stage{stage})");1109            builder.info(&msg);11101111            // Here the compiler that built the rlibs (`uplift_build_compiler`) can be different1112            // from the compiler whose sysroot should be modified in this step. So we need to copy1113            // the (previously built) rlibs into the correct sysroot.1114            builder.ensure(RustcLink::from_build_compiler_and_sysroot(1115                // This is the compiler that actually built the rustc rlibs1116                uplift_build_compiler,1117                // We copy the rlibs into the sysroot of `build_compiler`1118                build_compiler,1119                target,1120                self.crates,1121            ));11221123            // Here we have performed an uplift, so we return the actual build compiler that "built"1124            // this rustc.1125            return BuiltRustc { build_compiler: uplift_build_compiler };1126        }11271128        // Build a standard library for the current host target using the `build_compiler`.1129        // This standard library will be used when building `rustc` for compiling1130        // build scripts and proc macros.1131        // If we are not cross-compiling, the Std build above will be the same one as the one we1132        // prepare here.1133        builder.std(1134            builder.compiler(self.build_compiler.stage, builder.config.host_target),1135            builder.config.host_target,1136        );11371138        let mut cargo = builder::Cargo::new(1139            builder,1140            build_compiler,1141            Mode::Rustc,1142            SourceType::InTree,1143            target,1144            Kind::Build,1145        );11461147        rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);11481149        // NB: all RUSTFLAGS should be added to `rustc_cargo()` so they will be1150        // consistently applied by check/doc/test modes too.11511152        for krate in &*self.crates {1153            cargo.arg("-p").arg(krate);1154        }11551156        if builder.build.config.enable_bolt_settings && build_compiler.stage == 1 {1157            // Relocations are required for BOLT to work.1158            cargo.env("RUSTC_BOLT_LINK_FLAGS", "1");1159        }11601161        let _guard = builder.msg(1162            Kind::Build,1163            format_args!("compiler artifacts{}", crate_description(&self.crates)),1164            Mode::Rustc,1165            build_compiler,1166            target,1167        );1168        let stamp = build_stamp::librustc_stamp(builder, build_compiler, target);11691170        run_cargo(1171            builder,1172            cargo,1173            vec![],1174            &stamp,1175            vec![],1176            ArtifactKeepMode::Custom(Box::new(|filename| {1177                if filename.contains("jemalloc_sys")1178                    || filename.contains("rustc_public_bridge")1179                    || filename.contains("rustc_public")1180                {1181                    // jemalloc_sys and rustc_public_bridge are not linked into librustc_driver.so,1182                    // so we need to distribute them as rlib to be able to use them.1183                    filename.ends_with(".rlib")1184                } else {1185                    // Distribute the rest of the rustc crates as rmeta files only to reduce1186                    // the tarball sizes by about 50%. The object files are linked into1187                    // librustc_driver.so, so it is still possible to link against them.1188                    filename.ends_with(".rmeta")1189                }1190            })),1191        );11921193        let target_root_dir = stamp.path().parent().unwrap();1194        // When building `librustc_driver.so` (like `libLLVM.so`) on linux, it can contain1195        // unexpected debuginfo from dependencies, for example from the C++ standard library used in1196        // our LLVM wrapper. Unless we're explicitly requesting `librustc_driver` to be built with1197        // debuginfo (via the debuginfo level of the executables using it): strip this debuginfo1198        // away after the fact.1199        if builder.config.rust_debuginfo_level_rustc == DebuginfoLevel::None1200            && builder.config.rust_debuginfo_level_tools == DebuginfoLevel::None1201        {1202            let rustc_driver = target_root_dir.join("librustc_driver.so");1203            strip_debug(builder, target, &rustc_driver);1204        }12051206        if builder.config.rust_debuginfo_level_rustc == DebuginfoLevel::None {1207            // Due to LTO a lot of debug info from C++ dependencies such as jemalloc can make it into1208            // our final binaries1209            strip_debug(builder, target, &target_root_dir.join("rustc-main"));1210        }12111212        builder.ensure(RustcLink::from_rustc(self));1213        BuiltRustc { build_compiler }1214    }12151216    fn metadata(&self) -> Option<StepMetadata> {1217        Some(StepMetadata::build("rustc", self.target).built_by(self.build_compiler))1218    }1219}12201221pub fn rustc_cargo(1222    builder: &Builder<'_>,1223    cargo: &mut Cargo,1224    target: TargetSelection,1225    build_compiler: &Compiler,1226    crates: &[String],1227) {1228    cargo1229        .arg("--features")1230        .arg(builder.rustc_features(builder.kind, target, crates))1231        .arg("--manifest-path")1232        .arg(builder.src.join("compiler/rustc/Cargo.toml"));12331234    cargo.rustdocflag("-Zcrate-attr=warn(rust_2018_idioms)");12351236    // If the rustc output is piped to e.g. `head -n1` we want the process to be killed, rather than1237    // having an error bubble up and cause a panic.1238    //1239    // FIXME(jieyouxu): this flag is load-bearing for rustc to not ICE on broken pipes, because1240    // rustc internally sometimes uses std `println!` -- but std `println!` by default will panic on1241    // broken pipes, and uncaught panics will manifest as an ICE. The compiler *should* handle this1242    // properly, but this flag is set in the meantime to paper over the I/O errors.1243    //1244    // See <https://github.com/rust-lang/rust/issues/131059> for details.1245    //1246    // Also see the discussion for properly handling I/O errors related to broken pipes, i.e. safe1247    // variants of `println!` in1248    // <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Internal.20lint.20for.20raw.20.60print!.60.20and.20.60println!.60.3F>.1249    cargo.rustflag("-Zon-broken-pipe=kill");12501251    // Building with protected visibility reduces the number of dynamic relocations needed, giving1252    // us a faster startup time. However GNU ld < 2.40 will error if we try to link a shared object1253    // with direct references to protected symbols, so for now we only use protected symbols if1254    // linking with LLD is enabled.1255    if builder.build.config.bootstrap_override_lld.is_used() {1256        cargo.rustflag("-Zdefault-visibility=protected");1257    }12581259    if is_lto_stage(build_compiler) {1260        match builder.config.rust_lto {1261            RustcLto::Thin | RustcLto::Fat => {1262                // Since using LTO for optimizing dylibs is currently experimental,1263                // we need to pass -Zdylib-lto.1264                cargo.rustflag("-Zdylib-lto");1265                // Cargo by default passes `-Cembed-bitcode=no` and doesn't pass `-Clto` when1266                // compiling dylibs (and their dependencies), even when LTO is enabled for the1267                // crate. Therefore, we need to override `-Clto` and `-Cembed-bitcode` here.1268                let lto_type = match builder.config.rust_lto {1269                    RustcLto::Thin => "thin",1270                    RustcLto::Fat => "fat",1271                    _ => unreachable!(),1272                };1273                cargo.rustflag(&format!("-Clto={lto_type}"));1274                cargo.rustflag("-Cembed-bitcode=yes");1275            }1276            RustcLto::ThinLocal => { /* Do nothing, this is the default */ }1277            RustcLto::Off => {1278                cargo.rustflag("-Clto=off");1279            }1280        }1281    } else if builder.config.rust_lto == RustcLto::Off {1282        cargo.rustflag("-Clto=off");1283    }12841285    // With LLD, we can use ICF (identical code folding) to reduce the executable size1286    // of librustc_driver/rustc and to improve i-cache utilization.1287    //1288    // -Wl,[link options] doesn't work on MSVC. However, /OPT:ICF (technically /OPT:REF,ICF)1289    // is already on by default in MSVC optimized builds, which is interpreted as --icf=all:1290    // https://github.com/llvm/llvm-project/blob/3329cec2f79185bafd678f310fafadba2a8c76d2/lld/COFF/Driver.cpp#L17461291    // https://github.com/rust-lang/rust/blob/f22819bcce4abaff7d1246a56eec493418f9f4ee/compiler/rustc_codegen_ssa/src/back/linker.rs#L8271292    if builder.config.bootstrap_override_lld.is_used() && !build_compiler.host.is_msvc() {1293        cargo.rustflag("-Clink-args=-Wl,--icf=all");1294    }12951296    if builder.config.rust_profile_use.is_some() && builder.config.rust_profile_generate.is_some() {1297        panic!("Cannot use and generate PGO profiles at the same time");1298    }1299    let is_collecting = if let Some(path) = &builder.config.rust_profile_generate {1300        if build_compiler.stage == 1 {1301            cargo.rustflag(&format!("-Cprofile-generate={path}"));1302            // Apparently necessary to avoid overflowing the counters during1303            // a Cargo build profile1304            cargo.rustflag("-Cllvm-args=-vp-counters-per-site=4");1305            true1306        } else {1307            false1308        }1309    } else if let Some(path) = &builder.config.rust_profile_use {1310        if build_compiler.stage == 1 {1311            cargo.rustflag(&format!("-Cprofile-use={path}"));1312            if builder.is_verbose() {1313                cargo.rustflag("-Cllvm-args=-pgo-warn-missing-function");1314            }1315            true1316        } else {1317            false1318        }1319    } else {1320        false1321    };1322    if is_collecting {1323        // Ensure paths to Rust sources are relative, not absolute.1324        cargo.rustflag(&format!(1325            "-Cllvm-args=-static-func-strip-dirname-prefix={}",1326            builder.config.src.components().count()1327        ));1328    }13291330    // The stage0 compiler changes infrequently and does not directly depend on code1331    // in the current working directory. Therefore, caching it with sccache should be1332    // useful.1333    // This is only performed for non-incremental builds, as ccache cannot deal with these.1334    if let Some(ref ccache) = builder.config.ccache1335        && build_compiler.stage == 01336        && !builder.config.incremental1337    {1338        cargo.env("RUSTC_WRAPPER", ccache);1339    }13401341    rustc_cargo_env(builder, cargo, target);1342}13431344pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) {1345    // Set some configuration variables picked up by build scripts and1346    // the compiler alike1347    cargo1348        .env("CFG_RELEASE", builder.rust_release())1349        .env("CFG_RELEASE_CHANNEL", &builder.config.channel)1350        .env("CFG_VERSION", builder.rust_version());13511352    // Some tools like Cargo detect their own git information in build scripts. When omit-git-hash1353    // is enabled in bootstrap.toml, we pass this environment variable to tell build scripts to avoid1354    // detecting git information on their own.1355    if builder.config.omit_git_hash {1356        cargo.env("CFG_OMIT_GIT_HASH", "1");1357    }13581359    cargo.env("CFG_DEFAULT_CODEGEN_BACKEND", builder.config.default_codegen_backend(target).name());13601361    let libdir_relative = builder.config.libdir_relative().unwrap_or_else(|| Path::new("lib"));1362    let target_config = builder.config.target_config.get(&target);13631364    cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);13651366    if let Some(ref ver_date) = builder.rust_info().commit_date() {1367        cargo.env("CFG_VER_DATE", ver_date);1368    }1369    if let Some(ref ver_hash) = builder.rust_info().sha() {1370        cargo.env("CFG_VER_HASH", ver_hash);1371    }1372    if !builder.unstable_features() {1373        cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1");1374    }13751376    // Prefer the current target's own default_linker, else a globally1377    // specified one.1378    if let Some(s) = target_config.and_then(|c| c.default_linker.as_ref()) {1379        cargo.env("CFG_DEFAULT_LINKER", s);1380    } else if let Some(ref s) = builder.config.rustc_default_linker {1381        cargo.env("CFG_DEFAULT_LINKER", s);1382    }13831384    // Enable rustc's env var to use a linker override on Linux when requested.1385    if let Some(linker) = target_config.map(|c| c.default_linker_linux_override) {1386        match linker {1387            DefaultLinuxLinkerOverride::Off => {}1388            DefaultLinuxLinkerOverride::SelfContainedLldCc => {1389                cargo.env("CFG_DEFAULT_LINKER_SELF_CONTAINED_LLD_CC", "1");1390            }1391        }1392    }13931394    // The host this new compiler will *run* on.1395    cargo.env("CFG_COMPILER_HOST_TRIPLE", target.triple);13961397    if builder.config.rust_verify_llvm_ir {1398        cargo.env("RUSTC_VERIFY_LLVM_IR", "1");1399    }14001401    // These conditionals represent a tension between three forces:1402    // - For non-check builds, we need to define some LLVM-related environment1403    //   variables, requiring LLVM to have been built.1404    // - For check builds, we want to avoid building LLVM if possible.1405    // - Check builds and non-check builds should have the same environment if1406    //   possible, to avoid unnecessary rebuilds due to cache-busting.1407    //1408    // Therefore we try to avoid building LLVM for check builds, but only if1409    // building LLVM would be expensive. If "building" LLVM is cheap1410    // (i.e. it's already built or is downloadable), we prefer to maintain a1411    // consistent environment between check and non-check builds.1412    if builder.config.llvm_enabled(target) {1413        let building_llvm_is_expensive =1414            crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target, false)1415                .should_build();14161417        let skip_llvm = (builder.kind == Kind::Check) && building_llvm_is_expensive;1418        if !skip_llvm {1419            rustc_llvm_env(builder, cargo, target)1420        }1421    }14221423    // See also the "JEMALLOC_SYS_WITH_LG_PAGE" setting in the tool build step.1424    if builder.config.jemalloc(target) && env::var_os("JEMALLOC_SYS_WITH_LG_PAGE").is_none() {1425        // Build jemalloc on AArch64 with support for page sizes up to 64K1426        // See: https://github.com/rust-lang/rust/pull/1350811427        if target.starts_with("aarch64") {1428            cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "16");1429        }1430        // Build jemalloc on LoongArch with support for page sizes up to 16K1431        else if target.starts_with("loongarch") {1432            cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "14");1433        }1434    }1435}14361437/// Pass down configuration from the LLVM build into the build of1438/// rustc_llvm and rustc_codegen_llvm.1439///1440/// Note that this has the side-effect of _building LLVM_, which is sometimes1441/// unwanted (e.g. for check builds).1442fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) {1443    if builder.config.is_rust_llvm(target) {1444        cargo.env("LLVM_RUSTLLVM", "1");1445    }1446    if builder.config.llvm_enzyme {1447        cargo.env("LLVM_ENZYME", "1");1448    }1449    let llvm::LlvmResult { host_llvm_config, .. } = builder.ensure(llvm::Llvm { target });1450    if builder.config.llvm_offload {1451        builder.ensure(llvm::OmpOffload { target });1452        cargo.env("LLVM_OFFLOAD", "1");1453    }14541455    cargo.env("LLVM_CONFIG", &host_llvm_config);14561457    // Some LLVM linker flags (-L and -l) may be needed to link `rustc_llvm`. Its build script1458    // expects these to be passed via the `LLVM_LINKER_FLAGS` env variable, separated by1459    // whitespace.1460    //1461    // For example:1462    // - on windows, when `clang-cl` is used with instrumentation, we need to manually add1463    // clang's runtime library resource directory so that the profiler runtime library can be1464    // found. This is to avoid the linker errors about undefined references to1465    // `__llvm_profile_instrument_memop` when linking `rustc_driver`.1466    let mut llvm_linker_flags = String::new();1467    if builder.config.llvm_profile_generate1468        && target.is_msvc()1469        && let Some(ref clang_cl_path) = builder.config.llvm_clang_cl1470    {1471        // Add clang's runtime library directory to the search path1472        let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path);1473        llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display()));1474    }14751476    // The config can also specify its own llvm linker flags.1477    if let Some(ref s) = builder.config.llvm_ldflags {1478        if !llvm_linker_flags.is_empty() {1479            llvm_linker_flags.push(' ');1480        }1481        llvm_linker_flags.push_str(s);1482    }14831484    // Set the linker flags via the env var that `rustc_llvm`'s build script will read.1485    if !llvm_linker_flags.is_empty() {1486        cargo.env("LLVM_LINKER_FLAGS", llvm_linker_flags);1487    }14881489    // Building with a static libstdc++ is only supported on Linux and windows-gnu* right now,1490    // not for MSVC or macOS1491    if builder.config.llvm_static_stdcpp1492        && !target.contains("freebsd")1493        && !target.is_msvc()1494        && !target.contains("apple")1495        && !target.contains("solaris")1496    {1497        let libstdcxx_name =1498            if target.contains("windows-gnullvm") { "libc++.a" } else { "libstdc++.a" };1499        let file = compiler_file(1500            builder,1501            &builder.cxx(target).unwrap(),1502            target,1503            CLang::Cxx,1504            libstdcxx_name,1505        );1506        cargo.env("LLVM_STATIC_STDCPP", file);1507    }1508    if builder.llvm_link_shared() {1509        cargo.env("LLVM_LINK_SHARED", "1");1510    }1511    if builder.config.llvm_use_libcxx {1512        cargo.env("LLVM_USE_LIBCXX", "1");1513    }1514    if builder.config.llvm_assertions {1515        cargo.env("LLVM_ASSERTIONS", "1");1516    }1517}15181519/// `RustcLink` copies compiler rlibs from a rustc build into a compiler sysroot.1520/// It works with (potentially up to) three compilers:1521/// - `build_compiler` is a compiler that built rustc rlibs1522/// - `sysroot_compiler` is a compiler into whose sysroot we will copy the rlibs1523///   - In most situations, `build_compiler` == `sysroot_compiler`1524/// - `target_compiler` is the compiler whose rlibs were built. It is not represented explicitly1525///   in this step, rather we just read the rlibs from a rustc build stamp of `build_compiler`.1526///1527/// This is necessary for tools using `rustc_private`, where the previous compiler will build1528/// a tool against the next compiler.1529/// To build a tool against a compiler, the rlibs of that compiler that it links against1530/// must be in the sysroot of the compiler that's doing the compiling.1531#[derive(Debug, Clone, PartialEq, Eq, Hash)]1532struct RustcLink {1533    /// This compiler **built** some rustc, whose rlibs we will copy into a sysroot.1534    build_compiler: Compiler,1535    /// This is the compiler into whose sysroot we want to copy the built rlibs.1536    /// In most cases, it will correspond to `build_compiler`.1537    sysroot_compiler: Compiler,1538    target: TargetSelection,1539    /// Not actually used; only present to make sure the cache invalidation is correct.1540    crates: Vec<String>,1541}15421543impl RustcLink {1544    /// Copy rlibs from the build compiler that build this `rustc` into the sysroot of that1545    /// build compiler.1546    fn from_rustc(rustc: Rustc) -> Self {1547        Self {1548            build_compiler: rustc.build_compiler,1549            sysroot_compiler: rustc.build_compiler,1550            target: rustc.target,1551            crates: rustc.crates,1552        }1553    }15541555    /// Copy rlibs **built** by `build_compiler` into the sysroot of `sysroot_compiler`.1556    fn from_build_compiler_and_sysroot(1557        build_compiler: Compiler,1558        sysroot_compiler: Compiler,1559        target: TargetSelection,1560        crates: Vec<String>,1561    ) -> Self {1562        Self { build_compiler, sysroot_compiler, target, crates }1563    }1564}15651566impl Step for RustcLink {1567    type Output = ();15681569    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1570        run.never()1571    }15721573    /// Same as `StdLink`, only for librustc1574    fn run(self, builder: &Builder<'_>) {1575        let build_compiler = self.build_compiler;1576        let sysroot_compiler = self.sysroot_compiler;1577        let target = self.target;1578        add_to_sysroot(1579            builder,1580            &builder.sysroot_target_libdir(sysroot_compiler, target),1581            &builder.sysroot_target_libdir(sysroot_compiler, sysroot_compiler.host),1582            &build_stamp::librustc_stamp(builder, build_compiler, target),1583        );1584    }1585}15861587/// Set of `libgccjit` dylibs that can be used by `cg_gcc` to compile code for a set of targets.1588/// `libgccjit` requires a separate build for each `(host, target)` pair.1589/// So if you are on linux-x64 and build for linux-aarch64, you will need at least:1590/// - linux-x64 -> linux-x64 libgccjit (for building host code like proc macros)1591/// - linux-x64 -> linux-aarch64 libgccjit (for the aarch64 target code)1592#[derive(Clone)]1593pub struct GccDylibSet {1594    dylibs: BTreeMap<GccTargetPair, GccOutput>,1595}15961597impl GccDylibSet {1598    /// Build a set of libgccjit dylibs that will be executed on `host` and will generate code for1599    /// each specified target.1600    pub fn build(1601        builder: &Builder<'_>,1602        host: TargetSelection,1603        targets: Vec<TargetSelection>,1604    ) -> Self {1605        let dylibs = targets1606            .iter()1607            .map(|t| GccTargetPair::for_target_pair(host, *t))1608            .map(|target_pair| (target_pair, builder.ensure(Gcc { target_pair })))1609            .collect();1610        Self { dylibs }1611    }16121613    /// Install the libgccjit dylibs to the corresponding target directories of the given compiler.1614    /// cg_gcc know how to search for the libgccjit dylibs in these directories, according to the1615    /// (host, target) pair that is being compiled by rustc and cg_gcc.1616    pub fn install_to(&self, builder: &Builder<'_>, compiler: Compiler) {1617        if builder.config.dry_run() {1618            return;1619        }16201621        // <rustc>/lib/<host-target>/codegen-backends1622        let cg_sysroot = builder.sysroot_codegen_backends(compiler);16231624        for (target_pair, libgccjit) in &self.dylibs {1625            assert_eq!(1626                target_pair.host(),1627                compiler.host,1628                "Trying to install libgccjit ({target_pair}) to a compiler with a different host ({})",1629                compiler.host1630            );1631            let libgccjit_path = libgccjit.libgccjit();16321633            // If we build libgccjit ourselves, then `libgccjit` can actually be a symlink.1634            // In that case, we have to resolve it first, otherwise we'd create a symlink to a1635            // symlink, which wouldn't work.1636            let libgccjit_path = t!(1637                libgccjit_path.canonicalize(),1638                format!("Cannot find libgccjit at {}", libgccjit_path.display())1639            );16401641            let dst = cg_sysroot.join(libgccjit_path_relative_to_cg_dir(target_pair, libgccjit));1642            t!(std::fs::create_dir_all(dst.parent().unwrap()));1643            builder.copy_link(&libgccjit_path, &dst, FileType::NativeLibrary);1644        }1645    }1646}16471648/// Returns a path where libgccjit.so should be stored, **relative** to the1649/// **codegen backend directory**.1650pub fn libgccjit_path_relative_to_cg_dir(1651    target_pair: &GccTargetPair,1652    libgccjit: &GccOutput,1653) -> PathBuf {1654    let target_filename = libgccjit.libgccjit().file_name().unwrap().to_str().unwrap();16551656    // <cg-dir>/lib/<target>/libgccjit.so1657    Path::new("lib").join(target_pair.target()).join(target_filename)1658}16591660/// Output of the `compile::GccCodegenBackend` step.1661///1662/// It contains a build stamp with the path to the built cg_gcc dylib.1663#[derive(Clone)]1664pub struct GccCodegenBackendOutput {1665    stamp: BuildStamp,1666}16671668impl GccCodegenBackendOutput {1669    pub fn stamp(&self) -> &BuildStamp {1670        &self.stamp1671    }1672}16731674/// Builds the GCC codegen backend (`cg_gcc`).1675/// Note that this **does not** build libgccjit, which is a dependency of cg_gcc.1676/// That has to be built separately, because a separate copy of libgccjit is required1677/// for each (host, target) compilation pair.1678/// cg_gcc goes to great lengths to ensure that it does not *directly* link to libgccjit,1679/// so we respect that here and allow building cg_gcc without building libgccjit itself.1680#[derive(Debug, Clone, PartialEq, Eq, Hash)]1681pub struct GccCodegenBackend {1682    compilers: RustcPrivateCompilers,1683    target: TargetSelection,1684}16851686impl GccCodegenBackend {1687    /// Build `cg_gcc` that will run on the given host target.1688    pub fn for_target(compilers: RustcPrivateCompilers, target: TargetSelection) -> Self {1689        Self { compilers, target }1690    }1691}16921693impl Step for GccCodegenBackend {1694    type Output = GccCodegenBackendOutput;16951696    const IS_HOST: bool = true;16971698    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1699        run.alias("rustc_codegen_gcc").alias("cg_gcc")1700    }17011702    fn make_run(run: RunConfig<'_>) {1703        let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target);1704        run.builder.ensure(GccCodegenBackend::for_target(compilers, run.target));1705    }17061707    fn run(self, builder: &Builder<'_>) -> Self::Output {1708        let host = self.compilers.target();1709        let build_compiler = self.compilers.build_compiler();17101711        let stamp = build_stamp::codegen_backend_stamp(1712            builder,1713            build_compiler,1714            host,1715            &CodegenBackendKind::Gcc,1716        );17171718        if builder.config.keep_stage.contains(&build_compiler.stage) && stamp.path().exists() {1719            trace!("`keep-stage` requested");1720            builder.info(1721                "WARNING: Using a potentially old codegen backend. \1722                This may not behave well.",1723            );1724            // Codegen backends are linked separately from this step today, so we don't do1725            // anything here.1726            return GccCodegenBackendOutput { stamp };1727        }17281729        let mut cargo = builder::Cargo::new(1730            builder,1731            build_compiler,1732            Mode::Codegen,1733            SourceType::InTree,1734            host,1735            Kind::Build,1736        );1737        cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml"));1738        rustc_cargo_env(builder, &mut cargo, host);17391740        let _guard =1741            builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, host);1742        let files = run_cargo(builder, cargo, vec![], &stamp, vec![], ArtifactKeepMode::OnlyRlib);17431744        GccCodegenBackendOutput {1745            stamp: write_codegen_backend_stamp(stamp, files, builder.config.dry_run()),1746        }1747    }17481749    fn metadata(&self) -> Option<StepMetadata> {1750        Some(1751            StepMetadata::build("rustc_codegen_gcc", self.compilers.target())1752                .built_by(self.compilers.build_compiler()),1753        )1754    }1755}17561757#[derive(Debug, Clone, PartialEq, Eq, Hash)]1758pub struct CraneliftCodegenBackend {1759    pub compilers: RustcPrivateCompilers,1760}17611762impl Step for CraneliftCodegenBackend {1763    type Output = BuildStamp;1764    const IS_HOST: bool = true;17651766    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1767        run.alias("rustc_codegen_cranelift").alias("cg_clif")1768    }17691770    fn make_run(run: RunConfig<'_>) {1771        run.builder.ensure(CraneliftCodegenBackend {1772            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),1773        });1774    }17751776    fn run(self, builder: &Builder<'_>) -> Self::Output {1777        let target = self.compilers.target();1778        let build_compiler = self.compilers.build_compiler();17791780        let stamp = build_stamp::codegen_backend_stamp(1781            builder,1782            build_compiler,1783            target,1784            &CodegenBackendKind::Cranelift,1785        );17861787        if builder.config.keep_stage.contains(&build_compiler.stage) {1788            trace!("`keep-stage` requested");1789            builder.info(1790                "WARNING: Using a potentially old codegen backend. \1791                This may not behave well.",1792            );1793            // Codegen backends are linked separately from this step today, so we don't do1794            // anything here.1795            return stamp;1796        }17971798        let mut cargo = builder::Cargo::new(1799            builder,1800            build_compiler,1801            Mode::Codegen,1802            SourceType::InTree,1803            target,1804            Kind::Build,1805        );1806        cargo1807            .arg("--manifest-path")1808            .arg(builder.src.join("compiler/rustc_codegen_cranelift/Cargo.toml"));1809        rustc_cargo_env(builder, &mut cargo, target);18101811        let _guard = builder.msg(1812            Kind::Build,1813            "codegen backend cranelift",1814            Mode::Codegen,1815            build_compiler,1816            target,1817        );1818        let files = run_cargo(builder, cargo, vec![], &stamp, vec![], ArtifactKeepMode::OnlyRlib);1819        write_codegen_backend_stamp(stamp, files, builder.config.dry_run())1820    }18211822    fn metadata(&self) -> Option<StepMetadata> {1823        Some(1824            StepMetadata::build("rustc_codegen_cranelift", self.compilers.target())1825                .built_by(self.compilers.build_compiler()),1826        )1827    }1828}18291830/// Write filtered `files` into the passed build stamp and returns it.1831fn write_codegen_backend_stamp(1832    mut stamp: BuildStamp,1833    files: Vec<PathBuf>,1834    dry_run: bool,1835) -> BuildStamp {1836    if dry_run {1837        return stamp;1838    }18391840    let mut files = files.into_iter().filter(|f| {1841        let filename = f.file_name().unwrap().to_str().unwrap();1842        is_dylib(f) && filename.contains("rustc_codegen_")1843    });1844    let codegen_backend = match files.next() {1845        Some(f) => f,1846        None => panic!("no dylibs built for codegen backend?"),1847    };1848    if let Some(f) = files.next() {1849        panic!("codegen backend built two dylibs:\n{}\n{}", codegen_backend.display(), f.display());1850    }18511852    let codegen_backend = codegen_backend.to_str().unwrap();1853    stamp = stamp.add_stamp(codegen_backend);1854    t!(stamp.write());1855    stamp1856}18571858/// Creates the `codegen-backends` folder for a compiler that's about to be1859/// assembled as a complete compiler.1860///1861/// This will take the codegen artifacts recorded in the given `stamp` and link them1862/// into an appropriate location for `target_compiler` to be a functional1863/// compiler.1864fn copy_codegen_backends_to_sysroot(1865    builder: &Builder<'_>,1866    stamp: BuildStamp,1867    target_compiler: Compiler,1868) {1869    // Note that this step is different than all the other `*Link` steps in1870    // that it's not assembling a bunch of libraries but rather is primarily1871    // moving the codegen backend into place. The codegen backend of rustc is1872    // not linked into the main compiler by default but is rather dynamically1873    // selected at runtime for inclusion.1874    //1875    // Here we're looking for the output dylib of the `CodegenBackend` step and1876    // we're copying that into the `codegen-backends` folder.1877    let dst = builder.sysroot_codegen_backends(target_compiler);1878    t!(fs::create_dir_all(&dst), dst);18791880    if builder.config.dry_run() {1881        return;1882    }18831884    if stamp.path().exists() {1885        let file = get_codegen_backend_file(&stamp);1886        builder.copy_link(1887            &file,1888            &dst.join(normalize_codegen_backend_name(builder, &file)),1889            FileType::NativeLibrary,1890        );1891    }1892}18931894/// Gets the path to a dynamic codegen backend library from its build stamp.1895pub fn get_codegen_backend_file(stamp: &BuildStamp) -> PathBuf {1896    PathBuf::from(t!(fs::read_to_string(stamp.path())))1897}18981899/// Normalize the name of a dynamic codegen backend library.1900pub fn normalize_codegen_backend_name(builder: &Builder<'_>, path: &Path) -> String {1901    let filename = path.file_name().unwrap().to_str().unwrap();1902    // change e.g. `librustc_codegen_cranelift-xxxxxx.so` to1903    // `librustc_codegen_cranelift-release.so`1904    let dash = filename.find('-').unwrap();1905    let dot = filename.find('.').unwrap();1906    format!("{}-{}{}", &filename[..dash], builder.rust_release(), &filename[dot..])1907}19081909pub fn compiler_file(1910    builder: &Builder<'_>,1911    compiler: &Path,1912    target: TargetSelection,1913    c: CLang,1914    file: &str,1915) -> PathBuf {1916    if builder.config.dry_run() {1917        return PathBuf::new();1918    }1919    let mut cmd = command(compiler);1920    cmd.args(builder.cc_handled_clags(target, c));1921    cmd.args(builder.cc_unhandled_cflags(target, GitRepo::Rustc, c));1922    cmd.arg(format!("-print-file-name={file}"));1923    let out = cmd.run_capture_stdout(builder).stdout();1924    PathBuf::from(out.trim())1925}19261927#[derive(Debug, Clone, PartialEq, Eq, Hash)]1928pub struct Sysroot {1929    pub compiler: Compiler,1930    /// See [`Std::force_recompile`].1931    force_recompile: bool,1932}19331934impl Sysroot {1935    pub(crate) fn new(compiler: Compiler) -> Self {1936        Sysroot { compiler, force_recompile: false }1937    }1938}19391940impl Step for Sysroot {1941    type Output = PathBuf;19421943    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1944        run.never()1945    }19461947    /// Returns the sysroot that `compiler` is supposed to use.1948    /// For the stage0 compiler, this is stage0-sysroot (because of the initial std build).1949    /// For all other stages, it's the same stage directory that the compiler lives in.1950    fn run(self, builder: &Builder<'_>) -> PathBuf {1951        let compiler = self.compiler;1952        let host_dir = builder.out.join(compiler.host);19531954        let sysroot_dir = |stage| {1955            if stage == 0 {1956                host_dir.join("stage0-sysroot")1957            } else if self.force_recompile && stage == compiler.stage {1958                host_dir.join(format!("stage{stage}-test-sysroot"))1959            } else if builder.download_rustc() && compiler.stage != builder.top_stage {1960                host_dir.join("ci-rustc-sysroot")1961            } else {1962                host_dir.join(format!("stage{stage}"))1963            }1964        };1965        let sysroot = sysroot_dir(compiler.stage);1966        trace!(stage = ?compiler.stage, ?sysroot);19671968        builder.do_if_verbose(|| {1969            println!("Removing sysroot {} to avoid caching bugs", sysroot.display())1970        });1971        let _ = fs::remove_dir_all(&sysroot);1972        t!(fs::create_dir_all(&sysroot));19731974        // In some cases(see https://github.com/rust-lang/rust/issues/109314), when the stage01975        // compiler relies on more recent version of LLVM than the stage0 compiler, it may not1976        // be able to locate the correct LLVM in the sysroot. This situation typically occurs1977        // when we upgrade LLVM version while the stage0 compiler continues to use an older version.1978        //1979        // Make sure to add the correct version of LLVM into the stage0 sysroot.1980        if compiler.stage == 0 {1981            dist::maybe_install_llvm_target(builder, compiler.host, &sysroot);1982        }19831984        // If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0.1985        if builder.download_rustc() && compiler.stage != 0 {1986            assert_eq!(1987                builder.config.host_target, compiler.host,1988                "Cross-compiling is not yet supported with `download-rustc`",1989            );19901991            // #102002, cleanup old toolchain folders when using download-rustc so people don't use them by accident.1992            for stage in 0..=2 {1993                if stage != compiler.stage {1994                    let dir = sysroot_dir(stage);1995                    if !dir.ends_with("ci-rustc-sysroot") {1996                        let _ = fs::remove_dir_all(dir);1997                    }1998                }1999            }

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.