Skip to content

Commit 87693d7

Browse files
authored
Rollup merge of rust-lang#133633 - jyn514:hide-linker-args, r=bjorn3,jyn514
don't show the full linker args unless `--verbose` is passed the linker arguments can be *very* long, especially for crates with many dependencies. often they are not useful. omit them unless the user specifically requests them. split out from rust-lang#119286. fixes rust-lang#109979. r? ```@bjorn3```
2 parents bad335c + 2a6a7be commit 87693d7

File tree

8 files changed

+126
-14
lines changed

8 files changed

+126
-14
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -992,12 +992,12 @@ fn link_natively(
992992
let mut output = prog.stderr.clone();
993993
output.extend_from_slice(&prog.stdout);
994994
let escaped_output = escape_linker_output(&output, flavor);
995-
// FIXME: Add UI tests for this error.
996995
let err = errors::LinkingFailed {
997996
linker_path: &linker_path,
998997
exit_status: prog.status,
999-
command: &cmd,
998+
command: cmd,
1000999
escaped_output,
1000+
verbose: sess.opts.verbose,
10011001
};
10021002
sess.dcx().emit_err(err);
10031003
// If MSVC's `link.exe` was expected but the return code

compiler/rustc_codegen_ssa/src/errors.rs

+66-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Errors emitted by codegen_ssa
22
33
use std::borrow::Cow;
4+
use std::ffi::OsString;
45
use std::io::Error;
56
use std::num::ParseIntError;
67
use std::path::{Path, PathBuf};
@@ -345,21 +346,82 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ThorinErrorWrapper {
345346
}
346347

347348
pub(crate) struct LinkingFailed<'a> {
348-
pub linker_path: &'a PathBuf,
349+
pub linker_path: &'a Path,
349350
pub exit_status: ExitStatus,
350-
pub command: &'a Command,
351+
pub command: Command,
351352
pub escaped_output: String,
353+
pub verbose: bool,
352354
}
353355

354356
impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
355-
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
357+
fn into_diag(mut self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
356358
let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_linking_failed);
357359
diag.arg("linker_path", format!("{}", self.linker_path.display()));
358360
diag.arg("exit_status", format!("{}", self.exit_status));
359361

360362
let contains_undefined_ref = self.escaped_output.contains("undefined reference to");
361363

362-
diag.note(format!("{:?}", self.command)).note(self.escaped_output);
364+
if self.verbose {
365+
diag.note(format!("{:?}", self.command));
366+
} else {
367+
enum ArgGroup {
368+
Regular(OsString),
369+
Objects(usize),
370+
Rlibs(PathBuf, Vec<OsString>),
371+
}
372+
373+
// Omit rust object files and fold rlibs in the error by default to make linker errors a
374+
// bit less verbose.
375+
let orig_args = self.command.take_args();
376+
let mut args: Vec<ArgGroup> = vec![];
377+
for arg in orig_args {
378+
if arg.as_encoded_bytes().ends_with(b".rcgu.o") {
379+
if let Some(ArgGroup::Objects(n)) = args.last_mut() {
380+
*n += 1;
381+
} else {
382+
args.push(ArgGroup::Objects(1));
383+
}
384+
} else if arg.as_encoded_bytes().ends_with(b".rlib") {
385+
let rlib_path = Path::new(&arg);
386+
let dir = rlib_path.parent().unwrap();
387+
let filename = rlib_path.file_name().unwrap().to_owned();
388+
if let Some(ArgGroup::Rlibs(parent, rlibs)) = args.last_mut() {
389+
if parent == dir {
390+
rlibs.push(filename);
391+
} else {
392+
args.push(ArgGroup::Rlibs(dir.to_owned(), vec![filename]));
393+
}
394+
} else {
395+
args.push(ArgGroup::Rlibs(dir.to_owned(), vec![filename]));
396+
}
397+
} else {
398+
args.push(ArgGroup::Regular(arg));
399+
}
400+
}
401+
self.command.args(args.into_iter().map(|arg_group| match arg_group {
402+
ArgGroup::Regular(arg) => arg,
403+
ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")),
404+
ArgGroup::Rlibs(dir, rlibs) => {
405+
let mut arg = dir.into_os_string();
406+
arg.push("/{");
407+
let mut first = true;
408+
for rlib in rlibs {
409+
if !first {
410+
arg.push(",");
411+
}
412+
first = false;
413+
arg.push(rlib);
414+
}
415+
arg.push("}");
416+
arg
417+
}
418+
}));
419+
420+
diag.note(format!("{:?}", self.command));
421+
diag.note("some arguments are omitted. use `--verbose` to show all linker arguments");
422+
}
423+
424+
diag.note(self.escaped_output);
363425

364426
// Trying to match an error from OS linkers
365427
// which by now we have no way to translate.

src/tools/run-make-support/src/external_deps/rustc.rs

+6
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,12 @@ impl Rustc {
325325
self
326326
}
327327

328+
/// Pass the `--verbose` flag.
329+
pub fn verbose(&mut self) -> &mut Self {
330+
self.cmd.arg("--verbose");
331+
self
332+
}
333+
328334
/// `EXTRARSCXXFLAGS`
329335
pub fn extra_rs_cxx_flags(&mut self) -> &mut Self {
330336
// Adapted from tools.mk (trimmed):

tests/run-make/link-args-order/rmake.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,17 @@ fn main() {
1515
.link_args("b c")
1616
.link_args("d e")
1717
.link_arg("f")
18+
.arg("--print=link-args")
1819
.run_fail()
19-
.assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#);
20+
.assert_stdout_contains(r#""a" "b" "c" "d" "e" "f""#);
2021
rustc()
2122
.input("empty.rs")
2223
.linker_flavor(linker)
2324
.arg("-Zpre-link-arg=a")
2425
.arg("-Zpre-link-args=b c")
2526
.arg("-Zpre-link-args=d e")
2627
.arg("-Zpre-link-arg=f")
28+
.arg("--print=link-args")
2729
.run_fail()
28-
.assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#);
30+
.assert_stdout_contains(r#""a" "b" "c" "d" "e" "f""#);
2931
}

tests/run-make/link-dedup/rmake.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ fn main() {
1414
rustc().input("depb.rs").run();
1515
rustc().input("depc.rs").run();
1616

17-
let output = rustc().input("empty.rs").cfg("bar").run_fail();
18-
output.assert_stderr_contains(needle_from_libs(&["testa", "testb", "testa"]));
17+
let output = rustc().input("empty.rs").cfg("bar").arg("--print=link-args").run_fail();
18+
output.assert_stdout_contains(needle_from_libs(&["testa", "testb", "testa"]));
1919

20-
let output = rustc().input("empty.rs").run_fail();
21-
output.assert_stderr_contains(needle_from_libs(&["testa"]));
22-
output.assert_stderr_not_contains(needle_from_libs(&["testb"]));
23-
output.assert_stderr_not_contains(needle_from_libs(&["testa", "testa", "testa"]));
20+
let output = rustc().input("empty.rs").arg("--print=link-args").run_fail();
21+
output.assert_stdout_contains(needle_from_libs(&["testa"]));
22+
output.assert_stdout_not_contains(needle_from_libs(&["testb"]));
23+
output.assert_stdout_not_contains(needle_from_libs(&["testa", "testa", "testa"]));
2424
// Adjacent identical native libraries are no longer deduplicated if
2525
// they come from different crates (https://github.com/rust-lang/rust/pull/103311)
2626
// so the following will fail:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
fn main() {
2+
for arg in std::env::args() {
3+
match &*arg {
4+
"run_make_info" => println!("foo"),
5+
"run_make_warn" => eprintln!("warning: bar"),
6+
"run_make_error" => {
7+
eprintln!("error: baz");
8+
std::process::exit(1);
9+
}
10+
_ => (),
11+
}
12+
}
13+
}

tests/run-make/linker-warning/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fn main() {}
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use run_make_support::{Rustc, rustc};
2+
3+
fn run_rustc() -> Rustc {
4+
let mut rustc = rustc();
5+
rustc.arg("main.rs").output("main").linker("./fake-linker");
6+
rustc
7+
}
8+
9+
fn main() {
10+
// first, compile our linker
11+
rustc().arg("fake-linker.rs").output("fake-linker").run();
12+
13+
// Make sure we don't show the linker args unless `--verbose` is passed
14+
run_rustc()
15+
.link_arg("run_make_error")
16+
.verbose()
17+
.run_fail()
18+
.assert_stderr_contains_regex("fake-linker.*run_make_error")
19+
.assert_stderr_not_contains("object files omitted")
20+
.assert_stderr_contains_regex(r"lib[/\\]libstd");
21+
run_rustc()
22+
.link_arg("run_make_error")
23+
.run_fail()
24+
.assert_stderr_contains("fake-linker")
25+
.assert_stderr_contains("object files omitted")
26+
.assert_stderr_contains_regex(r"\{")
27+
.assert_stderr_not_contains_regex(r"lib[/\\]libstd");
28+
}

0 commit comments

Comments
 (0)