diff --git a/Cargo.lock b/Cargo.lock index 1f26dd7c43cfc..faf2c473ee188 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3342,6 +3342,7 @@ name = "run_make_support" version = "0.0.0" dependencies = [ "object 0.34.0", + "regex", "wasmparser", ] diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index f78e0363f55ba..99597875d0f93 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -839,6 +839,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "needs-profiler-support", "needs-relocation-model-pic", "needs-run-enabled", + "needs-rust-lld", "needs-rust-lldb", "needs-sanitizer-address", "needs-sanitizer-cfi", diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index d8bb8c643d1d2..3ea35c7940c21 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" [dependencies] object = "0.34.0" wasmparser = "0.118.2" +regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 47b46a0a699c1..9a4fdff5d1526 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -13,6 +13,7 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Output}; pub use object; +pub use regex; pub use wasmparser; pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc}; diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index ebda151b908b0..9bf41c6e2e9a5 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -128,9 +128,8 @@ impl Rustc { self } - /// Specify target triple. + /// Specify the target triple, or a path to a custom target json spec file. pub fn target(&mut self, target: &str) -> &mut Self { - assert!(!target.contains(char::is_whitespace), "target triple cannot contain spaces"); self.cmd.arg(format!("--target={target}")); self } @@ -149,6 +148,12 @@ impl Rustc { self } + /// Add an extra argument to the linker invocation, via `-Clink-arg`. + pub fn link_arg(&mut self, link_arg: &str) -> &mut Self { + self.cmd.arg(format!("-Clink-arg={link_arg}")); + self + } + #[track_caller] pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output { let caller_location = std::panic::Location::caller(); diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 3914feb3499dd..f0ed0ae806fd8 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -249,8 +249,6 @@ run-make/rlib-format-packed-bundled-libs-2/Makefile run-make/rlib-format-packed-bundled-libs-3/Makefile run-make/rlib-format-packed-bundled-libs/Makefile run-make/rmeta-preferred/Makefile -run-make/rust-lld-custom-target/Makefile -run-make/rust-lld/Makefile run-make/rustc-macro-dep-files/Makefile run-make/rustdoc-determinism/Makefile run-make/rustdoc-error-lines/Makefile diff --git a/tests/run-make/rust-lld-custom-target/Makefile b/tests/run-make/rust-lld-custom-target/Makefile deleted file mode 100644 index 007493ab0b99c..0000000000000 --- a/tests/run-make/rust-lld-custom-target/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -# needs-rust-lld -# only-x86_64-unknown-linux-gnu -all: - RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) --crate-type cdylib --target custom-target.json -Clink-args=-Wl,-v lib.rs 2> $(TMPDIR)/output.txt - $(CGREP) -e "^LLD [0-9]+\.[0-9]+\.[0-9]+" < $(TMPDIR)/output.txt diff --git a/tests/run-make/rust-lld-custom-target/rmake.rs b/tests/run-make/rust-lld-custom-target/rmake.rs new file mode 100644 index 0000000000000..b5341725e36ea --- /dev/null +++ b/tests/run-make/rust-lld-custom-target/rmake.rs @@ -0,0 +1,51 @@ +// Test linking using `cc` with `rust-lld`, using a custom target with features described in MCP 510 +// see https://github.com/rust-lang/compiler-team/issues/510 for more info: +// +// Starting from the `x86_64-unknown-linux-gnu` target spec, we add the following options: +// - a linker-flavor using lld via a C compiler +// - the self-contained linker component is enabled + +//@ needs-rust-lld +//@ only-x86_64-unknown-linux-gnu + +extern crate run_make_support; + +use run_make_support::regex::Regex; +use run_make_support::rustc; +use std::process::Output; + +fn main() { + // Compile to a custom target spec with rust-lld enabled by default. We'll check that by asking + // the linker to display its version number with a link-arg. + let output = rustc() + .env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info") + .crate_type("cdylib") + .target("custom-target.json") + .link_arg("-Wl,-v") + .input("lib.rs") + .run(); + assert!( + find_lld_version_in_logs(output), + "the LLD version string should be present in the output logs" + ); + + // But it can also be disabled via linker features. + let output = rustc() + .env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info") + .crate_type("cdylib") + .target("custom-target.json") + .arg("-Zlinker-features=-lld") + .link_arg("-Wl,-v") + .input("lib.rs") + .run(); + assert!( + !find_lld_version_in_logs(output), + "the LLD version string should not be present in the output logs" + ); +} + +fn find_lld_version_in_logs(output: Output) -> bool { + let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap(); + let stderr = std::str::from_utf8(&output.stderr).unwrap(); + stderr.lines().any(|line| lld_version_re.is_match(line)) +} diff --git a/tests/run-make/rust-lld/Makefile b/tests/run-make/rust-lld/Makefile deleted file mode 100644 index 1ecac479f4147..0000000000000 --- a/tests/run-make/rust-lld/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include ../tools.mk - -# ignore-msvc -# needs-rust-lld -# ignore-s390x lld does not yet support s390x as target -all: - RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Clink-self-contained=+linker -Zlinker-features=+lld -Zunstable-options -Clink-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt - $(CGREP) -e "^LLD [0-9]+\.[0-9]+\.[0-9]+" < $(TMPDIR)/output.txt - - # while we're here, also check that the last linker feature flag "wins" - RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Clink-self-contained=+linker -Zlinker-features=-lld -Zlinker-features=+lld -Zunstable-options -Clink-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt - $(CGREP) -e "^LLD [0-9]+\.[0-9]+\.[0-9]+" < $(TMPDIR)/output.txt diff --git a/tests/run-make/rust-lld/rmake.rs b/tests/run-make/rust-lld/rmake.rs new file mode 100644 index 0000000000000..acb6d74aaa8be --- /dev/null +++ b/tests/run-make/rust-lld/rmake.rs @@ -0,0 +1,64 @@ +// Test linking using `cc` with `rust-lld`, using the unstable CLI described in MCP 510 +// see https://github.com/rust-lang/compiler-team/issues/510 for more info + +//@ needs-rust-lld +//@ ignore-msvc +//@ ignore-s390x lld does not yet support s390x as target + +extern crate run_make_support; + +use run_make_support::regex::Regex; +use run_make_support::rustc; +use std::process::Output; + +fn main() { + // Opt-in to lld and the self-contained linker, to link with rust-lld. We'll check that by + // asking the linker to display its version number with a link-arg. + let output = rustc() + .env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info") + .arg("-Zlinker-features=+lld") + .arg("-Clink-self-contained=+linker") + .arg("-Zunstable-options") + .link_arg("-Wl,-v") + .input("main.rs") + .run(); + assert!( + find_lld_version_in_logs(output), + "the LLD version string should be present in the output logs" + ); + + // It should not be used when we explictly opt-out of lld. + let output = rustc() + .env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info") + .link_arg("-Wl,-v") + .arg("-Zlinker-features=-lld") + .input("main.rs") + .run(); + assert!( + !find_lld_version_in_logs(output), + "the LLD version string should not be present in the output logs" + ); + + // While we're here, also check that the last linker feature flag "wins" when passed multiple + // times to rustc. + let output = rustc() + .env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info") + .link_arg("-Wl,-v") + .arg("-Clink-self-contained=+linker") + .arg("-Zunstable-options") + .arg("-Zlinker-features=-lld") + .arg("-Zlinker-features=+lld") + .arg("-Zlinker-features=-lld,+lld") + .input("main.rs") + .run(); + assert!( + find_lld_version_in_logs(output), + "the LLD version string should be present in the output logs" + ); +} + +fn find_lld_version_in_logs(output: Output) -> bool { + let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap(); + let stderr = std::str::from_utf8(&output.stderr).unwrap(); + stderr.lines().any(|line| lld_version_re.is_match(line)) +}