Skip to content

Commit

Permalink
show linker warnings even if it returns 0
Browse files Browse the repository at this point in the history
  • Loading branch information
jyn514 committed Dec 24, 2023
1 parent df9d457 commit 060a457
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 2 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_ssa/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ codegen_ssa_linker_file_stem = couldn't extract file stem from specified linker
codegen_ssa_linker_not_found = linker `{$linker_path}` not found
.note = {$error}
codegen_ssa_linker_output = {$inner}
codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for current linker
codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status}
Expand Down
25 changes: 23 additions & 2 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,15 @@ fn link_dwarf_object<'a>(
}
}

#[derive(Diagnostic)]
#[diag(codegen_ssa_linker_output)]
/// Translating this is kind of useless. We don't pass translation flags to the linker, so we'd just
/// end up with inconsistent languages within the same diagnostic. Ideally we'd accept strings in
/// `emit_warning`, but I didn't feel like doing that much of a refactor.
struct LinkerOutput {
inner: String,
}

/// Create a dynamic library or executable.
///
/// This will invoke the system linker/cc to create the resulting file. This links to all upstream
Expand Down Expand Up @@ -972,8 +981,20 @@ fn link_natively<'a>(

sess.abort_if_errors();
}
info!("linker stderr:\n{}", escape_string(&prog.stderr));
info!("linker stdout:\n{}", escape_string(&prog.stdout));

if !prog.stderr.is_empty() {
// We already print `warning:` at the start of the diagnostic. Remove it from the linker output if present.
let stderr = escape_string(&prog.stderr);
debug!("original stderr: {stderr}");
let stderr =
stderr.strip_prefix("warning: ").unwrap_or(&stderr).replace(" warning: ", " ");
sess.emit_warning(LinkerOutput { inner: format!("linker stderr: {stderr}") });
}
if !prog.stdout.is_empty() && sess.opts.verbose {
sess.emit_warning(LinkerOutput {
inner: format!("linker stdout: {}", escape_string(&prog.stdout)),
});
}
}
Err(e) => {
let linker_not_found = e.kind() == io::ErrorKind::NotFound;
Expand Down
17 changes: 17 additions & 0 deletions tests/run-make/linker-warning/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
include ../tools.mk

RUN_RUSTC := $(RUSTC_ORIGINAL) main.rs -o $(TMPDIR)/main -C linker=./fake-linker.sh

all:
# Run rustc with our fake linker, and make sure it shows warnings
$(RUN_RUSTC) -C link-arg=run_make_warn 2>&1 | $(CGREP) "warning: linker stderr: bar"

# Make sure it shows stdout, but only when --verbose is passed
$(RUN_RUSTC) -C link-arg=run_make_info --verbose 2>&1 | $(CGREP) "warning: linker stdout: foo"
$(RUN_RUSTC) -C link-arg=run_make_info 2>&1 | $(CGREP) -v "warning: linker stdout: foo"

# Make sure we short-circuit this new path if the linker exits with an error (so the diagnostic is less verbose)
rm -f $(TMPDIR)/main
$(RUN_RUSTC) -C link-arg=run_make_error 2>&1 | $(CGREP) "note: error: baz"
! [ -e $(TMPDIR)/main ]

17 changes: 17 additions & 0 deletions tests/run-make/linker-warning/fake-linker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/sh

code=0
while ! [ $# = 0 ]; do
case "$1" in
run_make_info) echo "foo"
;;
run_make_warn) echo "warning: bar" >&2
;;
run_make_error) echo "error: baz" >&2; code=1
;;
*) ;; # rustc passes lots of args we don't care about
esac
shift
done

exit $code
1 change: 1 addition & 0 deletions tests/run-make/linker-warning/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fn main() {}

0 comments on commit 060a457

Please sign in to comment.