diff --git a/library/Cargo.toml b/library/Cargo.toml index 788c990c16344..20b2625d6e1c2 100644 --- a/library/Cargo.toml +++ b/library/Cargo.toml @@ -2,17 +2,12 @@ cargo-features = ["profile-rustflags"] [workspace] resolver = "1" -members = [ - "std", - "sysroot", - "coretests", - "alloctests", -] +members = ["std", "sysroot", "coretests", "alloctests"] exclude = [ - # stdarch has its own Cargo workspace - "stdarch", - "windows_link" + # stdarch has its own Cargo workspace + "stdarch", + "windows_link", ] [profile.release.package.compiler_builtins] @@ -46,13 +41,43 @@ object.debug = 0 rustc-demangle.debug = 0 rustc-demangle.opt-level = "s" -# panic_abort must always be compiled with panic=abort, even when the rest of the -# sysroot is panic=unwind. -[profile.dev.package.panic_abort] -rustflags = ["-Cpanic=abort"] +[profile.dev] +rustflags = [ + # `profile.lto=off` implies `-Cembed-bitcode=no`, but unconditionally embedding + # bitcode is necessary for when users enable LTO. + # Required until Cargo can re-build the standard library based on the value + # of `profile.lto` in the user's profile. + "-Cembed-bitcode=yes", + # `std`, `alloc` and `core` imports some dependencies by #[path] (like + # backtrace, core_simd, std_float, ...), those dependencies have their own + # features but cargo isn't involved in the #[path] process and so cannot pass the + # complete list of features, so for that reason we don't enable checking of + # features for std crates. + "--check-cfg=cfg(feature,values(any()))", + # Always enable inlining MIR when building the standard library. + # Without this flag, MIR inlining is disabled when incremental compilation is enabled. + # That causes some mir-opt tests which inline functions from the standard library to + # break when incremental compilation is enabled. So this overrides the "no inlining + # during incremental builds" heuristic for the standard library. + "-Zunstable-options", + "-Zinline-mir", + # Similarly, we need to keep debug info for functions inlined into other std functions, + # even if we're not going to output debuginfo for the crate we're currently building, + # so that it'll be available when downstream consumers of std try to use it. + "-Zinline-mir-preserve-debug", + "-Zmir_strip_debuginfo=locals-in-tiny-functions", +] -[profile.release.package.panic_abort] -rustflags = ["-Cpanic=abort"] +[profile.release] +rustflags = [ + # Same as `profile.dev.rustflags` + "-Cembed-bitcode=yes", + "--check-cfg=cfg(feature,values(any()))", + "-Zunstable-options", + "-Zinline-mir", + "-Zinline-mir-preserve-debug", + "-Zmir_strip_debuginfo=locals-in-tiny-functions", +] # The "dist" profile is used by bootstrap for prebuilt libstd artifacts # These settings ensure that the prebuilt artifacts support a variety of features @@ -62,21 +87,50 @@ inherits = "release" codegen-units = 1 debug = 1 # "limited" rustflags = [ - # `profile.lto=off` implies `-Cembed-bitcode=no`, but unconditionally embedding - # bitcode is necessary for when users enable LTO. - # Required until Cargo can re-build the standard library based on the value - # of `profile.lto` in the user's profile. + # Inherited from `profile.release.rustflags` "-Cembed-bitcode=yes", + "--check-cfg=cfg(feature,values(any()))", + "-Zinline-mir", + "-Zinline-mir-preserve-debug", + "-Zmir_strip_debuginfo=locals-in-tiny-functions", + # Enable frame pointers - "-Zunstable-options", "-Cforce-frame-pointers=non-leaf", ] -[profile.dist.package.panic_abort] + +# panic_abort must always be compiled with panic=abort, even when the rest of the +# sysroot is panic=unwind. +[profile.dev.package.panic_abort] +rustflags = [ + "-Cpanic=abort", + "-Cembed-bitcode=yes", + "--check-cfg=cfg(feature,values(any()))", + "-Zinline-mir", + "-Zinline-mir-preserve-debug", + "-Zmir-strip-debuginfo=locals-in-tiny-functions", +] + +[profile.release.package.panic_abort] rustflags = [ "-Cpanic=abort", "-Cembed-bitcode=yes", + "--check-cfg=cfg(feature,values(any()))", "-Zunstable-options", + "-Zinline-mir", + "-Zinline-mir-preserve-debug", + "-Zmir_strip_debuginfo=locals-in-tiny-functions", +] + +[profile.dist.package.panic_abort] +rustflags = [ + "-Cpanic=abort", + # Inherited from `profile.dist.rustflags` + "-Cembed-bitcode=yes", + "--check-cfg=cfg(feature,values(any()))", + "-Zinline-mir", + "-Zinline-mir-preserve-debug", + "-Zmir_strip_debuginfo=locals-in-tiny-functions", "-Cforce-frame-pointers=non-leaf", ] diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 9d958f7d10078..fbcb22b910dc1 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -90,7 +90,7 @@ impl Step for Std { builder.config.cmd.kind(), ); - std_cargo(builder, target, &mut cargo, &self.crates); + std_cargo(builder, Mode::Std, target, &mut cargo, &self.crates); if matches!(builder.config.cmd, Subcommand::Fix) { // By default, cargo tries to fix all targets. Tell it not to fix tests until we've added `test` to the sysroot. cargo.arg("--lib"); @@ -137,7 +137,7 @@ impl Step for Std { Kind::Check, ); - std_cargo(builder, target, &mut cargo, &self.crates); + std_cargo(builder, Mode::Std, target, &mut cargo, &self.crates); let stamp = build_stamp::libstd_stamp(builder, build_compiler, target).with_prefix("check-test"); @@ -511,7 +511,7 @@ pub fn prepare_compiler_for_check( std_rmeta_sysroot = prepare_std(builder, build_compiler, target); build_compiler } - Mode::Std => { + Mode::Std | Mode::DistStd => { // When checking std stage N, we want to do it with the stage N compiler // Note: we don't need to build the host stdlib here, because when compiling std, the // stage 0 stdlib is used to compile build scripts and proc macros. diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index d3b533c954293..ed0d1f0a542e5 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -198,7 +198,7 @@ impl Step for Std { Kind::Clippy, ); - std_cargo(builder, target, &mut cargo, &self.crates); + std_cargo(builder, Mode::Std, target, &mut cargo, &self.crates); let _guard = builder.msg( Kind::Clippy, diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 3b497e1db923c..7bbf02d414dce 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -242,6 +242,7 @@ impl Step for Std { } target_deps.extend(self.copy_extra_objects(builder, &build_compiler, target)); + let mode = if builder.kind == Kind::Dist { Mode::DistStd } else { Mode::Std }; // We build a sysroot for mir-opt tests using the same trick that Miri does: A check build // with -Zalways-encode-mir. This frees us from the need to have a target linker, and the @@ -251,7 +252,7 @@ impl Step for Std { let mut cargo = builder::Cargo::new_for_mir_opt_tests( builder, build_compiler, - Mode::Std, + mode, SourceType::InTree, target, Kind::Check, @@ -264,12 +265,12 @@ impl Step for Std { let mut cargo = builder::Cargo::new( builder, build_compiler, - Mode::Std, + mode, SourceType::InTree, target, Kind::Build, ); - std_cargo(builder, target, &mut cargo, &self.crates); + std_cargo(builder, mode, target, &mut cargo, &self.crates); cargo }; @@ -284,7 +285,7 @@ impl Step for Std { let _guard = builder.msg( Kind::Build, format_args!("library artifacts{}", crate_description(&self.crates)), - Mode::Std, + mode, build_compiler, target, ); @@ -526,6 +527,7 @@ fn compiler_rt_for_profiler(builder: &Builder<'_>) -> PathBuf { /// and such. pub fn std_cargo( builder: &Builder<'_>, + mode: Mode, target: TargetSelection, cargo: &mut Cargo, crates: &[String], @@ -687,7 +689,7 @@ pub fn std_cargo( } } - if builder.config.rust_lto == RustcLto::Off { + if mode != Mode::DistStd && builder.config.rust_lto == RustcLto::Off { cargo.rustflag("-Clto=off"); } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index b0feea13b0485..2b708b32e6071 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1011,9 +1011,9 @@ impl Step for Analysis { } let src = builder - .stage_out(compiler, Mode::Std) + .stage_out(compiler, Mode::DistStd) .join(target) - .join(builder.cargo_dir(Mode::Std)) + .join(builder.cargo_dir(Mode::DistStd)) .join("deps") .join("save-analysis"); diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 0948742de27a7..4b258628109a8 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -815,7 +815,7 @@ fn doc_std( Kind::Doc, ); - compile::std_cargo(builder, target, &mut cargo, requested_crates); + compile::std_cargo(builder, Mode::Std, target, &mut cargo, requested_crates); cargo .arg("--no-deps") .arg("--target-dir") diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 0dd6cd0d6fc3b..2bb2c554f9677 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3313,7 +3313,7 @@ impl Step for Crate { .arg("--manifest-path") .arg(builder.src.join("library/sysroot/Cargo.toml")); } else { - compile::std_cargo(builder, target, &mut cargo, &[]); + compile::std_cargo(builder, Mode::Std, target, &mut cargo, &[]); } } Mode::Rustc => { diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 24d7a24152a32..6fee8b8276c39 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -738,7 +738,11 @@ impl Builder<'_> { // Note: Although it would seems that "-Zunstable-options" to `rustflags` is useless as // cargo would implicitly add it, it was discover that sometimes bootstrap only use // `rustflags` without `cargo` making it required. - rustflags.arg("-Zunstable-options"); + // This shouldn't be needed for DistStd unless the configuration of distributed std changes + // in the future. + if mode != Mode::DistStd { + rustflags.arg("-Zunstable-options"); + } // Add parallel frontend threads configuration if let Some(threads) = self.config.rust_parallel_frontend_threads { @@ -773,7 +777,7 @@ impl Builder<'_> { let mut rustdocflags = rustflags.clone(); match mode { - Mode::Std | Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTarget => {} + Mode::Std | Mode::DistStd | Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTarget => {} Mode::Rustc | Mode::Codegen | Mode::ToolRustcPrivate => { // Build proc macros both for the host and the target unless proc-macros are not // supported by the target. @@ -837,7 +841,9 @@ impl Builder<'_> { "binary-dep-depinfo,proc_macro_span,proc_macro_span_shrink,proc_macro_diagnostic" .to_string() } - Mode::Std | Mode::Rustc | Mode::Codegen | Mode::ToolRustcPrivate => String::new(), + Mode::Std | Mode::DistStd | Mode::Rustc | Mode::Codegen | Mode::ToolRustcPrivate => { + String::new() + } }; cargo.arg("-j").arg(self.jobs().to_string()); @@ -874,6 +880,7 @@ impl Builder<'_> { // things still build right, please do! match mode { Mode::Std => metadata.push_str("std"), + Mode::DistStd => metadata.push_str("diststd"), // When we're building rustc tools, they're built with a search path // that contains things built during the rustc build. For example, // bitflags is built during the rustc build, and is a dependency of @@ -964,42 +971,47 @@ impl Builder<'_> { cargo.env("MIRI_HOST_SYSROOT", &host_sysroot); } - cargo.env(profile_var("STRIP"), self.config.rust_strip.to_string()); + if mode != Mode::DistStd { + cargo.env(profile_var("STRIP"), self.config.rust_strip.to_string()); + } if let Some(stack_protector) = &self.config.rust_stack_protector { rustflags.arg(&format!("-Zstack-protector={stack_protector}")); } let debuginfo_level = match mode { - Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc, - Mode::Std => self.config.rust_debuginfo_level_std, + Mode::Rustc | Mode::Codegen => Some(self.config.rust_debuginfo_level_rustc), + Mode::Std => Some(self.config.rust_debuginfo_level_std), Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustcPrivate | Mode::ToolTarget => { - self.config.rust_debuginfo_level_tools + Some(self.config.rust_debuginfo_level_tools) } + Mode::DistStd => None, }; - cargo.env(profile_var("DEBUG"), debuginfo_level.to_string()); - if let Some(opt_level) = &self.config.rust_optimize.get_opt_level() { + debuginfo_level.map(|value| cargo.env(profile_var("DEBUG"), value.to_string())); + if let Some(opt_level) = &self.config.rust_optimize.get_opt_level() + && mode != Mode::DistStd + { cargo.env(profile_var("OPT_LEVEL"), opt_level); } - cargo.env( - profile_var("DEBUG_ASSERTIONS"), - match mode { - Mode::Std => self.config.std_debug_assertions, - Mode::Rustc | Mode::Codegen => self.config.rustc_debug_assertions, - Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustcPrivate | Mode::ToolTarget => { - self.config.tools_debug_assertions - } + let debug_assertions = match mode { + Mode::Std => Some(self.config.std_debug_assertions), + Mode::Rustc | Mode::Codegen => Some(self.config.rustc_debug_assertions), + Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustcPrivate | Mode::ToolTarget => { + Some(self.config.tools_debug_assertions) } - .to_string(), - ); - cargo.env( - profile_var("OVERFLOW_CHECKS"), - if mode == Mode::Std { - self.config.rust_overflow_checks_std.to_string() - } else { - self.config.rust_overflow_checks.to_string() - }, - ); + Mode::DistStd => None, + }; + debug_assertions.map(|value| cargo.env(profile_var("DEBUG_ASSERTIONS"), value.to_string())); + if mode != Mode::DistStd { + cargo.env( + profile_var("OVERFLOW_CHECKS"), + if mode == Mode::Std { + self.config.rust_overflow_checks_std.to_string() + } else { + self.config.rust_overflow_checks.to_string() + }, + ); + } match self.config.split_debuginfo(target) { SplitDebuginfo::Packed => rustflags.arg("-Csplit-debuginfo=packed"), @@ -1018,7 +1030,7 @@ impl Builder<'_> { // Any library crate that's part of the sysroot should be marked unstable // (including third-party dependencies), unless it uses a staged_api // `#![stable(..)]` attribute to explicitly mark itself stable. - Mode::Std | Mode::Codegen | Mode::Rustc => { + Mode::Std | Mode::DistStd | Mode::Codegen | Mode::Rustc => { cargo.env("RUSTC_FORCE_UNSTABLE", "1"); } @@ -1086,6 +1098,7 @@ impl Builder<'_> { } } Mode::Std + | Mode::DistStd | Mode::ToolBootstrap | Mode::ToolRustcPrivate | Mode::ToolStd @@ -1136,7 +1149,7 @@ impl Builder<'_> { // Enable usage of unstable features cargo.env("RUSTC_BOOTSTRAP", "1"); - if matches!(mode, Mode::Std) { + if mode.is_std() { cargo.arg("-Zno-embed-metadata"); } @@ -1164,7 +1177,7 @@ impl Builder<'_> { // For other crates, however, we know that we've already got a standard // library up and running, so we can use the normal compiler to compile // build scripts in that situation. - if mode == Mode::Std { + if mode.is_std() { cargo .env("RUSTC_SNAPSHOT", &self.initial_rustc) .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir()); @@ -1337,7 +1350,10 @@ impl Builder<'_> { } match (mode, self.config.rust_codegen_units_std, self.config.rust_codegen_units) { - (Mode::Std, Some(n), _) | (_, _, Some(n)) => { + (Mode::Std, Some(n), _) => { + cargo.env(profile_var("CODEGEN_UNITS"), n.to_string()); + } + (m, _, Some(n)) if m != Mode::DistStd => { cargo.env(profile_var("CODEGEN_UNITS"), n.to_string()); } _ => { @@ -1366,7 +1382,7 @@ impl Builder<'_> { // When we build Rust dylibs they're all intended for intermediate // usage, so make sure we pass the -Cprefer-dynamic flag instead of // linking all deps statically into the dylib. - if matches!(mode, Mode::Std) { + if mode.is_std() { rustflags.arg("-Cprefer-dynamic"); } if matches!(mode, Mode::Rustc) && !self.link_std_into_rustc_driver(target) { @@ -1404,19 +1420,6 @@ impl Builder<'_> { if self.config.rust_randomize_layout { rustflags.arg("--cfg=randomized_layouts"); } - // Always enable inlining MIR when building the standard library. - // Without this flag, MIR inlining is disabled when incremental compilation is enabled. - // That causes some mir-opt tests which inline functions from the standard library to - // break when incremental compilation is enabled. So this overrides the "no inlining - // during incremental builds" heuristic for the standard library. - rustflags.arg("-Zinline-mir"); - - // Similarly, we need to keep debug info for functions inlined into other std functions, - // even if we're not going to output debuginfo for the crate we're currently building, - // so that it'll be available when downstream consumers of std try to use it. - rustflags.arg("-Zinline-mir-preserve-debug"); - - rustflags.arg("-Zmir_strip_debuginfo=locals-in-tiny-functions"); } // take target-specific extra rustflags if any otherwise take `rust.rustflags` @@ -1435,7 +1438,7 @@ impl Builder<'_> { } else { match (mode, self.config.rust_optimize.is_release()) { // Some std configuration exists in its own profile - (Mode::Std, _) => Some("dist"), + (Mode::DistStd, _) => Some("dist"), (_, true) => Some("release"), (_, false) => Some("dev"), } @@ -1461,7 +1464,9 @@ impl Builder<'_> { pub fn cargo_profile_var(name: &str, config: &Config, mode: Mode) -> String { let profile = match (mode, config.rust_optimize.is_release()) { // Some std configuration exists in its own profile - (Mode::Std, _) => "DIST", + (Mode::DistStd, _) => { + panic!("Attempted to override the distributed std's profile with {name}") + } (_, true) => "RELEASE", (_, false) => "DEV", }; diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index fd3e88e1a36f4..eecd4519fe4d4 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -303,6 +303,12 @@ pub enum Mode { /// Build the standard library, placing output in the "stageN-std" directory. Std, + /// Build the standard library as intended for distribution. This involves ignoring any + /// bootstrap.toml configuration and following the defined `dist` profile/config in the + /// library workspace. This ensures that any required configuration is shared for Cargo's + /// build-std implementation. + DistStd, + /// Build librustc, and compiler libraries, placing output in the "stageN-rustc" directory. Rustc, @@ -350,7 +356,7 @@ pub enum Mode { impl Mode { pub fn must_support_dlopen(&self) -> bool { match self { - Mode::Std | Mode::Codegen => true, + Mode::Std | Mode::DistStd | Mode::Codegen => true, Mode::ToolBootstrap | Mode::ToolRustcPrivate | Mode::ToolStd @@ -358,6 +364,10 @@ impl Mode { | Mode::Rustc => false, } } + + pub fn is_std(&self) -> bool { + *self == Mode::Std || *self == Mode::DistStd + } } /// When `rust.rust_remap_debuginfo` is requested, the compiler needs to know how to @@ -909,7 +919,7 @@ impl Build { /// release/debug) fn cargo_dir(&self, mode: Mode) -> &'static str { match (mode, self.config.rust_optimize.is_release()) { - (Mode::Std, _) => "dist", + (Mode::DistStd, _) => "dist", (_, true) => "release", (_, false) => "debug", } @@ -940,7 +950,7 @@ impl Build { let (stage, suffix) = match mode { // Std is special, stage N std is built with stage N rustc - Mode::Std => (Some(build_compiler.stage), "std"), + Mode::Std | Mode::DistStd => (Some(build_compiler.stage), "std"), // The rest of things are built with stage N-1 rustc Mode::Rustc => (Some(build_compiler.stage + 1), "rustc"), Mode::Codegen => (Some(build_compiler.stage + 1), "codegen"), @@ -1146,7 +1156,7 @@ impl Build { let actual_stage = match mode.into() { // Std has the same stage as the compiler that builds it - Some(Mode::Std) => target_and_stage.stage, + Some(Mode::Std | Mode::DistStd) => target_and_stage.stage, // Other things have stage corresponding to their build compiler + 1 Some( Mode::Rustc diff --git a/src/bootstrap/src/utils/build_stamp.rs b/src/bootstrap/src/utils/build_stamp.rs index 5cd68f6d4fe7f..3623600054afa 100644 --- a/src/bootstrap/src/utils/build_stamp.rs +++ b/src/bootstrap/src/utils/build_stamp.rs @@ -7,7 +7,7 @@ use std::{fs, io}; use sha2::digest::Digest; -use crate::core::builder::Builder; +use crate::core::builder::{Builder, Kind}; use crate::core::config::TargetSelection; use crate::utils::helpers::{hex_encode, mtime}; use crate::{CodegenBackendKind, Compiler, Mode, helpers, t}; @@ -142,7 +142,8 @@ pub fn libstd_stamp( build_compiler: Compiler, target: TargetSelection, ) -> BuildStamp { - BuildStamp::new(&builder.cargo_out(build_compiler, Mode::Std, target)).with_prefix("libstd") + let mode = if builder.kind == Kind::Dist { Mode::DistStd } else { Mode::Std }; + BuildStamp::new(&builder.cargo_out(build_compiler, mode, target)).with_prefix("libstd") } /// Cargo's output path for librustc in a given stage, compiled by a particular