diff --git a/src/tools/run-make-support/src/clang.rs b/src/tools/run-make-support/src/clang.rs new file mode 100644 index 0000000000000..ed9f8383dc3ae --- /dev/null +++ b/src/tools/run-make-support/src/clang.rs @@ -0,0 +1,73 @@ +use std::env; +use std::path::Path; +use std::process::Command; + +use crate::{bin_name, handle_failed_output, tmp_dir}; + +/// Construct a new `clang` invocation. `clang` is not always available for all targets. +pub fn clang() -> Clang { + Clang::new() +} + +/// A `clang` invocation builder. +#[derive(Debug)] +pub struct Clang { + cmd: Command, +} + +crate::impl_common_helpers!(Clang); + +impl Clang { + /// Construct a new `clang` invocation. `clang` is not always available for all targets. + pub fn new() -> Self { + let clang = + env::var("CLANG").expect("`CLANG` not specified, but this is required to find `clang`"); + let cmd = Command::new(clang); + Self { cmd } + } + + /// Provide an input file. + pub fn input>(&mut self, path: P) -> &mut Self { + self.cmd.arg(path.as_ref()); + self + } + + /// Specify the name of the executable. The executable will be placed under `$TMPDIR`, and the + /// extension will be determined by [`bin_name`]. + pub fn out_exe(&mut self, name: &str) -> &mut Self { + self.cmd.arg("-o"); + self.cmd.arg(tmp_dir().join(bin_name(name))); + self + } + + /// Specify which target triple clang should target. + pub fn target(&mut self, target_triple: &str) -> &mut Self { + self.cmd.arg("-target"); + self.cmd.arg(target_triple); + self + } + + /// Pass `-nostdlib` to disable linking the C standard library. + pub fn no_stdlib(&mut self) -> &mut Self { + self.cmd.arg("-nostdlib"); + self + } + + /// Specify architecture. + pub fn arch(&mut self, arch: &str) -> &mut Self { + self.cmd.arg(format!("-march={arch}")); + self + } + + /// Specify LTO settings. + pub fn lto(&mut self, lto: &str) -> &mut Self { + self.cmd.arg(format!("-flto={lto}")); + self + } + + /// Specify which ld to use. + pub fn use_ld(&mut self, ld: &str) -> &mut Self { + self.cmd.arg(format!("-fuse-ld={ld}")); + self + } +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 9a4fdff5d1526..e723e824ed6c8 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -4,6 +4,8 @@ //! as `object` or `wasmparser`, they can be re-exported and be made available through this library. pub mod cc; +pub mod clang; +pub mod llvm_readobj; pub mod run; pub mod rustc; pub mod rustdoc; @@ -17,6 +19,8 @@ pub use regex; pub use wasmparser; pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc}; +pub use clang::{clang, Clang}; +pub use llvm_readobj::{llvm_readobj, LlvmReadobj}; pub use run::{run, run_fail}; pub use rustc::{aux_build, rustc, Rustc}; pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; diff --git a/src/tools/run-make-support/src/llvm_readobj.rs b/src/tools/run-make-support/src/llvm_readobj.rs new file mode 100644 index 0000000000000..32ea07e932ed8 --- /dev/null +++ b/src/tools/run-make-support/src/llvm_readobj.rs @@ -0,0 +1,44 @@ +use std::env; +use std::path::{Path, PathBuf}; +use std::process::Command; + +use crate::handle_failed_output; + +/// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available +/// at `$LLVM_BIN_DIR/llvm-readobj`. +pub fn llvm_readobj() -> LlvmReadobj { + LlvmReadobj::new() +} + +/// A `llvm-readobj` invocation builder. +#[derive(Debug)] +pub struct LlvmReadobj { + cmd: Command, +} + +crate::impl_common_helpers!(LlvmReadobj); + +impl LlvmReadobj { + /// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available + /// at `$LLVM_BIN_DIR/llvm-readobj`. + pub fn new() -> Self { + let llvm_bin_dir = env::var("LLVM_BIN_DIR") + .expect("`LLVM_BIN_DIR` not specified, but this is required to find `llvm-readobj`"); + let llvm_bin_dir = PathBuf::from(llvm_bin_dir); + let llvm_readobj = llvm_bin_dir.join("llvm-readobj"); + let cmd = Command::new(llvm_readobj); + Self { cmd } + } + + /// Provide an input file. + pub fn input>(&mut self, path: P) -> &mut Self { + self.cmd.arg(path.as_ref()); + self + } + + /// Pass `--file-header` to display file headers. + pub fn file_header(&mut self) -> &mut Self { + self.cmd.arg("--file-header"); + self + } +} 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 2f13cf17169fa..b534a99f8cfee 100644 --- a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs +++ b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs @@ -1,10 +1,10 @@ //! Make sure that cross-language LTO works on riscv targets, -//! which requires extra abi metadata to be emitted. +//! which requires extra `target-abi` metadata to be emitted. //@ needs-matching-clang //@ needs-llvm-components riscv extern crate run_make_support; -use run_make_support::{bin_name, rustc, tmp_dir}; +use run_make_support::{bin_name, clang, llvm_readobj, rustc, tmp_dir}; use std::{ env, path::PathBuf, @@ -12,13 +12,6 @@ use std::{ str, }; -fn handle_failed_output(output: Output) { - eprintln!("output status: `{}`", output.status); - eprintln!("=== STDOUT ===\n{}\n\n", String::from_utf8(output.stdout).unwrap()); - eprintln!("=== STDERR ===\n{}\n\n", String::from_utf8(output.stderr).unwrap()); - std::process::exit(1) -} - fn check_target(target: &str, clang_target: &str, carch: &str, is_double_float: bool) { eprintln!("Checking target {target}"); // Rust part @@ -30,40 +23,24 @@ fn check_target(target: &str, clang_target: &str, carch: &str, is_double_float: .linker_plugin_lto("on") .run(); // C part - let clang = env::var("CLANG").unwrap(); - let mut cmd = Command::new(clang); - let executable = tmp_dir().join("riscv-xlto"); - cmd.arg("-target") - .arg(clang_target) - .arg(format!("-march={carch}")) - .arg(format!("-flto=thin")) - .arg(format!("-fuse-ld=lld")) - .arg("-nostdlib") - .arg("-o") - .arg(&executable) - .arg("cstart.c") - .arg(tmp_dir().join("libriscv_xlto.rlib")); - eprintln!("{cmd:?}"); - let output = cmd.output().unwrap(); - if !output.status.success() { - handle_failed_output(output); - } + clang() + .target(clang_target) + .arch(carch) + .lto("thin") + .use_ld("lld") + .no_stdlib() + .out_exe("riscv-xlto") + .input("cstart.c") + .input(tmp_dir().join("libriscv_xlto.rlib")) + .run(); + // Check that the built binary has correct float abi - let llvm_readobj = - PathBuf::from(env::var("LLVM_BIN_DIR").unwrap()).join(bin_name("llvm-readobj")); - let mut cmd = Command::new(llvm_readobj); - cmd.arg("--file-header").arg(executable); - eprintln!("{cmd:?}"); - let output = cmd.output().unwrap(); - if output.status.success() { - assert!( - !(is_double_float - ^ dbg!(str::from_utf8(&output.stdout).unwrap()) - .contains("EF_RISCV_FLOAT_ABI_DOUBLE")) - ) - } else { - handle_failed_output(output); - } + let executable = tmp_dir().join(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"))); } fn main() {