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