Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add helper function for checking LLD usage to run-make-support #139322

Merged
merged 2 commits into from
Apr 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/tools/run-make-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub mod assertion_helpers;
pub mod diff;
pub mod env;
pub mod external_deps;
pub mod linker;
pub mod path_helpers;
pub mod run;
pub mod scoped_run;
Expand Down
36 changes: 36 additions & 0 deletions src/tools/run-make-support/src/linker.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use regex::Regex;

use crate::{Rustc, is_msvc};

/// Asserts that `rustc` uses LLD for linking when executed.
pub fn assert_rustc_uses_lld(rustc: &mut Rustc) {
let stderr = get_stderr_with_linker_messages(rustc);
assert!(
has_lld_version_in_logs(&stderr),
"LLD version should be present in rustc stderr:\n{stderr}"
);
}

/// Asserts that `rustc` doesn't use LLD for linking when executed.
pub fn assert_rustc_doesnt_use_lld(rustc: &mut Rustc) {
let stderr = get_stderr_with_linker_messages(rustc);
assert!(
!has_lld_version_in_logs(&stderr),
"LLD version should NOT be present in rustc stderr:\n{stderr}"
);
}

fn get_stderr_with_linker_messages(rustc: &mut Rustc) -> String {
// lld-link is used if msvc, otherwise a gnu-compatible lld is used.
let linker_version_flag = if is_msvc() { "--version" } else { "-Wl,-v" };

let output = rustc.arg("-Wlinker-messages").link_arg(linker_version_flag).run();
output.stderr_utf8()
}

fn has_lld_version_in_logs(stderr: &str) -> bool {
// Strip the `-Wlinker-messages` wrappers prefixing the linker output.
let stderr = Regex::new(r"warning: linker std(out|err):").unwrap().replace_all(&stderr, "");
let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap();
stderr.lines().any(|line| lld_version_re.is_match(line.trim()))
}
17 changes: 2 additions & 15 deletions tests/run-make/rust-lld-by-default-beta-stable/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,11 @@
//@ ignore-nightly
//@ only-x86_64-unknown-linux-gnu

use std::process::Output;

use run_make_support::regex::Regex;
use run_make_support::linker::assert_rustc_doesnt_use_lld;
use run_make_support::rustc;

fn main() {
// A regular compilation should not use rust-lld by default. We'll check that by asking the
// linker to display its version number with a link-arg.
let output = rustc().arg("-Wlinker-messages").link_arg("-Wl,-v").input("main.rs").run();
assert!(
!find_lld_version_in_logs(output.stderr_utf8()),
"the LLD version string should not be present in the output logs:\n{}",
output.stderr_utf8()
);
}

fn find_lld_version_in_logs(stderr: String) -> bool {
let lld_version_re =
Regex::new(r"^warning: linker stdout: LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap();
stderr.lines().any(|line| lld_version_re.is_match(line.trim()))
assert_rustc_doesnt_use_lld(rustc().input("main.rs"));
}
27 changes: 3 additions & 24 deletions tests/run-make/rust-lld-by-default-nightly/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,14 @@
//@ ignore-stable
//@ only-x86_64-unknown-linux-gnu

use run_make_support::regex::Regex;
use run_make_support::linker::{assert_rustc_doesnt_use_lld, assert_rustc_uses_lld};
use run_make_support::rustc;

fn main() {
// A regular compilation should use rust-lld by default. We'll check that by asking the linker
// to display its version number with a link-arg.
let output = rustc().arg("-Wlinker-messages").link_arg("-Wl,-v").input("main.rs").run();
assert!(
find_lld_version_in_logs(output.stderr_utf8()),
"the LLD version string should be present in the output logs:\n{}",
output.stderr_utf8()
);
assert_rustc_uses_lld(rustc().input("main.rs"));

// But it can still be disabled by turning the linker feature off.
let output = rustc()
.arg("-Wlinker-messages")
.link_arg("-Wl,-v")
.arg("-Zlinker-features=-lld")
.input("main.rs")
.run();
assert!(
!find_lld_version_in_logs(output.stderr_utf8()),
"the LLD version string should not be present in the output logs:\n{}",
output.stderr_utf8()
);
}

fn find_lld_version_in_logs(stderr: String) -> bool {
let lld_version_re =
Regex::new(r"^warning: linker stdout: LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap();
stderr.lines().any(|line| lld_version_re.is_match(line.trim()))
assert_rustc_doesnt_use_lld(rustc().arg("-Zlinker-features=-lld").input("main.rs"));
}
39 changes: 9 additions & 30 deletions tests/run-make/rust-lld-custom-target/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,22 @@
//@ needs-rust-lld
//@ only-x86_64-unknown-linux-gnu

use run_make_support::regex::Regex;
use run_make_support::linker::{assert_rustc_doesnt_use_lld, assert_rustc_uses_lld};
use run_make_support::rustc;

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()
.crate_type("cdylib")
.arg("-Wlinker-messages")
.target("custom-target.json")
.link_arg("-Wl,-v")
.input("lib.rs")
.run();
assert!(
find_lld_version_in_logs(output.stderr_utf8()),
"the LLD version string should be present in the output logs:\n{}",
output.stderr_utf8()
assert_rustc_uses_lld(
rustc().crate_type("cdylib").target("custom-target.json").input("lib.rs"),
);

// But it can also be disabled via linker features.
let output = rustc()
.crate_type("cdylib")
.arg("-Wlinker-messages")
.target("custom-target.json")
.arg("-Zlinker-features=-lld")
.link_arg("-Wl,-v")
.input("lib.rs")
.run();
assert!(
!find_lld_version_in_logs(output.stderr_utf8()),
"the LLD version string should not be present in the output logs:\n{}",
output.stderr_utf8()
assert_rustc_doesnt_use_lld(
rustc()
.crate_type("cdylib")
.target("custom-target.json")
.arg("-Zlinker-features=-lld")
.input("lib.rs"),
);
}

fn find_lld_version_in_logs(stderr: String) -> bool {
let lld_version_re =
Regex::new(r"^warning: linker stdout: LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap();
stderr.lines().any(|line| lld_version_re.is_match(line.trim()))
}
68 changes: 18 additions & 50 deletions tests/run-make/rust-lld/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,64 +4,32 @@
//@ needs-rust-lld
//@ ignore-s390x lld does not yet support s390x as target

use run_make_support::regex::Regex;
use run_make_support::{is_msvc, rustc};
use run_make_support::linker::{assert_rustc_doesnt_use_lld, assert_rustc_uses_lld};
use run_make_support::rustc;

fn main() {
// lld-link is used if msvc, otherwise a gnu-compatible lld is used.
let linker_version_flag = if is_msvc() { "--version" } else { "-Wl,-v" };

// 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()
.arg("-Zlinker-features=+lld")
.arg("-Clink-self-contained=+linker")
.arg("-Zunstable-options")
.arg("-Wlinker-messages")
.link_arg(linker_version_flag)
.input("main.rs")
.run();
assert!(
find_lld_version_in_logs(output.stderr_utf8()),
"the LLD version string should be present in the output logs:\n{}",
output.stderr_utf8()
assert_rustc_uses_lld(
rustc()
.arg("-Zlinker-features=+lld")
.arg("-Clink-self-contained=+linker")
.arg("-Zunstable-options")
.input("main.rs"),
);

// It should not be used when we explicitly opt-out of lld.
let output = rustc()
.link_arg(linker_version_flag)
.arg("-Zlinker-features=-lld")
.arg("-Wlinker-messages")
.input("main.rs")
.run();
assert!(
!find_lld_version_in_logs(output.stderr_utf8()),
"the LLD version string should not be present in the output logs:\n{}",
output.stderr_utf8()
);
// It should not be used when we explicitly opt out of lld.
assert_rustc_doesnt_use_lld(rustc().arg("-Zlinker-features=-lld").input("main.rs"));

// While we're here, also check that the last linker feature flag "wins" when passed multiple
// times to rustc.
let output = rustc()
.link_arg(linker_version_flag)
.arg("-Clink-self-contained=+linker")
.arg("-Zunstable-options")
.arg("-Zlinker-features=-lld")
.arg("-Zlinker-features=+lld")
.arg("-Zlinker-features=-lld,+lld")
.arg("-Wlinker-messages")
.input("main.rs")
.run();
assert!(
find_lld_version_in_logs(output.stderr_utf8()),
"the LLD version string should be present in the output logs:\n{}",
output.stderr_utf8()
assert_rustc_uses_lld(
rustc()
.arg("-Clink-self-contained=+linker")
.arg("-Zunstable-options")
.arg("-Zlinker-features=-lld")
.arg("-Zlinker-features=+lld")
.arg("-Zlinker-features=-lld,+lld")
.input("main.rs"),
);
}

fn find_lld_version_in_logs(stderr: String) -> bool {
// Strip the `-Wlinker-messages` wrappers prefixing the linker output.
let stderr = Regex::new(r"warning: linker std(out|err):").unwrap().replace_all(&stderr, "");
let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap();
stderr.lines().any(|line| lld_version_re.is_match(line.trim()))
}
Loading