Shorten linker output even more when --verbose
is not present
- Don't show environment variables. Seeing PATH is almost never useful, and it can be extremely long. - For .rlibs in the sysroot, replace crate hashes with a `"-*"` string. This will expand to the full crate name when pasted into the shell. - Move `.rlib` to outside the glob. - Abbreviate the sysroot path to `<sysroot>` wherever it appears in the arguments. This also adds an example of the linker output as a run-make test. Currently it only runs on x86_64-unknown-linux-gnu, because each platform has its own linker arguments. So that it's stable across machines, pass BUILD_ROOT as an argument through compiletest through to run-make tests. - Only use linker-flavor=gnu-cc if we're actually going to compare the output. It doesn't exist on MacOS.
This commit is contained in:
parent
f7cc13af82
commit
c1b4ab0e73
11 changed files with 118 additions and 28 deletions
|
@ -3537,6 +3537,7 @@ dependencies = [
|
||||||
"ar_archive_writer",
|
"ar_archive_writer",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
"bstr",
|
||||||
"cc",
|
"cc",
|
||||||
"either",
|
"either",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
|
|
@ -8,6 +8,7 @@ edition = "2021"
|
||||||
ar_archive_writer = "0.4.2"
|
ar_archive_writer = "0.4.2"
|
||||||
arrayvec = { version = "0.7", default-features = false }
|
arrayvec = { version = "0.7", default-features = false }
|
||||||
bitflags = "2.4.1"
|
bitflags = "2.4.1"
|
||||||
|
bstr = "1.11.3"
|
||||||
# Pinned so `cargo update` bumps don't cause breakage. Please also update the
|
# Pinned so `cargo update` bumps don't cause breakage. Please also update the
|
||||||
# `cc` in `rustc_llvm` if you update the `cc` here.
|
# `cc` in `rustc_llvm` if you update the `cc` here.
|
||||||
cc = "=1.2.7"
|
cc = "=1.2.7"
|
||||||
|
|
|
@ -13,6 +13,7 @@ pub(crate) struct Command {
|
||||||
args: Vec<OsString>,
|
args: Vec<OsString>,
|
||||||
env: Vec<(OsString, OsString)>,
|
env: Vec<(OsString, OsString)>,
|
||||||
env_remove: Vec<OsString>,
|
env_remove: Vec<OsString>,
|
||||||
|
env_clear: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -36,7 +37,13 @@ impl Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _new(program: Program) -> Command {
|
fn _new(program: Program) -> Command {
|
||||||
Command { program, args: Vec::new(), env: Vec::new(), env_remove: Vec::new() }
|
Command {
|
||||||
|
program,
|
||||||
|
args: Vec::new(),
|
||||||
|
env: Vec::new(),
|
||||||
|
env_remove: Vec::new(),
|
||||||
|
env_clear: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn arg<P: AsRef<OsStr>>(&mut self, arg: P) -> &mut Command {
|
pub(crate) fn arg<P: AsRef<OsStr>>(&mut self, arg: P) -> &mut Command {
|
||||||
|
@ -79,6 +86,11 @@ impl Command {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn env_clear(&mut self) -> &mut Command {
|
||||||
|
self.env_clear = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn _env_remove(&mut self, key: &OsStr) {
|
fn _env_remove(&mut self, key: &OsStr) {
|
||||||
self.env_remove.push(key.to_owned());
|
self.env_remove.push(key.to_owned());
|
||||||
}
|
}
|
||||||
|
@ -106,6 +118,9 @@ impl Command {
|
||||||
for k in &self.env_remove {
|
for k in &self.env_remove {
|
||||||
ret.env_remove(k);
|
ret.env_remove(k);
|
||||||
}
|
}
|
||||||
|
if self.env_clear {
|
||||||
|
ret.env_clear();
|
||||||
|
}
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1007,6 +1007,7 @@ fn link_natively(
|
||||||
command: cmd,
|
command: cmd,
|
||||||
escaped_output,
|
escaped_output,
|
||||||
verbose: sess.opts.verbose,
|
verbose: sess.opts.verbose,
|
||||||
|
sysroot_dir: sess.sysroot.clone(),
|
||||||
};
|
};
|
||||||
sess.dcx().emit_err(err);
|
sess.dcx().emit_err(err);
|
||||||
// If MSVC's `link.exe` was expected but the return code
|
// If MSVC's `link.exe` was expected but the return code
|
||||||
|
|
|
@ -351,6 +351,7 @@ pub(crate) struct LinkingFailed<'a> {
|
||||||
pub command: Command,
|
pub command: Command,
|
||||||
pub escaped_output: String,
|
pub escaped_output: String,
|
||||||
pub verbose: bool,
|
pub verbose: bool,
|
||||||
|
pub sysroot_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
|
impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
|
||||||
|
@ -364,6 +365,8 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
|
||||||
if self.verbose {
|
if self.verbose {
|
||||||
diag.note(format!("{:?}", self.command));
|
diag.note(format!("{:?}", self.command));
|
||||||
} else {
|
} else {
|
||||||
|
self.command.env_clear();
|
||||||
|
|
||||||
enum ArgGroup {
|
enum ArgGroup {
|
||||||
Regular(OsString),
|
Regular(OsString),
|
||||||
Objects(usize),
|
Objects(usize),
|
||||||
|
@ -398,26 +401,55 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
|
||||||
args.push(ArgGroup::Regular(arg));
|
args.push(ArgGroup::Regular(arg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.command.args(args.into_iter().map(|arg_group| match arg_group {
|
let crate_hash = regex::bytes::Regex::new(r"-[0-9a-f]+\.rlib$").unwrap();
|
||||||
ArgGroup::Regular(arg) => arg,
|
self.command.args(args.into_iter().map(|arg_group| {
|
||||||
|
match arg_group {
|
||||||
|
// SAFETY: we are only matching on ASCII, not any surrogate pairs, so any replacements we do will still be valid.
|
||||||
|
ArgGroup::Regular(arg) => unsafe {
|
||||||
|
use bstr::ByteSlice;
|
||||||
|
OsString::from_encoded_bytes_unchecked(
|
||||||
|
arg.as_encoded_bytes().replace(
|
||||||
|
self.sysroot_dir.as_os_str().as_encoded_bytes(),
|
||||||
|
b"<sysroot>",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")),
|
ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")),
|
||||||
ArgGroup::Rlibs(dir, rlibs) => {
|
ArgGroup::Rlibs(mut dir, rlibs) => {
|
||||||
|
let is_sysroot_dir = match dir.strip_prefix(&self.sysroot_dir) {
|
||||||
|
Ok(short) => {
|
||||||
|
dir = Path::new("<sysroot>").join(short);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Err(_) => false,
|
||||||
|
};
|
||||||
let mut arg = dir.into_os_string();
|
let mut arg = dir.into_os_string();
|
||||||
arg.push("/{");
|
arg.push("/{");
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for rlib in rlibs {
|
for mut rlib in rlibs {
|
||||||
if !first {
|
if !first {
|
||||||
arg.push(",");
|
arg.push(",");
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
if is_sysroot_dir {
|
||||||
|
// SAFETY: Regex works one byte at a type, and our regex will not match surrogate pairs (because it only matches ascii).
|
||||||
|
rlib = unsafe {
|
||||||
|
OsString::from_encoded_bytes_unchecked(
|
||||||
|
crate_hash
|
||||||
|
.replace(rlib.as_encoded_bytes(), b"-*")
|
||||||
|
.into_owned(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
arg.push(rlib);
|
arg.push(rlib);
|
||||||
}
|
}
|
||||||
arg.push("}");
|
arg.push("}.rlib");
|
||||||
arg
|
arg
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
diag.note(format!("{:?}", self.command));
|
diag.note(format!("{:?}", self.command).trim_start_matches("env -i").to_owned());
|
||||||
diag.note("some arguments are omitted. use `--verbose` to show all linker arguments");
|
diag.note("some arguments are omitted. use `--verbose` to show all linker arguments");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -414,6 +414,8 @@ impl TestCx<'_> {
|
||||||
// Provide path to checkout root. This is the top-level directory containing
|
// Provide path to checkout root. This is the top-level directory containing
|
||||||
// rust-lang/rust checkout.
|
// rust-lang/rust checkout.
|
||||||
.env("SOURCE_ROOT", &source_root)
|
.env("SOURCE_ROOT", &source_root)
|
||||||
|
// Path to the build directory. This is usually the same as `source_root.join("build").join("host")`.
|
||||||
|
.env("BUILD_ROOT", &build_root)
|
||||||
// Provide path to stage-corresponding rustc.
|
// Provide path to stage-corresponding rustc.
|
||||||
.env("RUSTC", &self.config.rustc_path)
|
.env("RUSTC", &self.config.rustc_path)
|
||||||
// Provide the directory to libraries that are needed to run the *compiler*. This is not
|
// Provide the directory to libraries that are needed to run the *compiler*. This is not
|
||||||
|
|
|
@ -90,7 +90,7 @@ pub use artifact_names::{
|
||||||
/// Path-related helpers.
|
/// Path-related helpers.
|
||||||
pub use path_helpers::{
|
pub use path_helpers::{
|
||||||
cwd, filename_contains, filename_not_in_denylist, has_extension, has_prefix, has_suffix,
|
cwd, filename_contains, filename_not_in_denylist, has_extension, has_prefix, has_suffix,
|
||||||
not_contains, path, shallow_find_files, source_root,
|
not_contains, path, shallow_find_files, build_root, source_root,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Helpers for scoped test execution where certain properties are attempted to be maintained.
|
/// Helpers for scoped test execution where certain properties are attempted to be maintained.
|
||||||
|
|
|
@ -34,6 +34,12 @@ pub fn source_root() -> PathBuf {
|
||||||
env_var("SOURCE_ROOT").into()
|
env_var("SOURCE_ROOT").into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Path to the build directory root.
|
||||||
|
#[must_use]
|
||||||
|
pub fn build_root() -> PathBuf {
|
||||||
|
env_var("BUILD_ROOT").into()
|
||||||
|
}
|
||||||
|
|
||||||
/// Browse the directory `path` non-recursively and return all files which respect the parameters
|
/// Browse the directory `path` non-recursively and return all files which respect the parameters
|
||||||
/// outlined by `closure`.
|
/// outlined by `closure`.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
|
|
@ -253,6 +253,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"blake3",
|
"blake3",
|
||||||
"block-buffer",
|
"block-buffer",
|
||||||
|
"bstr",
|
||||||
"byteorder", // via ruzstd in object in thorin-dwp
|
"byteorder", // via ruzstd in object in thorin-dwp
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
|
|
@ -1,8 +1,19 @@
|
||||||
use run_make_support::{Rustc, rustc};
|
use run_make_support::{Rustc, diff, regex, rustc};
|
||||||
|
|
||||||
fn run_rustc() -> Rustc {
|
fn run_rustc() -> Rustc {
|
||||||
let mut rustc = rustc();
|
let mut rustc = rustc();
|
||||||
rustc.arg("main.rs").output("main").linker("./fake-linker");
|
rustc
|
||||||
|
.arg("main.rs")
|
||||||
|
// NOTE: `link-self-contained` can vary depending on config.toml.
|
||||||
|
// Make sure we use a consistent value.
|
||||||
|
.arg("-Clink-self-contained=-linker")
|
||||||
|
.arg("-Zunstable-options")
|
||||||
|
.output("main")
|
||||||
|
.linker("./fake-linker");
|
||||||
|
if run_make_support::target() == "x86_64-unknown-linux-gnu" {
|
||||||
|
// The value of `rust.lld` is different between CI and locally. Override it explicitly.
|
||||||
|
rustc.arg("-Clinker-flavor=gnu-cc");
|
||||||
|
}
|
||||||
rustc
|
rustc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,21 +36,32 @@ fn main() {
|
||||||
run_rustc().link_arg("run_make_error").run_fail().assert_stderr_contains("note: error: baz");
|
run_rustc().link_arg("run_make_error").run_fail().assert_stderr_contains("note: error: baz");
|
||||||
|
|
||||||
// Make sure we don't show the linker args unless `--verbose` is passed
|
// Make sure we don't show the linker args unless `--verbose` is passed
|
||||||
run_rustc()
|
let out = run_rustc().link_arg("run_make_error").verbose().run_fail();
|
||||||
.link_arg("run_make_error")
|
out.assert_stderr_contains_regex("fake-linker.*run_make_error")
|
||||||
.verbose()
|
|
||||||
.run_fail()
|
|
||||||
.assert_stderr_contains_regex("fake-linker.*run_make_error")
|
|
||||||
.assert_stderr_not_contains("object files omitted")
|
.assert_stderr_not_contains("object files omitted")
|
||||||
|
.assert_stderr_contains(r".rcgu.o")
|
||||||
.assert_stderr_contains_regex(r"lib(/|\\\\)libstd");
|
.assert_stderr_contains_regex(r"lib(/|\\\\)libstd");
|
||||||
run_rustc()
|
|
||||||
.link_arg("run_make_error")
|
let out = run_rustc().link_arg("run_make_error").run_fail();
|
||||||
.run_fail()
|
out.assert_stderr_contains("fake-linker")
|
||||||
.assert_stderr_contains("fake-linker")
|
|
||||||
.assert_stderr_contains("object files omitted")
|
.assert_stderr_contains("object files omitted")
|
||||||
.assert_stderr_contains_regex(r"\{")
|
.assert_stderr_contains_regex(r"\{")
|
||||||
|
.assert_stderr_not_contains(r".rcgu.o")
|
||||||
.assert_stderr_not_contains_regex(r"lib(/|\\\\)libstd");
|
.assert_stderr_not_contains_regex(r"lib(/|\\\\)libstd");
|
||||||
|
|
||||||
|
// FIXME: we should have a version of this for mac and windows
|
||||||
|
if run_make_support::target() == "x86_64-unknown-linux-gnu" {
|
||||||
|
diff()
|
||||||
|
.expected_file("short-error.txt")
|
||||||
|
.actual_text("(linker error)", out.stderr())
|
||||||
|
.normalize(r#"/rustc[^/]*/"#, "/rustc/")
|
||||||
|
.normalize(
|
||||||
|
regex::escape(run_make_support::build_root().to_str().unwrap()),
|
||||||
|
"/build-root",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure we show linker warnings even across `-Z no-link`
|
// Make sure we show linker warnings even across `-Z no-link`
|
||||||
rustc()
|
rustc()
|
||||||
.arg("-Zno-link")
|
.arg("-Zno-link")
|
||||||
|
|
9
tests/run-make/linker-warning/short-error.txt
Normal file
9
tests/run-make/linker-warning/short-error.txt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
error: linking with `./fake-linker` failed: exit status: 1
|
||||||
|
|
|
||||||
|
= note: "./fake-linker" "-m64" "/tmp/rustc/symbols.o" "<2 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,libcfg_if-*,liblibc-*,liballoc-*,librustc_std_workspace_core-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/build-root/test/run-make/linker-warning/rmake_out" "-L" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "run_make_error"
|
||||||
|
= note: some arguments are omitted. use `--verbose` to show all linker arguments
|
||||||
|
= note: error: baz
|
||||||
|
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue