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.