about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-10-25 18:33:17 +0000
committerbors <bors@rust-lang.org>2024-10-25 18:33:17 +0000
commitb188577f14fd238ca8568276baabd461a174038d (patch)
tree881cef4888e0da19f071a02ce8e82072ea5abe76
parent6faf0bd3e561f1a0c81f3eafe0ce0e688385d70e (diff)
parent03c7f992cd3b955bde2cdffc30ed44bcdb4f972f (diff)
downloadrust-b188577f14fd238ca8568276baabd461a174038d.tar.gz
rust-b188577f14fd238ca8568276baabd461a174038d.zip
Auto merge of #131917 - jieyouxu:rmake-clang, r=Kobzol
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.

I had to bump the `x86_64-gnu-debug` job to be ran with a runner with larger disk space.

Part of #132034.

try-job: x86_64-gnu-debug
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile4
-rw-r--r--src/ci/github-actions/jobs.yml4
-rw-r--r--src/tools/run-make-support/src/command.rs18
-rw-r--r--src/tools/run-make-support/src/external_deps/llvm.rs66
-rw-r--r--src/tools/run-make-support/src/lib.rs11
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt1
-rw-r--r--tests/run-make/cross-lang-lto-riscv-abi/rmake.rs84
-rw-r--r--tests/run-make/issue-84395-lto-embed-bitcode/Makefile14
-rw-r--r--tests/run-make/issue-84395-lto-embed-bitcode/rmake.rs27
9 files changed, 183 insertions, 46 deletions
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile
index fa31801269a..292dbfd20a5 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile
@@ -49,9 +49,7 @@ ENV RUST_CONFIGURE_ARGS \
 #   (without necessarily testing the result).
 # - That the tests with `//@ needs-force-clang-based-tests` pass, since they
 #   don't run by default unless RUSTBUILD_FORCE_CLANG_BASED_TESTS is set.
-#   - FIXME(https://github.com/rust-lang/rust/pull/126155#issuecomment-2156314273):
-#     Currently we only run the subset of tests with "clang" in their name.
 
 ENV SCRIPT \
   python3 ../x.py --stage 2 build && \
-  python3 ../x.py --stage 2 test tests/run-make --test-args clang
+  python3 ../x.py --stage 2 test tests/run-make
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 6b6a3806666..a401092a3a7 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -256,7 +256,9 @@ auto:
     <<: *job-linux-4c
 
   - image: x86_64-gnu-debug
-    <<: *job-linux-4c
+    # This seems to be needed because a full stage 2 build + run-make tests
+    # overwhelms the storage capacity of the standard 4c runner.
+    <<: *job-linux-4c-largedisk
 
   - image: x86_64-gnu-distcheck
     <<: *job-linux-8c
diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs
index 6b58173b343..9e09527d6d0 100644
--- a/src/tools/run-make-support/src/command.rs
+++ b/src/tools/run-make-support/src/command.rs
@@ -224,6 +224,12 @@ pub struct CompletedProcess {
 impl CompletedProcess {
     #[must_use]
     #[track_caller]
+    pub fn stdout(&self) -> Vec<u8> {
+        self.output.stdout.clone()
+    }
+
+    #[must_use]
+    #[track_caller]
     pub fn stdout_utf8(&self) -> String {
         String::from_utf8(self.output.stdout.clone()).expect("stdout is not valid UTF-8")
     }
@@ -236,11 +242,23 @@ impl CompletedProcess {
 
     #[must_use]
     #[track_caller]
+    pub fn stderr(&self) -> Vec<u8> {
+        self.output.stderr.clone()
+    }
+
+    #[must_use]
+    #[track_caller]
     pub fn stderr_utf8(&self) -> String {
         String::from_utf8(self.output.stderr.clone()).expect("stderr is not valid UTF-8")
     }
 
     #[must_use]
+    #[track_caller]
+    pub fn invalid_stderr_utf8(&self) -> String {
+        String::from_utf8_lossy(&self.output.stderr.clone()).to_string()
+    }
+
+    #[must_use]
     pub fn status(&self) -> ExitStatus {
         self.output.status
     }
diff --git a/src/tools/run-make-support/src/external_deps/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs
index 38a9ac923b4..9a6e35da3fe 100644
--- a/src/tools/run-make-support/src/external_deps/llvm.rs
+++ b/src/tools/run-make-support/src/external_deps/llvm.rs
@@ -60,6 +60,18 @@ pub fn llvm_pdbutil() -> LlvmPdbutil {
     LlvmPdbutil::new()
 }
 
+/// Construct a new `llvm-dis` invocation. This assumes that `llvm-dis` is available
+/// at `$LLVM_BIN_DIR/llvm-dis`.
+pub fn llvm_dis() -> LlvmDis {
+    LlvmDis::new()
+}
+
+/// Construct a new `llvm-objcopy` invocation. This assumes that `llvm-objcopy` is available
+/// at `$LLVM_BIN_DIR/llvm-objcopy`.
+pub fn llvm_objcopy() -> LlvmObjcopy {
+    LlvmObjcopy::new()
+}
+
 /// A `llvm-readobj` invocation builder.
 #[derive(Debug)]
 #[must_use]
@@ -123,6 +135,20 @@ pub struct LlvmPdbutil {
     cmd: Command,
 }
 
+/// A `llvm-dis` invocation builder.
+#[derive(Debug)]
+#[must_use]
+pub struct LlvmDis {
+    cmd: Command,
+}
+
+/// A `llvm-objcopy` invocation builder.
+#[derive(Debug)]
+#[must_use]
+pub struct LlvmObjcopy {
+    cmd: Command,
+}
+
 crate::macros::impl_common_helpers!(LlvmReadobj);
 crate::macros::impl_common_helpers!(LlvmProfdata);
 crate::macros::impl_common_helpers!(LlvmFilecheck);
@@ -132,6 +158,8 @@ crate::macros::impl_common_helpers!(LlvmNm);
 crate::macros::impl_common_helpers!(LlvmBcanalyzer);
 crate::macros::impl_common_helpers!(LlvmDwarfdump);
 crate::macros::impl_common_helpers!(LlvmPdbutil);
+crate::macros::impl_common_helpers!(LlvmDis);
+crate::macros::impl_common_helpers!(LlvmObjcopy);
 
 /// Generate the path to the bin directory of LLVM.
 #[must_use]
@@ -390,3 +418,41 @@ impl LlvmPdbutil {
         self
     }
 }
+
+impl LlvmObjcopy {
+    /// Construct a new `llvm-objcopy` invocation. This assumes that `llvm-objcopy` is available
+    /// at `$LLVM_BIN_DIR/llvm-objcopy`.
+    pub fn new() -> Self {
+        let llvm_objcopy = llvm_bin_dir().join("llvm-objcopy");
+        let cmd = Command::new(llvm_objcopy);
+        Self { cmd }
+    }
+
+    /// Dump the contents of `section` into the file at `path`.
+    #[track_caller]
+    pub fn dump_section<S: AsRef<str>, P: AsRef<Path>>(
+        &mut self,
+        section_name: S,
+        path: P,
+    ) -> &mut Self {
+        self.cmd.arg("--dump-section");
+        self.cmd.arg(format!("{}={}", section_name.as_ref(), path.as_ref().to_str().unwrap()));
+        self
+    }
+}
+
+impl LlvmDis {
+    /// Construct a new `llvm-dis` invocation. This assumes that `llvm-dis` is available
+    /// at `$LLVM_BIN_DIR/llvm-dis`.
+    pub fn new() -> Self {
+        let llvm_dis = llvm_bin_dir().join("llvm-dis");
+        let cmd = Command::new(llvm_dis);
+        Self { cmd }
+    }
+
+    /// Provide an input file.
+    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        self.cmd.arg(path.as_ref());
+        self
+    }
+}
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 15d813ccf53..368b98c9f0d 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -49,14 +49,17 @@ pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rust
 
 // These rely on external dependencies.
 pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc};
-pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_optimized, build_native_static_lib_cxx};
+pub use c_build::{
+    build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_cxx,
+    build_native_static_lib_optimized,
+};
 pub use cargo::cargo;
 pub use clang::{clang, Clang};
 pub use htmldocck::htmldocck;
 pub use llvm::{
-    llvm_ar, llvm_bcanalyzer, llvm_dwarfdump, llvm_filecheck, llvm_nm, llvm_objdump, llvm_profdata,
-    llvm_readobj, LlvmAr, LlvmBcanalyzer, LlvmDwarfdump, LlvmFilecheck, LlvmNm, LlvmObjdump,
-    LlvmProfdata, LlvmReadobj,
+    llvm_ar, llvm_bcanalyzer, llvm_dis, llvm_dwarfdump, llvm_filecheck, llvm_nm, llvm_objcopy,
+    llvm_objdump, llvm_profdata, llvm_readobj, LlvmAr, LlvmBcanalyzer, LlvmDis, LlvmDwarfdump,
+    LlvmFilecheck, LlvmNm, LlvmObjcopy, LlvmObjdump, LlvmProfdata, LlvmReadobj,
 };
 pub use python::python_command;
 pub use rustc::{aux_build, bare_rustc, rustc, rustc_path, Rustc};
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 7a0f98d59f0..0e156b9d1ac 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -2,7 +2,6 @@ run-make/branch-protection-check-IBT/Makefile
 run-make/cat-and-grep-sanity-check/Makefile
 run-make/extern-fn-reachable/Makefile
 run-make/incr-add-rust-src-component/Makefile
-run-make/issue-84395-lto-embed-bitcode/Makefile
 run-make/jobserver-error/Makefile
 run-make/libs-through-symlinks/Makefile
 run-make/split-debuginfo/Makefile
diff --git a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs
index 92573353a74..e595dbea94d 100644
--- a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs
+++ b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs
@@ -1,21 +1,20 @@
-//! Make sure that cross-language LTO works on riscv targets,
-//! which requires extra `target-abi` metadata to be emitted.
+//! Make sure that cross-language LTO works on riscv targets, which requires extra `target-abi`
+//! metadata to be emitted.
 //@ needs-force-clang-based-tests
-//@ needs-llvm-components riscv
+//@ needs-llvm-components: riscv
 
-//@ needs-force-clang-based-tests
-// FIXME(#126180): This test can only run on `x86_64-gnu-debug`, because that CI job sets
-// RUSTBUILD_FORCE_CLANG_BASED_TESTS and only runs tests which contain "clang" in their
-// name.
-// However, this test does not run at all as its name does not contain "clang".
-
-use std::path::PathBuf;
-use std::process::{Command, Output};
-use std::{env, str};
+// ignore-tidy-linelength
 
-use run_make_support::{bin_name, clang, llvm_readobj, rustc};
+use object::elf;
+use object::read::elf as readelf;
+use run_make_support::{bin_name, clang, object, rfs, rustc};
 
-fn check_target(target: &str, clang_target: &str, carch: &str, is_double_float: bool) {
+fn check_target<H: readelf::FileHeader<Endian = object::Endianness>>(
+    target: &str,
+    clang_target: &str,
+    carch: &str,
+    is_double_float: bool,
+) {
     eprintln!("Checking target {target}");
     // Rust part
     rustc()
@@ -39,16 +38,55 @@ fn check_target(target: &str, clang_target: &str, carch: &str, is_double_float:
 
     // Check that the built binary has correct float abi
     let executable = bin_name("riscv-xlto");
-    let output = llvm_readobj().input(&executable).file_header().run();
-    let stdout = String::from_utf8_lossy(&output.stdout);
-    eprintln!("obj:\n{}", stdout);
-
-    assert!(!(is_double_float ^ stdout.contains("EF_RISCV_FLOAT_ABI_DOUBLE")));
+    let data = rfs::read(&executable);
+    let header = <H>::parse(&*data).unwrap();
+    let endian = match header.e_ident().data {
+        elf::ELFDATA2LSB => object::Endianness::Little,
+        elf::ELFDATA2MSB => object::Endianness::Big,
+        x => unreachable!("invalid e_ident data: {:#010b}", x),
+    };
+    // Check `(e_flags & EF_RISCV_FLOAT_ABI) == EF_RISCV_FLOAT_ABI_DOUBLE`.
+    //
+    // See
+    // <https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#elf-object-files>.
+    if is_double_float {
+        assert_eq!(
+            header.e_flags(endian) & elf::EF_RISCV_FLOAT_ABI,
+            elf::EF_RISCV_FLOAT_ABI_DOUBLE,
+            "expected {target} to use double ABI, but it did not"
+        );
+    } else {
+        assert_ne!(
+            header.e_flags(endian) & elf::EF_RISCV_FLOAT_ABI,
+            elf::EF_RISCV_FLOAT_ABI_DOUBLE,
+            "did not expected {target} to use double ABI"
+        );
+    }
 }
 
 fn main() {
-    check_target("riscv64gc-unknown-linux-gnu", "riscv64-linux-gnu", "rv64gc", true);
-    check_target("riscv64imac-unknown-none-elf", "riscv64-unknown-elf", "rv64imac", false);
-    check_target("riscv32imac-unknown-none-elf", "riscv32-unknown-elf", "rv32imac", false);
-    check_target("riscv32gc-unknown-linux-gnu", "riscv32-linux-gnu", "rv32gc", true);
+    check_target::<elf::FileHeader64<object::Endianness>>(
+        "riscv64gc-unknown-linux-gnu",
+        "riscv64-linux-gnu",
+        "rv64gc",
+        true,
+    );
+    check_target::<elf::FileHeader64<object::Endianness>>(
+        "riscv64imac-unknown-none-elf",
+        "riscv64-unknown-elf",
+        "rv64imac",
+        false,
+    );
+    check_target::<elf::FileHeader32<object::Endianness>>(
+        "riscv32imac-unknown-none-elf",
+        "riscv32-unknown-elf",
+        "rv32imac",
+        false,
+    );
+    check_target::<elf::FileHeader32<object::Endianness>>(
+        "riscv32gc-unknown-linux-gnu",
+        "riscv32-linux-gnu",
+        "rv32gc",
+        true,
+    );
 }
diff --git a/tests/run-make/issue-84395-lto-embed-bitcode/Makefile b/tests/run-make/issue-84395-lto-embed-bitcode/Makefile
deleted file mode 100644
index aabe90754a6..00000000000
--- a/tests/run-make/issue-84395-lto-embed-bitcode/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-# needs-force-clang-based-tests
-
-# FIXME(#126180): This test doesn't actually run anywhere, because the only
-# CI job that sets RUSTBUILD_FORCE_CLANG_BASED_TESTS runs very few tests.
-
-# This test makes sure the embed bitcode in elf created with
-# lto-embed-bitcode=optimized is valid llvm BC module.
-
-include ../tools.mk
-
-all:
-	$(RUSTC) test.rs --target $(TARGET) -Clink-arg=-fuse-ld=lld -Clinker-plugin-lto -Clinker=$(CLANG) -Clink-arg=-Wl,--plugin-opt=-lto-embed-bitcode=optimized -Zemit-thin-lto=no
-	$(LLVM_BIN_DIR)/objcopy --dump-section .llvmbc=$(TMPDIR)/test.bc $(TMPDIR)/test
-	$(LLVM_BIN_DIR)/llvm-dis $(TMPDIR)/test.bc
diff --git a/tests/run-make/issue-84395-lto-embed-bitcode/rmake.rs b/tests/run-make/issue-84395-lto-embed-bitcode/rmake.rs
new file mode 100644
index 00000000000..450d8a9f099
--- /dev/null
+++ b/tests/run-make/issue-84395-lto-embed-bitcode/rmake.rs
@@ -0,0 +1,27 @@
+//! Smoke test to make sure the embed bitcode in elf created with
+//! `--plugin-opt=-lto-embed-bitcode=optimized` is valid llvm BC module.
+//!
+//! See <https://github.com/rust-lang/rust/issues/84395> where passing
+//! `-lto-embed-bitcode=optimized` to lld when linking rust code via `linker-plugin-lto` doesn't
+//! produce the expected result.
+//!
+//! See PR <https://github.com/rust-lang/rust/pull/98162> which initially introduced this test.
+
+//@ needs-force-clang-based-tests
+
+use run_make_support::{env_var, llvm_dis, llvm_objcopy, rustc};
+
+fn main() {
+    rustc()
+        .input("test.rs")
+        .arg("-Clink-arg=-fuse-ld=lld")
+        .arg("-Clinker-plugin-lto")
+        .arg(format!("-Clinker={}", env_var("CLANG")))
+        .arg("-Clink-arg=-Wl,--plugin-opt=-lto-embed-bitcode=optimized")
+        .arg("-Zemit-thin-lto=no")
+        .run();
+
+    llvm_objcopy().dump_section(".llvmbc", "test.bc").arg("test").run();
+
+    llvm_dis().arg("test.bc").run();
+}