diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 25e2ca5948bfb..a52d2e945536e 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -697,6 +697,13 @@ # FIXME(#61117): Some tests fail when this option is enabled. #rust.debuginfo-level-tests = 0 +# Compress debuginfo of Rust and C/C++ code. +# Valid options: +# - "off" or false: disable compression +# - true: compress debuginfo with the default compression method (currently zlib) +# - "zlib": compress debuginfo with zlib +#rust.compress-debuginfo = "off" + # Should rustc and the standard library be built with split debuginfo? Default # is platform dependent. # @@ -1019,6 +1026,13 @@ # and enabling it causes issues. #split-debuginfo = if linux || windows-gnu { off } else if windows-msvc { packed } else if apple { unpacked } +# Compress debuginfo for Rust and C/C++ code of this target. +# Valid options: +# - "off" or false: disable compression +# - true: compress debuginfo with the default compression method (currently zlib) +# - "zlib": compress debuginfo with zlib +#compress-debuginfo = "off" + # Path to the `llvm-config` binary of the installation of a custom LLVM to link # against. Note that if this is specified we don't compile LLVM at all for this # target. diff --git a/src/bootstrap/defaults/bootstrap.dist.toml b/src/bootstrap/defaults/bootstrap.dist.toml index cce3f068aabcd..03e012079b079 100644 --- a/src/bootstrap/defaults/bootstrap.dist.toml +++ b/src/bootstrap/defaults/bootstrap.dist.toml @@ -26,6 +26,8 @@ download-rustc = false llvm-bitcode-linker = true # Required to make builds reproducible. remap-debuginfo = true +# Compress debuginfo in generated artifacts to reduce their size +compress-debuginfo = "zlib" [dist] # Use better compression when preparing tarballs. diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index e7fe8bd1f3858..f495f0f209750 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -5,8 +5,8 @@ use std::path::{Path, PathBuf}; use super::{Builder, Kind}; use crate::core::build_steps::test; use crate::core::build_steps::tool::SourceType; -use crate::core::config::SplitDebuginfo; use crate::core::config::flags::Color; +use crate::core::config::{CompressDebuginfo, SplitDebuginfo}; use crate::utils::build_stamp; use crate::utils::helpers::{self, LldThreads, check_cfg_arg, linker_flags}; use crate::{ @@ -340,8 +340,18 @@ impl Cargo { self.rustdocflags.arg(&arg); } - if !builder.config.dry_run() && builder.cc[&target].args().iter().any(|arg| arg == "-gz") { - self.rustflags.arg("-Clink-arg=-gz"); + if !builder.config.dry_run() { + match builder.config.compress_debuginfo(target) { + CompressDebuginfo::Zlib => { + // Do not enable Zlib compression on: + // - Windows, because MSVC/PDB doesn't support it + // - macOS, because its linker doesn't know the flag + if !self.target.is_windows() && !self.target.is_apple() { + self.rustflags.arg("-Clink-arg=-Wl,--compress-debug-sections=zlib"); + } + } + CompressDebuginfo::Off => {} + } } // Ignore linker warnings for now. These are complicated to fix and don't affect the build. diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 5a9c7264c006f..ed5dd9c9ee9fa 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -49,8 +49,8 @@ use crate::core::config::toml::target::{ DefaultLinuxLinkerOverride, Target, TomlTarget, default_linux_linker_overrides, }; use crate::core::config::{ - CompilerBuiltins, DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, ReplaceOpt, - RustcLto, SplitDebuginfo, StringOrBool, threads_from_config, + CompilerBuiltins, CompressDebuginfo, DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, + ReplaceOpt, RustcLto, SplitDebuginfo, StringOrBool, threads_from_config, }; use crate::core::download::{ DownloadContext, download_beta_toolchain, is_download_ci_available, maybe_download_rustfmt, @@ -210,6 +210,7 @@ pub struct Config { pub rust_debuginfo_level_std: DebuginfoLevel, pub rust_debuginfo_level_tools: DebuginfoLevel, pub rust_debuginfo_level_tests: DebuginfoLevel, + pub rust_compress_debuginfo: CompressDebuginfo, pub rust_rpath: bool, pub rust_strip: bool, pub rust_frame_pointers: bool, @@ -550,6 +551,7 @@ impl Config { debuginfo_level_std: rust_debuginfo_level_std, debuginfo_level_tools: rust_debuginfo_level_tools, debuginfo_level_tests: rust_debuginfo_level_tests, + compress_debuginfo: rust_compress_debuginfo, backtrace: rust_backtrace, incremental: rust_incremental, randomize_layout: rust_randomize_layout, @@ -1469,6 +1471,7 @@ impl Config { .unwrap_or(vec![CodegenBackendKind::Llvm]), rust_codegen_units: rust_codegen_units.map(threads_from_config), rust_codegen_units_std: rust_codegen_units_std.map(threads_from_config), + rust_compress_debuginfo: rust_compress_debuginfo.unwrap_or_default(), rust_debug_logging: rust_debug_logging .or(rust_rustc_debug_assertions) .unwrap_or(rust_debug == Some(true)), @@ -1925,6 +1928,13 @@ impl Config { .unwrap_or_else(|| SplitDebuginfo::default_for_platform(target)) } + pub fn compress_debuginfo(&self, target: TargetSelection) -> CompressDebuginfo { + self.target_config + .get(&target) + .and_then(|t| t.compress_debuginfo) + .unwrap_or(self.rust_compress_debuginfo) + } + /// Checks if the given target is the same as the host target. pub fn is_host_target(&self, target: TargetSelection) -> bool { self.host_target == target diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index 7651def62672a..c29849cf5a5d6 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -32,6 +32,7 @@ use std::path::PathBuf; use build_helper::exit; pub use config::*; +use serde::de::Unexpected; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; pub use target_selection::TargetSelection; @@ -378,6 +379,53 @@ impl std::str::FromStr for SplitDebuginfo { } } +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)] +pub enum CompressDebuginfo { + Zlib, + #[default] + Off, +} + +impl CompressDebuginfo { + fn default_on() -> Self { + Self::Zlib + } +} + +impl std::str::FromStr for CompressDebuginfo { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "zlib" => Ok(CompressDebuginfo::Zlib), + "off" => Ok(CompressDebuginfo::Off), + _ => Err(()), + } + } +} + +impl<'de> Deserialize<'de> for CompressDebuginfo { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use serde::de::Error; + + Ok(match Deserialize::deserialize(deserializer)? { + StringOrBool::Bool(value) => { + if value { + CompressDebuginfo::default_on() + } else { + CompressDebuginfo::Off + } + } + StringOrBool::String(value) => CompressDebuginfo::from_str(&value).map_err(|_| { + D::Error::invalid_value(Unexpected::Str(&value), &"`zlib` or `off`") + })?, + }) + } +} + /// Describes how to handle conflicts in merging two `TomlConfig` #[derive(Copy, Clone, Debug)] pub enum ReplaceOpt { diff --git a/src/bootstrap/src/core/config/target_selection.rs b/src/bootstrap/src/core/config/target_selection.rs index 8457607b897dd..39bf2890017fa 100644 --- a/src/bootstrap/src/core/config/target_selection.rs +++ b/src/bootstrap/src/core/config/target_selection.rs @@ -82,6 +82,10 @@ impl TargetSelection { self.contains("windows") } + pub fn is_apple(&self) -> bool { + self.contains("apple") + } + pub fn is_windows_gnu(&self) -> bool { self.ends_with("windows-gnu") } diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index a872671343405..f190eec3761ed 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -5,7 +5,7 @@ use build_helper::ci::CiEnv; use serde::{Deserialize, Deserializer}; use crate::core::config::toml::TomlConfig; -use crate::core::config::{DebuginfoLevel, Merge, ReplaceOpt, StringOrBool}; +use crate::core::config::{CompressDebuginfo, DebuginfoLevel, Merge, ReplaceOpt, StringOrBool}; use crate::{BTreeSet, CodegenBackendKind, HashSet, PathBuf, TargetSelection, define_config, exit}; define_config! { @@ -28,6 +28,7 @@ define_config! { debuginfo_level_std: Option = "debuginfo-level-std", debuginfo_level_tools: Option = "debuginfo-level-tools", debuginfo_level_tests: Option = "debuginfo-level-tests", + compress_debuginfo: Option = "compress-debuginfo", backtrace: Option = "backtrace", incremental: Option = "incremental", default_linker: Option = "default-linker", @@ -322,6 +323,7 @@ pub fn check_incompatible_options_for_ci_rustc( randomize_layout, debug_logging, debuginfo_level_rustc, + compress_debuginfo, llvm_tools, llvm_bitcode_linker, stack_protector, @@ -389,6 +391,7 @@ pub fn check_incompatible_options_for_ci_rustc( err!(current_rust_config.optimize, optimize, "rust"); err!(current_rust_config.randomize_layout, randomize_layout, "rust"); + err!(current_rust_config.compress_debuginfo, compress_debuginfo, "rust"); err!(current_rust_config.debug_logging, debug_logging, "rust"); err!(current_rust_config.debuginfo_level_rustc, debuginfo_level_rustc, "rust"); err!(current_rust_config.rpath, rpath, "rust"); diff --git a/src/bootstrap/src/core/config/toml/target.rs b/src/bootstrap/src/core/config/toml/target.rs index 847b75e696b47..311d9add9a144 100644 --- a/src/bootstrap/src/core/config/toml/target.rs +++ b/src/bootstrap/src/core/config/toml/target.rs @@ -15,7 +15,8 @@ use serde::de::Error; use serde::{Deserialize, Deserializer}; use crate::core::config::{ - CompilerBuiltins, LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, StringOrBool, + CompilerBuiltins, CompressDebuginfo, LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, + StringOrBool, }; use crate::{CodegenBackendKind, HashSet, PathBuf, define_config, exit}; @@ -68,6 +69,7 @@ pub struct Target { pub default_linker_linux_override: DefaultLinuxLinkerOverride, pub linker: Option, pub split_debuginfo: Option, + pub compress_debuginfo: Option, pub sanitizers: Option, pub profiler: Option, pub rpath: Option, diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index d010226f0dfdb..320dfcc4e69ed 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -25,7 +25,7 @@ use std::collections::HashSet; use std::iter; use std::path::{Path, PathBuf}; -use crate::core::config::TargetSelection; +use crate::core::config::{CompressDebuginfo, TargetSelection}; use crate::utils::exec::{BootstrapCommand, command}; use crate::{Build, CLang, GitRepo}; @@ -36,10 +36,18 @@ fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build { .opt_level(2) .warnings(false) .debug(false) - // Compress debuginfo - .flag_if_supported("-gz") + // We have to configure out_dir, otherwise flag_if_supported will not work + .out_dir(build.tempdir().join("cc-rs-out-dir")) .target(&target.triple) .host(&build.host_target.triple); + + match build.config.compress_debuginfo(target) { + CompressDebuginfo::Zlib => { + cfg.flag_if_supported("-gz"); + } + CompressDebuginfo::Off => {} + } + match build.crt_static(target) { Some(a) => { cfg.static_crt(a); @@ -100,17 +108,15 @@ pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) { let config = build.config.target_config.get(&target); if let Some(cc) = config .and_then(|c| c.cc.clone()) - .or_else(|| default_compiler(&mut cfg, Language::C, target, build)) + .or_else(|| default_compiler(&cfg, Language::C, target, build)) { cfg.compiler(cc); } let compiler = cfg.get_compiler(); - let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) { - ar - } else { - cfg.try_get_archiver().map(|c| PathBuf::from(c.get_program())).ok() - }; + let ar = config + .and_then(|c| c.ar.clone()) + .or_else(|| cfg.try_get_archiver().map(|c| PathBuf::from(c.get_program())).ok()); build.cc.insert(target, compiler.clone()); let mut cflags = build.cc_handled_clags(target, CLang::C); @@ -122,7 +128,7 @@ pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) { cfg.cpp(true); let cxx_configured = if let Some(cxx) = config .and_then(|c| c.cxx.clone()) - .or_else(|| default_compiler(&mut cfg, Language::CPlusPlus, target, build)) + .or_else(|| default_compiler(&cfg, Language::CPlusPlus, target, build)) { cfg.compiler(cxx); true @@ -158,7 +164,7 @@ pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) { /// Determines the default compiler for a given target and language when not explicitly /// configured in `bootstrap.toml`. fn default_compiler( - cfg: &mut cc::Build, + cfg: &cc::Build, compiler: Language, target: TargetSelection, build: &Build, diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs index a6233e6b61c1f..30757a39caa1c 100644 --- a/src/bootstrap/src/utils/cc_detect/tests.rs +++ b/src/bootstrap/src/utils/cc_detect/tests.rs @@ -86,7 +86,7 @@ fn test_default_compiler_wasi() { build.wasi_sdk_path = Some(wasi_sdk.clone()); let mut cfg = cc::Build::new(); - if let Some(result) = default_compiler(&mut cfg, Language::C, target.clone(), &build) { + if let Some(result) = default_compiler(&cfg, Language::C, target.clone(), &build) { let expected = { let compiler = format!("{}-clang", target.triple); wasi_sdk.join("bin").join(compiler) @@ -105,7 +105,7 @@ fn test_default_compiler_fallback() { let build = Build::new(config); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let mut cfg = cc::Build::new(); - let result = default_compiler(&mut cfg, Language::C, target, &build); + let result = default_compiler(&cfg, Language::C, target, &build); assert!(result.is_none(), "default_compiler should return None for generic targets"); } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 566ad003ebe01..b34c1b55700f8 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -631,4 +631,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "New `--verbose-run-make-subprocess-output` flag for `x.py test` (defaults to true). Set `--verbose-run-make-subprocess-output=false` to suppress verbose subprocess output for passing run-make tests when using `--no-capture`.", }, + ChangeInfo { + change_id: 158169, + severity: ChangeSeverity::Info, + summary: "New option `rust.compress-debuginfo` allows configuring whether Rust and C/C++ debuginfo should be compressed.", + }, ]; diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile index 5ab44df7a8033..48be0b9f96e9d 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile @@ -28,6 +28,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils \ libssl-dev \ pkg-config \ + zlib1g-dev \ && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ diff --git a/src/ci/run.sh b/src/ci/run.sh index 18b5bf2e2bbb3..883cc20ba0014 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -145,6 +145,8 @@ if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then fi else RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo=false" + # No need to compress debuginfo for tests, and we do not want to depend on zlib + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.compress-debuginfo=off" # We almost always want debug assertions enabled, but sometimes this takes too # long for too little benefit, so we just turn them off.