From 6e9afb8dde7a9810fe444efc6e0e282c23be0a24 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Mon, 27 May 2024 20:10:46 -0700 Subject: [PATCH 1/4] Enable zstd for debug compression. Set LLVM_ENABLE_ZSTD alongside LLVM_ENABLE_ZLIB so that --compress-debug-sections=zstd is an option. Use static linking to avoid a new runtime dependency. Add an llvm.libzstd bootstrap option for LLVM with zstd. Set it off by default except for the dist builder. Handle llvm-config --system-libs output that contains static libraries. --- compiler/rustc_llvm/build.rs | 29 +++++++++++++++++-- config.example.toml | 3 ++ src/bootstrap/download-ci-llvm-stamp | 2 +- src/bootstrap/src/core/build_steps/llvm.rs | 12 ++++++-- src/bootstrap/src/core/config/config.rs | 6 ++++ src/bootstrap/src/utils/change_tracker.rs | 5 ++++ .../host-x86_64/dist-x86_64-linux/Dockerfile | 1 + 7 files changed, 51 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 4c1f78e6bee34..b2ff9efb41cba 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -259,6 +259,7 @@ fn main() { cmd.args(&components); for lib in output(&mut cmd).split_whitespace() { + let mut is_static = false; let name = if let Some(stripped) = lib.strip_prefix("-l") { stripped } else if let Some(stripped) = lib.strip_prefix('-') { @@ -266,8 +267,24 @@ fn main() { } else if Path::new(lib).exists() { // On MSVC llvm-config will print the full name to libraries, but // we're only interested in the name part - let name = Path::new(lib).file_name().unwrap().to_str().unwrap(); - name.trim_end_matches(".lib") + // On Unix when we get a static library llvm-config will print the + // full name and we *are* interested in the path, but we need to + // handle it separately. For example, when statically linking to + // libzstd llvm-config will output something like + // -lrt -ldl -lm -lz /usr/local/lib/libzstd.a -lxml2 + // and we transform the zstd part into + // cargo:rustc-link-search-native=/usr/local/lib + // cargo:rustc-link-lib=static=zstd + let path = Path::new(lib); + if lib.ends_with(".a") { + is_static = true; + println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display()); + let name = path.file_stem().unwrap().to_str().unwrap(); + name.trim_start_matches("lib") + } else { + let name = path.file_name().unwrap().to_str().unwrap(); + name.trim_end_matches(".lib") + } } else if lib.ends_with(".lib") { // Some MSVC libraries just come up with `.lib` tacked on, so chop // that off @@ -285,7 +302,13 @@ fn main() { continue; } - let kind = if name.starts_with("LLVM") { llvm_kind } else { "dylib" }; + let kind = if name.starts_with("LLVM") { + llvm_kind + } else if is_static { + "static" + } else { + "dylib" + }; println!("cargo:rustc-link-lib={kind}={name}"); } diff --git a/config.example.toml b/config.example.toml index 1a7bdc4737fbf..1b7de662e84ab 100644 --- a/config.example.toml +++ b/config.example.toml @@ -87,6 +87,9 @@ # library provided by LLVM. #static-libstdcpp = false +# Enable LLVM to use zstd for compression. +#libzstd = false + # Whether to use Ninja to build LLVM. This runs much faster than make. #ninja = true diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index 258a034745134..11316004412e6 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/126298 +Last change is for: https://github.com/rust-lang/rust/pull/125642 diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 81e591be6997c..ffae245dfb578 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -368,9 +368,7 @@ impl Step for Llvm { cfg.define("LLVM_PROFDATA_FILE", path); } - // Disable zstd to avoid a dependency on libzstd.so. - cfg.define("LLVM_ENABLE_ZSTD", "OFF"); - + // Libraries for ELF section compression. if !target.is_windows() { cfg.define("LLVM_ENABLE_ZLIB", "ON"); } else { @@ -824,6 +822,14 @@ fn configure_llvm(builder: &Builder<'_>, target: TargetSelection, cfg: &mut cmak } } + // Libraries for ELF section compression. + if builder.config.llvm_libzstd { + cfg.define("LLVM_ENABLE_ZSTD", "FORCE_ON"); + cfg.define("LLVM_USE_STATIC_ZSTD", "TRUE"); + } else { + cfg.define("LLVM_ENABLE_ZSTD", "OFF"); + } + if let Some(ref linker) = builder.config.llvm_use_linker { cfg.define("LLVM_USE_LINKER", linker); } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 14beef20bad6e..263d59518b1d3 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -218,6 +218,7 @@ pub struct Config { pub llvm_thin_lto: bool, pub llvm_release_debuginfo: bool, pub llvm_static_stdcpp: bool, + pub llvm_libzstd: bool, /// `None` if `llvm_from_ci` is true and we haven't yet downloaded llvm. #[cfg(not(test))] llvm_link_shared: Cell>, @@ -878,6 +879,7 @@ define_config! { plugins: Option = "plugins", ccache: Option = "ccache", static_libstdcpp: Option = "static-libstdcpp", + libzstd: Option = "libzstd", ninja: Option = "ninja", targets: Option = "targets", experimental_targets: Option = "experimental-targets", @@ -1153,6 +1155,7 @@ impl Config { llvm_optimize: true, ninja_in_file: true, llvm_static_stdcpp: false, + llvm_libzstd: false, backtrace: true, rust_optimize: RustOptimize::Bool(true), rust_optimize_tests: true, @@ -1787,6 +1790,7 @@ impl Config { plugins, ccache, static_libstdcpp, + libzstd, ninja, targets, experimental_targets, @@ -1821,6 +1825,7 @@ impl Config { set(&mut config.llvm_thin_lto, thin_lto); set(&mut config.llvm_release_debuginfo, release_debuginfo); set(&mut config.llvm_static_stdcpp, static_libstdcpp); + set(&mut config.llvm_libzstd, libzstd); if let Some(v) = link_shared { config.llvm_link_shared.set(Some(v)); } @@ -1871,6 +1876,7 @@ impl Config { check_ci_llvm!(optimize_toml); check_ci_llvm!(thin_lto); check_ci_llvm!(release_debuginfo); + check_ci_llvm!(libzstd); check_ci_llvm!(targets); check_ci_llvm!(experimental_targets); check_ci_llvm!(clang_cl); diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index b8f70fdf6a805..84dac25188e1e 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -220,4 +220,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "For tarball sources, default value for `rust.channel` will be taken from `src/ci/channel` file.", }, + ChangeInfo { + change_id: 125642, + severity: ChangeSeverity::Info, + summary: "New option `llvm.libzstd` to control whether llvm is built with zstd support.", + }, ]; diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 4aa1a3ccc2a5d..5188035d54a46 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -79,6 +79,7 @@ ENV RUST_CONFIGURE_ARGS \ --set target.x86_64-unknown-linux-gnu.ranlib=/rustroot/bin/llvm-ranlib \ --set llvm.thin-lto=true \ --set llvm.ninja=false \ + --set llvm.libzstd=true \ --set rust.jemalloc \ --set rust.use-lld=true \ --set rust.lto=thin \ From 9f3376eaf2d25069205f033fb362d96f4ee11065 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Fri, 12 Jul 2024 09:00:05 -0700 Subject: [PATCH 2/4] Test --compress-debug-sections with rust-lld. --- .../rust-lld-compress-debug-sections/main.rs | 1 + .../rust-lld-compress-debug-sections/rmake.rs | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 tests/run-make/rust-lld-compress-debug-sections/main.rs create mode 100644 tests/run-make/rust-lld-compress-debug-sections/rmake.rs diff --git a/tests/run-make/rust-lld-compress-debug-sections/main.rs b/tests/run-make/rust-lld-compress-debug-sections/main.rs new file mode 100644 index 0000000000000..f328e4d9d04c3 --- /dev/null +++ b/tests/run-make/rust-lld-compress-debug-sections/main.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/run-make/rust-lld-compress-debug-sections/rmake.rs b/tests/run-make/rust-lld-compress-debug-sections/rmake.rs new file mode 100644 index 0000000000000..df9691ccbcf39 --- /dev/null +++ b/tests/run-make/rust-lld-compress-debug-sections/rmake.rs @@ -0,0 +1,39 @@ +// Checks the `compress-debug-sections` option on rust-lld. + +//@ needs-rust-lld +//@ only-linux +//@ ignore-cross-compile + +// FIXME: This test isn't comprehensive and isn't covering all possible combinations. + +use run_make_support::{assert_contains, cmd, llvm_readobj, run_in_tmpdir, rustc}; + +fn check_compression(compression: &str, to_find: &str) { + run_in_tmpdir(|| { + let out = rustc() + .arg("-Zlinker-features=+lld") + .arg("-Clink-self-contained=+linker") + .arg("-Zunstable-options") + .arg("-Cdebuginfo=full") + .link_arg(&format!("-Wl,--compress-debug-sections={compression}")) + .input("main.rs") + .run_unchecked(); + let stderr = out.stderr_utf8(); + if stderr.is_empty() { + llvm_readobj().arg("-t").arg("main").run().assert_stdout_contains(to_find); + } else { + assert_contains( + stderr, + format!( + "LLVM was not built with LLVM_ENABLE_{to_find} \ + or did not find {compression} at build time" + ), + ); + } + }); +} + +fn main() { + check_compression("zlib", "ZLIB"); + check_compression("zstd", "ZSTD"); +} From 7bb345e677c0c11390da69389e9da472e45844fe Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Wed, 17 Jul 2024 12:59:09 -0700 Subject: [PATCH 3/4] Add zlib and zstd dev packages for building lld. --- src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile index 9025e9bb0a3af..19683317126ab 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile @@ -17,6 +17,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config \ xz-utils \ mingw-w64 \ + zlib1g-dev \ + libzstd-dev \ && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ From 8db318cc960d3a4ddd508bdbb930304d7a967332 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Sun, 28 Jul 2024 18:36:05 +0000 Subject: [PATCH 4/4] Install zstd in dist builder image. Build libzstd from source because the EPEL package is built without fPIC. --- .../host-x86_64/dist-x86_64-linux/Dockerfile | 4 +++ src/ci/docker/scripts/zstd.sh | 29 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100755 src/ci/docker/scripts/zstd.sh diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 5188035d54a46..61e9694f1e2ae 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -62,6 +62,10 @@ COPY host-x86_64/dist-x86_64-linux/build-clang.sh /tmp/ RUN ./build-clang.sh ENV CC=clang CXX=clang++ +# rustc's LLVM needs zstd. +COPY scripts/zstd.sh /tmp/ +RUN ./zstd.sh + COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/scripts/zstd.sh b/src/ci/docker/scripts/zstd.sh new file mode 100755 index 0000000000000..a3d37ccc31120 --- /dev/null +++ b/src/ci/docker/scripts/zstd.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -ex + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/zstd_build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + "$@" &> /tmp/zstd_build.log + trap - ERR + kill $PING_LOOP_PID + rm /tmp/zstd_build.log + set -x +} + +ZSTD=1.5.6 +curl -L https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz | tar xzf - + +cd zstd-$ZSTD +CFLAGS=-fPIC hide_output make -j$(nproc) VERBOSE=1 +hide_output make install + +cd .. +rm -rf zstd-$ZSTD