Skip to content

Commit 7b157b7

Browse files
committed
Auto merge of #131917 - jieyouxu:rmake-clang, r=<try>
Run the full stage 2 `run-make` test suite in `x86_64-gnu-debug` Run the full `run-make` test suite in the `x86_64-gnu-debug` CI job. This is currently the *only* CI job where `//@ needs-force-clang-based-test` will be satisfied, so some `run-make` tests will literally never be run otherwise. Before this PR, the CI job only ran `run-make` tests which contains the substring `clang` in its test name, which is both (1) a footgun because it's very easy to forget and (2) it masks tests that would otherwise fail (even failing to compile) because the test is skipped if doesn't have a `clang` in its test name. With the environment of `x86_64-gnu-debug`, two `run-make` tests failed before this PR: 1. `tests/run-make/issue-84395-lto-embed-bitcode/rmake.rs`: this was broken for a long time because `objcopy` in llvm bin tools was renamed to `llvm-objcopy`. This test was converted into a rmake.rs test, rather straight forward. 2. `tests/run-make/cross-lang-lto-riscv-abi/rmake.rs`: this was broken for a long time and never worked. The old version inspected human-readable output of `llvm-readobj --file-header` looking for substring `EF_RISCV_FLOAT_ABI_DOUBLE`, but the human-readable output will only contain something like `Flags: 0x5, RVC, double-float ABI`, hence it will never match. This test was fixed by instead using the `object` crate to actually decode the ELF headers looking for the specific `e_flags` based on reading the RISCV ELF psABI docs. This PR is best reviewed commit-by-commit, two commits setup the support library for functionality and two commits are for each of the failing `run-make` tests. try-job: x86_64-gnu-debug
2 parents 916e9ce + 03c7f99 commit 7b157b7

File tree

9 files changed

+183
-46
lines changed

9 files changed

+183
-46
lines changed

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

+1-3
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,7 @@ ENV RUST_CONFIGURE_ARGS \
4949
# (without necessarily testing the result).
5050
# - That the tests with `//@ needs-force-clang-based-tests` pass, since they
5151
# don't run by default unless RUSTBUILD_FORCE_CLANG_BASED_TESTS is set.
52-
# - FIXME(https://github.com/rust-lang/rust/pull/126155#issuecomment-2156314273):
53-
# Currently we only run the subset of tests with "clang" in their name.
5452

5553
ENV SCRIPT \
5654
python3 ../x.py --stage 2 build && \
57-
python3 ../x.py --stage 2 test tests/run-make --test-args clang
55+
python3 ../x.py --stage 2 test tests/run-make

src/ci/github-actions/jobs.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,9 @@ auto:
253253
<<: *job-linux-4c
254254

255255
- image: x86_64-gnu-debug
256-
<<: *job-linux-4c
256+
# This seems to be needed because a full stage 2 build + run-make tests
257+
# overwhelms the storage capacity of the standard 4c runner.
258+
<<: *job-linux-4c-largedisk
257259

258260
- image: x86_64-gnu-distcheck
259261
<<: *job-linux-8c

src/tools/run-make-support/src/command.rs

+18
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,12 @@ pub struct CompletedProcess {
222222
}
223223

224224
impl CompletedProcess {
225+
#[must_use]
226+
#[track_caller]
227+
pub fn stdout(&self) -> Vec<u8> {
228+
self.output.stdout.clone()
229+
}
230+
225231
#[must_use]
226232
#[track_caller]
227233
pub fn stdout_utf8(&self) -> String {
@@ -234,12 +240,24 @@ impl CompletedProcess {
234240
String::from_utf8_lossy(&self.output.stdout.clone()).to_string()
235241
}
236242

243+
#[must_use]
244+
#[track_caller]
245+
pub fn stderr(&self) -> Vec<u8> {
246+
self.output.stderr.clone()
247+
}
248+
237249
#[must_use]
238250
#[track_caller]
239251
pub fn stderr_utf8(&self) -> String {
240252
String::from_utf8(self.output.stderr.clone()).expect("stderr is not valid UTF-8")
241253
}
242254

255+
#[must_use]
256+
#[track_caller]
257+
pub fn invalid_stderr_utf8(&self) -> String {
258+
String::from_utf8_lossy(&self.output.stderr.clone()).to_string()
259+
}
260+
243261
#[must_use]
244262
pub fn status(&self) -> ExitStatus {
245263
self.output.status

src/tools/run-make-support/src/external_deps/llvm.rs

+66
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,18 @@ pub fn llvm_pdbutil() -> LlvmPdbutil {
6060
LlvmPdbutil::new()
6161
}
6262

63+
/// Construct a new `llvm-dis` invocation. This assumes that `llvm-dis` is available
64+
/// at `$LLVM_BIN_DIR/llvm-dis`.
65+
pub fn llvm_dis() -> LlvmDis {
66+
LlvmDis::new()
67+
}
68+
69+
/// Construct a new `llvm-objcopy` invocation. This assumes that `llvm-objcopy` is available
70+
/// at `$LLVM_BIN_DIR/llvm-objcopy`.
71+
pub fn llvm_objcopy() -> LlvmObjcopy {
72+
LlvmObjcopy::new()
73+
}
74+
6375
/// A `llvm-readobj` invocation builder.
6476
#[derive(Debug)]
6577
#[must_use]
@@ -123,6 +135,20 @@ pub struct LlvmPdbutil {
123135
cmd: Command,
124136
}
125137

138+
/// A `llvm-dis` invocation builder.
139+
#[derive(Debug)]
140+
#[must_use]
141+
pub struct LlvmDis {
142+
cmd: Command,
143+
}
144+
145+
/// A `llvm-objcopy` invocation builder.
146+
#[derive(Debug)]
147+
#[must_use]
148+
pub struct LlvmObjcopy {
149+
cmd: Command,
150+
}
151+
126152
crate::macros::impl_common_helpers!(LlvmReadobj);
127153
crate::macros::impl_common_helpers!(LlvmProfdata);
128154
crate::macros::impl_common_helpers!(LlvmFilecheck);
@@ -132,6 +158,8 @@ crate::macros::impl_common_helpers!(LlvmNm);
132158
crate::macros::impl_common_helpers!(LlvmBcanalyzer);
133159
crate::macros::impl_common_helpers!(LlvmDwarfdump);
134160
crate::macros::impl_common_helpers!(LlvmPdbutil);
161+
crate::macros::impl_common_helpers!(LlvmDis);
162+
crate::macros::impl_common_helpers!(LlvmObjcopy);
135163

136164
/// Generate the path to the bin directory of LLVM.
137165
#[must_use]
@@ -390,3 +418,41 @@ impl LlvmPdbutil {
390418
self
391419
}
392420
}
421+
422+
impl LlvmObjcopy {
423+
/// Construct a new `llvm-objcopy` invocation. This assumes that `llvm-objcopy` is available
424+
/// at `$LLVM_BIN_DIR/llvm-objcopy`.
425+
pub fn new() -> Self {
426+
let llvm_objcopy = llvm_bin_dir().join("llvm-objcopy");
427+
let cmd = Command::new(llvm_objcopy);
428+
Self { cmd }
429+
}
430+
431+
/// Dump the contents of `section` into the file at `path`.
432+
#[track_caller]
433+
pub fn dump_section<S: AsRef<str>, P: AsRef<Path>>(
434+
&mut self,
435+
section_name: S,
436+
path: P,
437+
) -> &mut Self {
438+
self.cmd.arg("--dump-section");
439+
self.cmd.arg(format!("{}={}", section_name.as_ref(), path.as_ref().to_str().unwrap()));
440+
self
441+
}
442+
}
443+
444+
impl LlvmDis {
445+
/// Construct a new `llvm-dis` invocation. This assumes that `llvm-dis` is available
446+
/// at `$LLVM_BIN_DIR/llvm-dis`.
447+
pub fn new() -> Self {
448+
let llvm_dis = llvm_bin_dir().join("llvm-dis");
449+
let cmd = Command::new(llvm_dis);
450+
Self { cmd }
451+
}
452+
453+
/// Provide an input file.
454+
pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
455+
self.cmd.arg(path.as_ref());
456+
self
457+
}
458+
}

src/tools/run-make-support/src/lib.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,17 @@ pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rust
4949

5050
// These rely on external dependencies.
5151
pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc};
52-
pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_optimized, build_native_static_lib_cxx};
52+
pub use c_build::{
53+
build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_cxx,
54+
build_native_static_lib_optimized,
55+
};
5356
pub use cargo::cargo;
5457
pub use clang::{clang, Clang};
5558
pub use htmldocck::htmldocck;
5659
pub use llvm::{
57-
llvm_ar, llvm_bcanalyzer, llvm_dwarfdump, llvm_filecheck, llvm_nm, llvm_objdump, llvm_profdata,
58-
llvm_readobj, LlvmAr, LlvmBcanalyzer, LlvmDwarfdump, LlvmFilecheck, LlvmNm, LlvmObjdump,
59-
LlvmProfdata, LlvmReadobj,
60+
llvm_ar, llvm_bcanalyzer, llvm_dis, llvm_dwarfdump, llvm_filecheck, llvm_nm, llvm_objcopy,
61+
llvm_objdump, llvm_profdata, llvm_readobj, LlvmAr, LlvmBcanalyzer, LlvmDis, LlvmDwarfdump,
62+
LlvmFilecheck, LlvmNm, LlvmObjcopy, LlvmObjdump, LlvmProfdata, LlvmReadobj,
6063
};
6164
pub use python::python_command;
6265
pub use rustc::{aux_build, bare_rustc, rustc, rustc_path, Rustc};

src/tools/tidy/src/allowed_run_make_makefiles.txt

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ run-make/branch-protection-check-IBT/Makefile
22
run-make/cat-and-grep-sanity-check/Makefile
33
run-make/extern-fn-reachable/Makefile
44
run-make/incr-add-rust-src-component/Makefile
5-
run-make/issue-84395-lto-embed-bitcode/Makefile
65
run-make/jobserver-error/Makefile
76
run-make/libs-through-symlinks/Makefile
87
run-make/split-debuginfo/Makefile
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
1-
//! Make sure that cross-language LTO works on riscv targets,
2-
//! which requires extra `target-abi` metadata to be emitted.
1+
//! Make sure that cross-language LTO works on riscv targets, which requires extra `target-abi`
2+
//! metadata to be emitted.
33
//@ needs-force-clang-based-tests
4-
//@ needs-llvm-components riscv
4+
//@ needs-llvm-components: riscv
55

6-
//@ needs-force-clang-based-tests
7-
// FIXME(#126180): This test can only run on `x86_64-gnu-debug`, because that CI job sets
8-
// RUSTBUILD_FORCE_CLANG_BASED_TESTS and only runs tests which contain "clang" in their
9-
// name.
10-
// However, this test does not run at all as its name does not contain "clang".
11-
12-
use std::path::PathBuf;
13-
use std::process::{Command, Output};
14-
use std::{env, str};
6+
// ignore-tidy-linelength
157

16-
use run_make_support::{bin_name, clang, llvm_readobj, rustc};
8+
use object::elf;
9+
use object::read::elf as readelf;
10+
use run_make_support::{bin_name, clang, object, rfs, rustc};
1711

18-
fn check_target(target: &str, clang_target: &str, carch: &str, is_double_float: bool) {
12+
fn check_target<H: readelf::FileHeader<Endian = object::Endianness>>(
13+
target: &str,
14+
clang_target: &str,
15+
carch: &str,
16+
is_double_float: bool,
17+
) {
1918
eprintln!("Checking target {target}");
2019
// Rust part
2120
rustc()
@@ -39,16 +38,55 @@ fn check_target(target: &str, clang_target: &str, carch: &str, is_double_float:
3938

4039
// Check that the built binary has correct float abi
4140
let executable = bin_name("riscv-xlto");
42-
let output = llvm_readobj().input(&executable).file_header().run();
43-
let stdout = String::from_utf8_lossy(&output.stdout);
44-
eprintln!("obj:\n{}", stdout);
45-
46-
assert!(!(is_double_float ^ stdout.contains("EF_RISCV_FLOAT_ABI_DOUBLE")));
41+
let data = rfs::read(&executable);
42+
let header = <H>::parse(&*data).unwrap();
43+
let endian = match header.e_ident().data {
44+
elf::ELFDATA2LSB => object::Endianness::Little,
45+
elf::ELFDATA2MSB => object::Endianness::Big,
46+
x => unreachable!("invalid e_ident data: {:#010b}", x),
47+
};
48+
// Check `(e_flags & EF_RISCV_FLOAT_ABI) == EF_RISCV_FLOAT_ABI_DOUBLE`.
49+
//
50+
// See
51+
// <https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#elf-object-files>.
52+
if is_double_float {
53+
assert_eq!(
54+
header.e_flags(endian) & elf::EF_RISCV_FLOAT_ABI,
55+
elf::EF_RISCV_FLOAT_ABI_DOUBLE,
56+
"expected {target} to use double ABI, but it did not"
57+
);
58+
} else {
59+
assert_ne!(
60+
header.e_flags(endian) & elf::EF_RISCV_FLOAT_ABI,
61+
elf::EF_RISCV_FLOAT_ABI_DOUBLE,
62+
"did not expected {target} to use double ABI"
63+
);
64+
}
4765
}
4866

4967
fn main() {
50-
check_target("riscv64gc-unknown-linux-gnu", "riscv64-linux-gnu", "rv64gc", true);
51-
check_target("riscv64imac-unknown-none-elf", "riscv64-unknown-elf", "rv64imac", false);
52-
check_target("riscv32imac-unknown-none-elf", "riscv32-unknown-elf", "rv32imac", false);
53-
check_target("riscv32gc-unknown-linux-gnu", "riscv32-linux-gnu", "rv32gc", true);
68+
check_target::<elf::FileHeader64<object::Endianness>>(
69+
"riscv64gc-unknown-linux-gnu",
70+
"riscv64-linux-gnu",
71+
"rv64gc",
72+
true,
73+
);
74+
check_target::<elf::FileHeader64<object::Endianness>>(
75+
"riscv64imac-unknown-none-elf",
76+
"riscv64-unknown-elf",
77+
"rv64imac",
78+
false,
79+
);
80+
check_target::<elf::FileHeader32<object::Endianness>>(
81+
"riscv32imac-unknown-none-elf",
82+
"riscv32-unknown-elf",
83+
"rv32imac",
84+
false,
85+
);
86+
check_target::<elf::FileHeader32<object::Endianness>>(
87+
"riscv32gc-unknown-linux-gnu",
88+
"riscv32-linux-gnu",
89+
"rv32gc",
90+
true,
91+
);
5492
}

tests/run-make/issue-84395-lto-embed-bitcode/Makefile

-14
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//! Smoke test to make sure the embed bitcode in elf created with
2+
//! `--plugin-opt=-lto-embed-bitcode=optimized` is valid llvm BC module.
3+
//!
4+
//! See <https://github.com/rust-lang/rust/issues/84395> where passing
5+
//! `-lto-embed-bitcode=optimized` to lld when linking rust code via `linker-plugin-lto` doesn't
6+
//! produce the expected result.
7+
//!
8+
//! See PR <https://github.com/rust-lang/rust/pull/98162> which initially introduced this test.
9+
10+
//@ needs-force-clang-based-tests
11+
12+
use run_make_support::{env_var, llvm_dis, llvm_objcopy, rustc};
13+
14+
fn main() {
15+
rustc()
16+
.input("test.rs")
17+
.arg("-Clink-arg=-fuse-ld=lld")
18+
.arg("-Clinker-plugin-lto")
19+
.arg(format!("-Clinker={}", env_var("CLANG")))
20+
.arg("-Clink-arg=-Wl,--plugin-opt=-lto-embed-bitcode=optimized")
21+
.arg("-Zemit-thin-lto=no")
22+
.run();
23+
24+
llvm_objcopy().dump_section(".llvmbc", "test.bc").arg("test").run();
25+
26+
llvm_dis().arg("test.bc").run();
27+
}

0 commit comments

Comments
 (0)