Skip to content

Commit 58b1b3c

Browse files
Auto merge of #149937 - jyn514:linker-info, r=<try>
try enabling `linker-messages` by default again
2 parents eb171a2 + 3062f50 commit 58b1b3c

File tree

13 files changed

+236
-54
lines changed

13 files changed

+236
-54
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 137 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc_errors::{DiagCtxtHandle, LintDiagnostic};
2121
use rustc_fs_util::{TempDirBuilder, fix_windows_verbatim_for_gcc, try_canonicalize};
2222
use rustc_hir::attrs::NativeLibKind;
2323
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
24+
use rustc_lint_defs::builtin::LINKER_INFO;
2425
use rustc_macros::LintDiagnostic;
2526
use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
2627
use rustc_metadata::{
@@ -59,7 +60,8 @@ use super::rpath::{self, RPathConfig};
5960
use super::{apple, versioned_llvm_target};
6061
use crate::base::needs_allocator_shim_for_linking;
6162
use crate::{
62-
CodegenResults, CompiledModule, CrateInfo, NativeLib, errors, looks_like_rust_object_file,
63+
CodegenLintLevels, CodegenResults, CompiledModule, CrateInfo, NativeLib, errors,
64+
looks_like_rust_object_file,
6365
};
6466

6567
pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) {
@@ -669,6 +671,133 @@ struct LinkerOutput {
669671
inner: String,
670672
}
671673

674+
fn is_msvc_link_exe(sess: &Session) -> bool {
675+
let (linker_path, flavor) = linker_and_flavor(sess);
676+
sess.target.is_like_msvc
677+
&& flavor == LinkerFlavor::Msvc(Lld::No)
678+
// Match exactly "link.exe"
679+
&& linker_path.to_str() == Some("link.exe")
680+
}
681+
682+
fn is_macos_ld(sess: &Session) -> bool {
683+
let (_, flavor) = linker_and_flavor(sess);
684+
sess.target.is_like_darwin && matches!(flavor, LinkerFlavor::Darwin(_, Lld::No))
685+
}
686+
687+
fn is_windows_gnu_ld(sess: &Session) -> bool {
688+
let (_, flavor) = linker_and_flavor(sess);
689+
sess.target.is_like_windows
690+
&& !sess.target.is_like_msvc
691+
&& matches!(flavor, LinkerFlavor::Gnu(_, Lld::No))
692+
}
693+
694+
fn report_linker_output(sess: &Session, levels: CodegenLintLevels, stdout: &[u8], stderr: &[u8]) {
695+
let mut escaped_stderr = escape_string(&stderr);
696+
let mut escaped_stdout = escape_string(&stdout);
697+
let mut linker_info = String::new();
698+
699+
info!("linker stderr:\n{}", &escaped_stderr);
700+
info!("linker stdout:\n{}", &escaped_stdout);
701+
702+
fn for_each(bytes: &[u8], mut f: impl FnMut(&str, &mut String)) -> String {
703+
let mut output = String::new();
704+
if let Ok(str) = str::from_utf8(bytes) {
705+
info!("line: {str}");
706+
output = String::with_capacity(str.len());
707+
for line in str.lines() {
708+
f(line.trim(), &mut output);
709+
}
710+
}
711+
escape_string(output.trim().as_bytes())
712+
}
713+
714+
// Hide some progress messages from link.exe that we don't care about.
715+
// See https://github.com/chromium/chromium/blob/bfa41e41145ffc85f041384280caf2949bb7bd72/build/toolchain/win/tool_wrapper.py#L144-L146
716+
if is_msvc_link_exe(sess) {
717+
escaped_stdout = for_each(&stdout, |line, output| {
718+
if line.starts_with(" Creating library")
719+
|| line.starts_with("Generating code")
720+
|| line.starts_with("Finished generating code")
721+
{
722+
linker_info += line;
723+
linker_info += "\r\n";
724+
} else {
725+
*output += line;
726+
*output += "\r\n"
727+
}
728+
});
729+
} else if is_macos_ld(sess) {
730+
let deployment_mismatch = |line: &str| {
731+
line.starts_with("ld: warning: object file (")
732+
&& line.contains("was built for newer 'macOS' version")
733+
&& line.contains("than being linked")
734+
};
735+
let search_path = |line: &str| {
736+
line.starts_with("ld: warning: search path '") && line.ends_with("' not found")
737+
};
738+
escaped_stderr = for_each(&stderr, |line, output| {
739+
if line.starts_with("ld: warning: ignoring duplicate libraries: ")
740+
|| deployment_mismatch(line)
741+
|| search_path(line)
742+
{
743+
linker_info += line;
744+
linker_info += "\n";
745+
} else {
746+
*output += line;
747+
*output += "\n"
748+
}
749+
});
750+
} else if is_windows_gnu_ld(sess) {
751+
let mut saw_exclude_symbol = false;
752+
let exclude_symbols = |line: &str| {
753+
line.starts_with("Warning: .drectve `-exclude-symbols:")
754+
&& line.ends_with("' unrecognized")
755+
};
756+
// FIXME: are we sure this is stderr and not stdout?
757+
escaped_stderr = for_each(&stderr, |line, output| {
758+
if exclude_symbols(line) {
759+
saw_exclude_symbol = true;
760+
linker_info += line;
761+
linker_info += "\n";
762+
} else if saw_exclude_symbol && line == "Warning: corrupt .drectve at end of def file" {
763+
linker_info += line;
764+
linker_info += "\n";
765+
} else {
766+
*output += line;
767+
*output += "\n"
768+
}
769+
});
770+
}
771+
772+
let lint_msg = |msg| {
773+
lint_level(sess, LINKER_MESSAGES, levels.linker_messages, None, |diag| {
774+
LinkerOutput { inner: msg }.decorate_lint(diag)
775+
})
776+
};
777+
let lint_info = |msg| {
778+
lint_level(sess, LINKER_INFO, levels.linker_info, None, |diag| {
779+
LinkerOutput { inner: msg }.decorate_lint(diag)
780+
})
781+
};
782+
783+
if !escaped_stderr.is_empty() {
784+
// We already print `warning:` at the start of the diagnostic. Remove it from the linker output if present.
785+
escaped_stderr =
786+
escaped_stderr.strip_prefix("warning: ").unwrap_or(&escaped_stderr).to_owned();
787+
escaped_stderr = escaped_stderr
788+
.strip_prefix("Warning: ")
789+
.unwrap_or(&escaped_stderr)
790+
.replace(": warning: ", ": ");
791+
lint_msg(format!("linker stderr: {escaped_stderr}"));
792+
}
793+
if !escaped_stdout.is_empty() {
794+
lint_msg(format!("linker stdout: {}", escaped_stdout))
795+
}
796+
if !linker_info.is_empty() {
797+
lint_info(linker_info);
798+
}
799+
}
800+
672801
/// Create a dynamic library or executable.
673802
///
674803
/// This will invoke the system linker/cc to create the resulting file. This links to all upstream
@@ -855,11 +984,6 @@ fn link_natively(
855984

856985
match prog {
857986
Ok(prog) => {
858-
let is_msvc_link_exe = sess.target.is_like_msvc
859-
&& flavor == LinkerFlavor::Msvc(Lld::No)
860-
// Match exactly "link.exe"
861-
&& linker_path.to_str() == Some("link.exe");
862-
863987
if !prog.status.success() {
864988
let mut output = prog.stderr.clone();
865989
output.extend_from_slice(&prog.stdout);
@@ -879,7 +1003,7 @@ fn link_natively(
8791003
if let Some(code) = prog.status.code() {
8801004
// All Microsoft `link.exe` linking ror codes are
8811005
// four digit numbers in the range 1000 to 9999 inclusive
882-
if is_msvc_link_exe && (code < 1000 || code > 9999) {
1006+
if is_msvc_link_exe(sess) && (code < 1000 || code > 9999) {
8831007
let is_vs_installed = find_msvc_tools::find_vs_version().is_ok();
8841008
let has_linker =
8851009
find_msvc_tools::find_tool(sess.target.arch.desc(), "link.exe")
@@ -911,48 +1035,12 @@ fn link_natively(
9111035
sess.dcx().abort_if_errors();
9121036
}
9131037

914-
let stderr = escape_string(&prog.stderr);
915-
let mut stdout = escape_string(&prog.stdout);
916-
info!("linker stderr:\n{}", &stderr);
917-
info!("linker stdout:\n{}", &stdout);
918-
919-
// Hide some progress messages from link.exe that we don't care about.
920-
// See https://github.com/chromium/chromium/blob/bfa41e41145ffc85f041384280caf2949bb7bd72/build/toolchain/win/tool_wrapper.py#L144-L146
921-
if is_msvc_link_exe {
922-
if let Ok(str) = str::from_utf8(&prog.stdout) {
923-
let mut output = String::with_capacity(str.len());
924-
for line in stdout.lines() {
925-
if line.starts_with(" Creating library")
926-
|| line.starts_with("Generating code")
927-
|| line.starts_with("Finished generating code")
928-
{
929-
continue;
930-
}
931-
output += line;
932-
output += "\r\n"
933-
}
934-
stdout = escape_string(output.trim().as_bytes())
935-
}
936-
}
937-
938-
let level = codegen_results.crate_info.lint_levels.linker_messages;
939-
let lint = |msg| {
940-
lint_level(sess, LINKER_MESSAGES, level, None, |diag| {
941-
LinkerOutput { inner: msg }.decorate_lint(diag)
942-
})
943-
};
944-
945-
if !prog.stderr.is_empty() {
946-
// We already print `warning:` at the start of the diagnostic. Remove it from the linker output if present.
947-
let stderr = stderr
948-
.strip_prefix("warning: ")
949-
.unwrap_or(&stderr)
950-
.replace(": warning: ", ": ");
951-
lint(format!("linker stderr: {stderr}"));
952-
}
953-
if !stdout.is_empty() {
954-
lint(format!("linker stdout: {}", stdout))
955-
}
1038+
report_linker_output(
1039+
sess,
1040+
codegen_results.crate_info.lint_levels,
1041+
&prog.stdout,
1042+
&prog.stderr,
1043+
);
9561044
}
9571045
Err(e) => {
9581046
let linker_not_found = e.kind() == io::ErrorKind::NotFound;

compiler/rustc_codegen_ssa/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use rustc_data_structures::unord::UnordMap;
2626
use rustc_hir::CRATE_HIR_ID;
2727
use rustc_hir::attrs::{CfgEntry, NativeLibKind, WindowsSubsystemKind};
2828
use rustc_hir::def_id::CrateNum;
29+
use rustc_lint_defs::builtin::LINKER_INFO;
2930
use rustc_macros::{Decodable, Encodable, HashStable};
3031
use rustc_metadata::EncodedMetadata;
3132
use rustc_middle::dep_graph::WorkProduct;
@@ -360,10 +361,14 @@ impl CodegenResults {
360361
#[derive(Copy, Clone, Debug, Encodable, Decodable)]
361362
pub struct CodegenLintLevels {
362363
linker_messages: LevelAndSource,
364+
linker_info: LevelAndSource,
363365
}
364366

365367
impl CodegenLintLevels {
366368
pub fn from_tcx(tcx: TyCtxt<'_>) -> Self {
367-
Self { linker_messages: tcx.lint_level_at_node(LINKER_MESSAGES, CRATE_HIR_ID) }
369+
Self {
370+
linker_messages: tcx.lint_level_at_node(LINKER_MESSAGES, CRATE_HIR_ID),
371+
linker_info: tcx.lint_level_at_node(LINKER_INFO, CRATE_HIR_ID),
372+
}
368373
}
369374
}

compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ declare_lint_pass! {
5757
LARGE_ASSIGNMENTS,
5858
LATE_BOUND_LIFETIME_ARGUMENTS,
5959
LEGACY_DERIVE_HELPERS,
60+
LINKER_INFO,
6061
LINKER_MESSAGES,
6162
LONG_RUNNING_CONST_EVAL,
6263
LOSSY_PROVENANCE_CASTS,
@@ -4033,10 +4034,44 @@ declare_lint! {
40334034
/// and actionable warning of similar quality to our other diagnostics. See this tracking
40344035
/// issue for more details: <https://github.com/rust-lang/rust/issues/136096>.
40354036
pub LINKER_MESSAGES,
4036-
Allow,
4037+
Deny,
40374038
"warnings emitted at runtime by the target-specific linker program"
40384039
}
40394040

4041+
declare_lint! {
4042+
/// The `linker_info` lint forwards warnings from the linker that are known to be informational-only.
4043+
///
4044+
/// ### Example
4045+
///
4046+
/// ```rust,ignore (needs CLI args, platform-specific)
4047+
/// #[warn(linker_info)]
4048+
/// fn main () {}
4049+
/// ```
4050+
///
4051+
/// On MacOS, using `-C link-arg=-lc` and the default linker, this will produce
4052+
///
4053+
/// ```text
4054+
/// warning: linker stderr: ld: ignoring duplicate libraries: '-lc'
4055+
/// |
4056+
/// note: the lint level is defined here
4057+
/// --> ex.rs:1:9
4058+
/// |
4059+
/// 1 | #![warn(linker_info)]
4060+
/// | ^^^^^^^^^^^^^^^
4061+
/// ```
4062+
///
4063+
/// ### Explanation
4064+
///
4065+
/// Many linkers are very "chatty" and print lots of information that is not necessarily
4066+
/// indicative of an issue. This output has been ignored for many years and is often not
4067+
/// actionable by developers. It is silenced unless the developer specifically requests for it
4068+
/// to be printed. See this tracking issue for more details:
4069+
/// <https://github.com/rust-lang/rust/issues/136096>.
4070+
pub LINKER_INFO,
4071+
Allow,
4072+
"linker warnings known to be informational-only and not indicative of a problem"
4073+
}
4074+
40404075
declare_lint! {
40414076
/// The `named_arguments_used_positionally` lint detects cases where named arguments are only
40424077
/// used positionally in format strings. This usage is valid but potentially very confusing.

compiler/rustc_passes/messages.ftl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ passes_unused_empty_lints_note =
570570
attribute `{$name}` with an empty list has no effect
571571
572572
passes_unused_linker_messages_note =
573-
the `linker_messages` lint can only be controlled at the root of a crate that needs to be linked
573+
the `linker_messages` and `linker_info` lints can only be controlled at the root of a crate that needs to be linked
574574
575575
passes_unused_multiple =
576576
multiple `{$name}` attributes

compiler/rustc_passes/src/check_attr.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1639,7 +1639,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
16391639
} else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect])
16401640
&& let Some(meta) = attr.meta_item_list()
16411641
&& meta.iter().any(|meta| {
1642-
meta.meta_item().map_or(false, |item| item.path == sym::linker_messages)
1642+
meta.meta_item().map_or(false, |item| {
1643+
item.path == sym::linker_messages || item.path == sym::linker_info
1644+
})
16431645
})
16441646
{
16451647
if hir_id != CRATE_HIR_ID {

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,6 +1336,7 @@ symbols! {
13361336
link_section,
13371337
linkage,
13381338
linker,
1339+
linker_info,
13391340
linker_messages,
13401341
linkonce,
13411342
linkonce_odr,
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//@ only-apple
2+
//@ compile-flags: -C link-arg=-lc -C link-arg=-lc
3+
//@ build-fail
4+
#![deny(linker_info)]
5+
//~? ERROR ignoring duplicate libraries
6+
fn main() {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: ld: warning: ignoring duplicate libraries: '-lc'
2+
3+
|
4+
note: the lint level is defined here
5+
--> $DIR/macos-ignoring-duplicate.rs:4:9
6+
|
7+
LL | #![deny(linker_info)]
8+
| ^^^^^^^^^^^
9+
10+
error: aborting due to 1 previous error
11+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//@ only-apple
2+
//@ compile-flags: -C link-arg=-Wl,-L/no/such/file/or/directory
3+
//@ build-fail
4+
#![deny(linker_info)]
5+
//~? ERROR search path
6+
fn main() {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: ld: warning: search path '/no/such/file/or/directory' not found
2+
3+
|
4+
note: the lint level is defined here
5+
--> $DIR/macos-search-path.rs:4:9
6+
|
7+
LL | #![deny(linker_info)]
8+
| ^^^^^^^^^^^
9+
10+
error: aborting due to 1 previous error
11+

0 commit comments

Comments
 (0)