Skip to content

Commit 66e31b8

Browse files
committed
Auto merge of #128935 - lqd:needs-zstd, r=<try>
More work on `zstd` compression r? `@Kobzol` as we've discussed this. This is a draft to show the current approach of supporting zstd in compiletest, and making the tests using it unconditional. Knowing whether llvm/lld was built with `LLVM_ENABLE_ZSTD` is quite hard, so there are two strategies. There are details in the code, and we can discuss this approach. Until we know the config used to build CI artifacts, it seems our options are somewhat limited in any case. zlib compression seems always enabled, so we only check this in its dedicated test, allowing the test to ignore errors due to zstd not being supported. The zstd test is made unconditional in what it tests, by relying on `needs-llvm-zstd` to be ignored when `llvm.libzstd` isn't enabled in `config.toml`. try-job: x86_64-gnu
2 parents 5e5ec8a + 7427683 commit 66e31b8

File tree

12 files changed

+163
-62
lines changed

12 files changed

+163
-62
lines changed

.gitmodules

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
shallow = true
3333
[submodule "src/llvm-project"]
3434
path = src/llvm-project
35-
url = https://github.com/rust-lang/llvm-project.git
36-
branch = rustc/19.1-2024-07-30
35+
url = https://github.com/lqd/llvm-project.git
36+
branch = bruh
3737
shallow = true
3838
[submodule "src/doc/embedded-book"]
3939
path = src/doc/embedded-book

src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile

+3-3
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ COPY host-x86_64/dist-x86_64-linux/build-clang.sh /tmp/
6262
RUN ./build-clang.sh
6363
ENV CC=clang CXX=clang++
6464

65-
# rustc's LLVM needs zstd.
66-
COPY scripts/zstd.sh /tmp/
67-
RUN ./zstd.sh
65+
# Build zstd to enable `llvm.libzstd`.
66+
COPY host-x86_64/dist-x86_64-linux/build-zstd.sh /tmp/
67+
RUN ./build-zstd.sh
6868

6969
COPY scripts/sccache.sh /scripts/
7070
RUN sh /scripts/sccache.sh

src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
1818
xz-utils \
1919
mingw-w64 \
2020
zlib1g-dev \
21-
libzstd-dev \
2221
&& rm -rf /var/lib/apt/lists/*
2322

2423
COPY scripts/sccache.sh /scripts/

src/llvm-project

Submodule llvm-project updated 169 files

src/tools/compiletest/src/command-list.rs

+1
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
138138
"needs-force-clang-based-tests",
139139
"needs-git-hash",
140140
"needs-llvm-components",
141+
"needs-llvm-zstd",
141142
"needs-profiler-support",
142143
"needs-relocation-model-pic",
143144
"needs-run-enabled",

src/tools/compiletest/src/header.rs

+101
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,107 @@ pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option<u32> {
12031203
None
12041204
}
12051205

1206+
/// For tests using the `needs-llvm-zstd` directive:
1207+
/// - for local LLVM builds, try to find the static zstd library in the llvm-config system libs.
1208+
/// - for `download-ci-llvm`, see if `lld` was built with zstd support.
1209+
pub fn llvm_has_libzstd(config: &Config) -> bool {
1210+
// Strategy 1: works for local builds but not with `download-ci-llvm`.
1211+
//
1212+
// We check whether `llvm-config` returns the zstd library. Bootstrap's `llvm.libzstd` will only
1213+
// ask to statically link it when building LLVM, so we only check if the list of system libs
1214+
// contains a path to that static lib, and that it exists.
1215+
//
1216+
// See compiler/rustc_llvm/build.rs for more details and similar expectations.
1217+
fn is_zstd_in_config(llvm_bin_dir: &Path) -> Option<()> {
1218+
let llvm_config_path = llvm_bin_dir.join("llvm-config");
1219+
let output = Command::new(llvm_config_path).arg("--system-libs").output().ok()?;
1220+
assert!(output.status.success(), "running llvm-config --system-libs failed");
1221+
1222+
let libs = String::from_utf8(output.stdout).ok()?;
1223+
for lib in libs.split_whitespace() {
1224+
if lib.ends_with("libzstd.a") && Path::new(lib).exists() {
1225+
return Some(());
1226+
}
1227+
}
1228+
1229+
None
1230+
}
1231+
1232+
// Strategy 2: `download-ci-llvm`'s `llvm-config --system-libs` will not return any libs to
1233+
// use.
1234+
//
1235+
// The CI artifacts also don't contain the bootstrap config used to build them: otherwise we
1236+
// could have looked at the `llvm.libzstd` config.
1237+
//
1238+
// We infer whether `LLVM_ENABLE_ZSTD` was used to build LLVM as a byproduct of testing whether
1239+
// `lld` supports it. If not, an error will be emitted: "LLVM was not built with
1240+
// LLVM_ENABLE_ZSTD or did not find zstd at build time".
1241+
#[cfg(unix)]
1242+
fn is_lld_built_with_zstd(llvm_bin_dir: &Path) -> Option<()> {
1243+
let lld_path = llvm_bin_dir.join("lld");
1244+
if lld_path.exists() {
1245+
// We can't call `lld` as-is, it expects to be invoked by a compiler driver using a
1246+
// different name. Prepare a temporary symlink to do that.
1247+
let lld_symlink_path = llvm_bin_dir.join("ld.lld");
1248+
if !lld_symlink_path.exists() {
1249+
std::os::unix::fs::symlink(lld_path, &lld_symlink_path).ok()?;
1250+
}
1251+
1252+
// Run `lld` with a zstd flag. We expect this command to always error here, we don't
1253+
// want to link actual files and don't pass any.
1254+
let output = Command::new(&lld_symlink_path)
1255+
.arg("--compress-debug-sections=zstd")
1256+
.output()
1257+
.ok()?;
1258+
assert!(!output.status.success());
1259+
1260+
// Look for a specific error caused by LLVM not being built with zstd support. We could
1261+
// also look for the "no input files" message, indicating the zstd flag was accepted.
1262+
let stderr = String::from_utf8(output.stderr).ok()?;
1263+
let zstd_available = !stderr.contains("LLVM was not built with LLVM_ENABLE_ZSTD");
1264+
1265+
// We don't particularly need to clean the link up (so the previous commands could fail
1266+
// in theory but won't in practice), but we can try.
1267+
std::fs::remove_file(lld_symlink_path).ok()?;
1268+
1269+
if zstd_available {
1270+
return Some(());
1271+
}
1272+
}
1273+
1274+
None
1275+
}
1276+
1277+
#[cfg(not(unix))]
1278+
fn is_lld_built_with_zstd(llvm_bin_dir: &Path) -> Option<()> {
1279+
None
1280+
}
1281+
1282+
if let Some(llvm_bin_dir) = &config.llvm_bin_dir {
1283+
// Strategy 1: for local LLVM builds.
1284+
if is_zstd_in_config(llvm_bin_dir).is_some() {
1285+
return true;
1286+
}
1287+
1288+
// Strategy 2: for LLVM artifacts built on CI via `download-ci-llvm`.
1289+
//
1290+
// It doesn't work for cases where the artifacts don't contain the linker, but it's
1291+
// best-effort: CI has `llvm.libzstd` and `lld` enabled on the x64 linux artifacts, so it
1292+
// will at least work there.
1293+
//
1294+
// If this can be improved and expanded to less common cases in the future, it should.
1295+
if config.target == "x86_64-unknown-linux-gnu"
1296+
&& config.host == config.target
1297+
&& is_lld_built_with_zstd(llvm_bin_dir).is_some()
1298+
{
1299+
return true;
1300+
}
1301+
}
1302+
1303+
// Otherwise, all hope is lost.
1304+
false
1305+
}
1306+
12061307
/// Takes a directive of the form "<version1> [- <version2>]",
12071308
/// returns the numeric representation of <version1> and <version2> as
12081309
/// tuple: (<version1> as u32, <version2> as u32)

src/tools/compiletest/src/header/needs.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::common::{Config, Debugger, Sanitizer};
2-
use crate::header::IgnoreDecision;
2+
use crate::header::{llvm_has_libzstd, IgnoreDecision};
33

44
pub(super) fn handle_needs(
55
cache: &CachedNeedsConditions,
@@ -149,6 +149,11 @@ pub(super) fn handle_needs(
149149
condition: cache.symlinks,
150150
ignore_reason: "ignored if symlinks are unavailable",
151151
},
152+
Need {
153+
name: "needs-llvm-zstd",
154+
condition: cache.llvm_zstd,
155+
ignore_reason: "ignored if LLVM wasn't build with zstd for ELF section compression",
156+
},
152157
];
153158

154159
let (name, comment) = match ln.split_once([':', ' ']) {
@@ -174,7 +179,7 @@ pub(super) fn handle_needs(
174179
} else {
175180
return IgnoreDecision::Ignore {
176181
reason: if let Some(comment) = comment {
177-
format!("{} ({comment})", need.ignore_reason)
182+
format!("{} ({})", need.ignore_reason, comment.trim())
178183
} else {
179184
need.ignore_reason.into()
180185
},
@@ -215,6 +220,8 @@ pub(super) struct CachedNeedsConditions {
215220
rust_lld: bool,
216221
dlltool: bool,
217222
symlinks: bool,
223+
/// Whether LLVM built with zstd, for the `needs-llvm-zstd` directive.
224+
llvm_zstd: bool,
218225
}
219226

220227
impl CachedNeedsConditions {
@@ -258,6 +265,7 @@ impl CachedNeedsConditions {
258265
.join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" })
259266
.exists(),
260267

268+
llvm_zstd: llvm_has_libzstd(&config),
261269
dlltool: find_dlltool(&config),
262270
symlinks: has_symlinks(),
263271
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Checks debuginfo compression both for the always-enabled zlib, and when the optional zstd is
2+
// enabled:
3+
// - via rustc's `debuginfo-compression`,
4+
// - and via rust-lld's `compress-debug-sections`
5+
6+
//@ needs-llvm-zstd: we want LLVM/LLD to be built with zstd support
7+
//@ needs-rust-lld: the system linker will most likely not support zstd
8+
//@ only-linux
9+
//@ ignore-cross-compile
10+
11+
use run_make_support::{llvm_readobj, run_in_tmpdir, Rustc};
12+
13+
fn check_compression(compression: &str, to_find: &str) {
14+
// check compressed debug sections via rustc flag
15+
prepare_and_check(to_find, |rustc| {
16+
rustc.arg(&format!("-Zdebuginfo-compression={compression}"))
17+
});
18+
19+
// check compressed debug sections via rust-lld flag
20+
prepare_and_check(to_find, |rustc| {
21+
rustc.link_arg(&format!("-Wl,--compress-debug-sections={compression}"))
22+
});
23+
}
24+
25+
fn prepare_and_check<F: FnOnce(&mut Rustc) -> &mut Rustc>(to_find: &str, prepare_rustc: F) {
26+
run_in_tmpdir(|| {
27+
let mut rustc = Rustc::new();
28+
rustc
29+
.arg("-Zlinker-features=+lld")
30+
.arg("-Clink-self-contained=+linker")
31+
.arg("-Zunstable-options")
32+
.arg("-Cdebuginfo=full")
33+
.input("main.rs");
34+
prepare_rustc(&mut rustc).run();
35+
llvm_readobj().arg("-t").arg("main").run().assert_stdout_contains(to_find);
36+
});
37+
}
38+
39+
fn main() {
40+
check_compression("zlib", "ZLIB");
41+
check_compression("zstd", "ZSTD");
42+
}
+3-14
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
// Checks the `debuginfo-compression` option.
1+
// Checks the always enabled `debuginfo-compression` option: zlib.
22

33
//@ only-linux
44
//@ ignore-cross-compile
55

6-
// FIXME: This test isn't comprehensive and isn't covering all possible combinations.
7-
8-
use run_make_support::{assert_contains, cmd, llvm_readobj, run_in_tmpdir, rustc};
6+
use run_make_support::{llvm_readobj, run_in_tmpdir, rustc};
97

108
fn check_compression(compression: &str, to_find: &str) {
119
run_in_tmpdir(|| {
@@ -17,19 +15,10 @@ fn check_compression(compression: &str, to_find: &str) {
1715
.arg(&format!("-Zdebuginfo-compression={compression}"))
1816
.input("foo.rs")
1917
.run();
20-
let stderr = out.stderr_utf8();
21-
if stderr.is_empty() {
22-
llvm_readobj().arg("-t").arg("foo.o").run().assert_stdout_contains(to_find);
23-
} else {
24-
assert_contains(
25-
stderr,
26-
format!("unknown debuginfo compression algorithm {compression}"),
27-
);
28-
}
18+
llvm_readobj().arg("-t").arg("foo.o").run().assert_stdout_contains(to_find);
2919
});
3020
}
3121

3222
fn main() {
3323
check_compression("zlib", "ZLIB");
34-
check_compression("zstd", "ZSTD");
3524
}

tests/run-make/rust-lld-compress-debug-sections/rmake.rs

-39
This file was deleted.

0 commit comments

Comments
 (0)