mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Split out linker-info from linker-messages
- Hide common linker output behind `linker-info` - Add tests - Account for different capitalization on windows-gnu when removing "warning" prefix - Add some more comments - Add macOS deployment-target test - Ignore linker warnings from trying to statically link glibc I don't know what's going on in `nofile-limit.rs` but I want no part of it. - Use a fake linker so tests are platform-independent
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
use rustc_fs_util::{TempDirBuilder, fix_windows_verbatim_for_gcc, try_canonicalize};
|
||||
use rustc_hir::attrs::NativeLibKind;
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_lint_defs::builtin::LINKER_INFO;
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
|
||||
use rustc_metadata::{
|
||||
@@ -60,10 +61,8 @@
|
||||
use super::{apple, versioned_llvm_target};
|
||||
use crate::base::needs_allocator_shim_for_linking;
|
||||
use crate::{
|
||||
CompiledModule, CompiledModules, CrateInfo, NativeLib, errors, looks_like_rust_object_file,
|
||||
};
|
||||
use crate::{
|
||||
CodegenLintLevels, CodegenResults, CompiledModule, CrateInfo, NativeLib, errors, looks_like_rust_object_file
|
||||
CodegenLintLevels, CompiledModule, CompiledModules, CrateInfo, NativeLib, errors,
|
||||
looks_like_rust_object_file,
|
||||
};
|
||||
|
||||
pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) {
|
||||
@@ -683,30 +682,105 @@ fn is_msvc_link_exe(sess: &Session) -> bool {
|
||||
&& linker_path.to_str() == Some("link.exe")
|
||||
}
|
||||
|
||||
fn is_macos_ld(sess: &Session) -> bool {
|
||||
let (_, flavor) = linker_and_flavor(sess);
|
||||
sess.target.is_like_darwin && matches!(flavor, LinkerFlavor::Darwin(_, Lld::No))
|
||||
}
|
||||
|
||||
fn is_windows_gnu_ld(sess: &Session) -> bool {
|
||||
let (_, flavor) = linker_and_flavor(sess);
|
||||
sess.target.is_like_windows
|
||||
&& !sess.target.is_like_msvc
|
||||
&& matches!(flavor, LinkerFlavor::Gnu(_, Lld::No))
|
||||
}
|
||||
|
||||
fn report_linker_output(sess: &Session, levels: CodegenLintLevels, stdout: &[u8], stderr: &[u8]) {
|
||||
let escaped_stderr = escape_string(&stderr);
|
||||
let mut escaped_stderr = escape_string(&stderr);
|
||||
let mut escaped_stdout = escape_string(&stdout);
|
||||
let mut linker_info = String::new();
|
||||
|
||||
info!("linker stderr:\n{}", &escaped_stderr);
|
||||
info!("linker stdout:\n{}", &escaped_stdout);
|
||||
|
||||
// Hide some progress messages from link.exe that we don't care about.
|
||||
// See https://github.com/chromium/chromium/blob/bfa41e41145ffc85f041384280caf2949bb7bd72/build/toolchain/win/tool_wrapper.py#L144-L146
|
||||
if is_msvc_link_exe(sess) {
|
||||
if let Ok(str) = str::from_utf8(&stdout) {
|
||||
let mut output = String::with_capacity(str.len());
|
||||
fn for_each(bytes: &[u8], mut f: impl FnMut(&str, &mut String)) -> String {
|
||||
let mut output = String::new();
|
||||
if let Ok(str) = str::from_utf8(bytes) {
|
||||
info!("line: {str}");
|
||||
output = String::with_capacity(str.len());
|
||||
for line in str.lines() {
|
||||
if line.starts_with(" Creating library")
|
||||
|| line.starts_with("Generating code")
|
||||
|| line.starts_with("Finished generating code")
|
||||
{
|
||||
continue;
|
||||
} else {
|
||||
output += line;
|
||||
output += "\r\n"
|
||||
}
|
||||
f(line.trim(), &mut output);
|
||||
}
|
||||
escaped_stdout = escape_string(output.trim().as_bytes())
|
||||
}
|
||||
escape_string(output.trim().as_bytes())
|
||||
}
|
||||
|
||||
if is_msvc_link_exe(sess) {
|
||||
info!("inferred MSVC link.exe");
|
||||
|
||||
escaped_stdout = for_each(&stdout, |line, output| {
|
||||
// Hide some progress messages from link.exe that we don't care about.
|
||||
// See https://github.com/chromium/chromium/blob/bfa41e41145ffc85f041384280caf2949bb7bd72/build/toolchain/win/tool_wrapper.py#L144-L146
|
||||
if line.starts_with(" Creating library")
|
||||
|| line.starts_with("Generating code")
|
||||
|| line.starts_with("Finished generating code")
|
||||
{
|
||||
linker_info += line;
|
||||
linker_info += "\r\n";
|
||||
} else {
|
||||
*output += line;
|
||||
*output += "\r\n"
|
||||
}
|
||||
});
|
||||
} else if is_macos_ld(sess) {
|
||||
info!("inferred macOS LD");
|
||||
|
||||
// FIXME: Tracked by https://github.com/rust-lang/rust/issues/136113
|
||||
let deployment_mismatch = |line: &str| {
|
||||
line.starts_with("ld: warning: object file (")
|
||||
&& line.contains("was built for newer 'macOS' version")
|
||||
&& line.contains("than being linked")
|
||||
};
|
||||
// FIXME: This is a real warning we would like to show, but it hits too many crates
|
||||
// to want to turn it on immediately.
|
||||
let search_path = |line: &str| {
|
||||
line.starts_with("ld: warning: search path '") && line.ends_with("' not found")
|
||||
};
|
||||
escaped_stderr = for_each(&stderr, |line, output| {
|
||||
// This duplicate library warning is just not helpful at all.
|
||||
if line.starts_with("ld: warning: ignoring duplicate libraries: ")
|
||||
|| deployment_mismatch(line)
|
||||
|| search_path(line)
|
||||
{
|
||||
linker_info += line;
|
||||
linker_info += "\n";
|
||||
} else {
|
||||
*output += line;
|
||||
*output += "\n"
|
||||
}
|
||||
});
|
||||
} else if is_windows_gnu_ld(sess) {
|
||||
info!("inferred Windows GNU LD");
|
||||
|
||||
let mut saw_exclude_symbol = false;
|
||||
// See https://github.com/rust-lang/rust/issues/112368.
|
||||
// FIXME: maybe check that binutils is older than 2.40 before downgrading this warning?
|
||||
let exclude_symbols = |line: &str| {
|
||||
line.starts_with("Warning: .drectve `-exclude-symbols:")
|
||||
&& line.ends_with("' unrecognized")
|
||||
};
|
||||
escaped_stderr = for_each(&stderr, |line, output| {
|
||||
if exclude_symbols(line) {
|
||||
saw_exclude_symbol = true;
|
||||
linker_info += line;
|
||||
linker_info += "\n";
|
||||
} else if saw_exclude_symbol && line == "Warning: corrupt .drectve at end of def file" {
|
||||
linker_info += line;
|
||||
linker_info += "\n";
|
||||
} else {
|
||||
*output += line;
|
||||
*output += "\n"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let lint_msg = |msg| {
|
||||
@@ -718,18 +792,27 @@ fn report_linker_output(sess: &Session, levels: CodegenLintLevels, stdout: &[u8]
|
||||
LinkerOutput { inner: msg },
|
||||
);
|
||||
};
|
||||
let lint_info = |msg| {
|
||||
diag_lint_level(sess, LINKER_INFO, levels.linker_info, None, LinkerOutput { inner: msg });
|
||||
};
|
||||
|
||||
if !escaped_stderr.is_empty() {
|
||||
// We already print `warning:` at the start of the diagnostic. Remove it from the linker output if present.
|
||||
let stderr = escaped_stderr
|
||||
.strip_prefix("warning: ")
|
||||
escaped_stderr =
|
||||
escaped_stderr.strip_prefix("warning: ").unwrap_or(&escaped_stderr).to_owned();
|
||||
// Windows GNU LD prints uppercase Warning
|
||||
escaped_stderr = escaped_stderr
|
||||
.strip_prefix("Warning: ")
|
||||
.unwrap_or(&escaped_stderr)
|
||||
.replace(": warning: ", ": ");
|
||||
lint_msg(format!("linker stderr: {stderr}"));
|
||||
lint_msg(format!("linker stderr: {escaped_stderr}"));
|
||||
}
|
||||
if !escaped_stdout.is_empty() {
|
||||
lint_msg(format!("linker stdout: {}", escaped_stdout))
|
||||
}
|
||||
if !linker_info.is_empty() {
|
||||
lint_info(linker_info);
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a dynamic library or executable.
|
||||
@@ -971,6 +1054,7 @@ fn link_natively(
|
||||
sess.dcx().abort_if_errors();
|
||||
}
|
||||
|
||||
info!("reporting linker output: flavor={flavor:?}");
|
||||
report_linker_output(sess, crate_info.lint_levels, &prog.stdout, &prog.stderr);
|
||||
}
|
||||
Err(e) => {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
use rustc_hir::CRATE_HIR_ID;
|
||||
use rustc_hir::attrs::{CfgEntry, NativeLibKind, WindowsSubsystemKind};
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
use rustc_lint_defs::builtin::LINKER_INFO;
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::WorkProduct;
|
||||
@@ -364,10 +365,14 @@ pub fn deserialize_rlink(
|
||||
#[derive(Copy, Clone, Debug, Encodable, Decodable)]
|
||||
pub struct CodegenLintLevels {
|
||||
linker_messages: LevelAndSource,
|
||||
linker_info: LevelAndSource,
|
||||
}
|
||||
|
||||
impl CodegenLintLevels {
|
||||
pub fn from_tcx(tcx: TyCtxt<'_>) -> Self {
|
||||
Self { linker_messages: tcx.lint_level_at_node(LINKER_MESSAGES, CRATE_HIR_ID) }
|
||||
Self {
|
||||
linker_messages: tcx.lint_level_at_node(LINKER_MESSAGES, CRATE_HIR_ID),
|
||||
linker_info: tcx.lint_level_at_node(LINKER_INFO, CRATE_HIR_ID),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
LARGE_ASSIGNMENTS,
|
||||
LATE_BOUND_LIFETIME_ARGUMENTS,
|
||||
LEGACY_DERIVE_HELPERS,
|
||||
LINKER_INFO,
|
||||
LINKER_MESSAGES,
|
||||
LONG_RUNNING_CONST_EVAL,
|
||||
LOSSY_PROVENANCE_CASTS,
|
||||
@@ -4062,6 +4063,40 @@
|
||||
"warnings emitted at runtime by the target-specific linker program"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `linker_info` lint forwards warnings from the linker that are known to be informational-only.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,ignore (needs CLI args, platform-specific)
|
||||
/// #[warn(linker_info)]
|
||||
/// fn main () {}
|
||||
/// ```
|
||||
///
|
||||
/// On MacOS, using `-C link-arg=-lc` and the default linker, this will produce
|
||||
///
|
||||
/// ```text
|
||||
/// warning: linker stderr: ld: ignoring duplicate libraries: '-lc'
|
||||
/// |
|
||||
/// note: the lint level is defined here
|
||||
/// --> ex.rs:1:9
|
||||
/// |
|
||||
/// 1 | #![warn(linker_info)]
|
||||
/// | ^^^^^^^^^^^^^^^
|
||||
/// ```
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Many linkers are very "chatty" and print lots of information that is not necessarily
|
||||
/// indicative of an issue. This output has been ignored for many years and is often not
|
||||
/// actionable by developers. It is silenced unless the developer specifically requests for it
|
||||
/// to be printed. See this tracking issue for more details:
|
||||
/// <https://github.com/rust-lang/rust/issues/136096>.
|
||||
pub LINKER_INFO,
|
||||
Allow,
|
||||
"linker warnings known to be informational-only and not indicative of a problem"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `named_arguments_used_positionally` lint detects cases where named arguments are only
|
||||
/// used positionally in format strings. This usage is valid but potentially very confusing.
|
||||
|
||||
@@ -1621,7 +1621,9 @@ fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute, style: Option<
|
||||
sym::expect,
|
||||
]) && let Some(meta) = attr.meta_item_list()
|
||||
&& meta.iter().any(|meta| {
|
||||
meta.meta_item().map_or(false, |item| item.path == sym::linker_messages)
|
||||
meta.meta_item().map_or(false, |item| {
|
||||
item.path == sym::linker_messages || item.path == sym::linker_info
|
||||
})
|
||||
})
|
||||
{
|
||||
if hir_id != CRATE_HIR_ID {
|
||||
|
||||
@@ -310,7 +310,7 @@ pub(crate) enum UnusedNote {
|
||||
#[note("`default_method_body_is_const` has been replaced with `const` on traits")]
|
||||
DefaultMethodBodyConst,
|
||||
#[note(
|
||||
"the `linker_messages` lint can only be controlled at the root of a crate that needs to be linked"
|
||||
"the `linker_messages` and `linker_info` lints can only be controlled at the root of a crate that needs to be linked"
|
||||
)]
|
||||
LinkerMessagesBinaryCrateOnly,
|
||||
}
|
||||
|
||||
@@ -1152,6 +1152,7 @@
|
||||
link_section,
|
||||
linkage,
|
||||
linker,
|
||||
linker_info,
|
||||
linker_messages,
|
||||
linkonce,
|
||||
linkonce_odr,
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/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
|
||||
@@ -0,0 +1 @@
|
||||
void foo() {}
|
||||
@@ -0,0 +1,8 @@
|
||||
#![warn(linker_info, linker_messages)]
|
||||
unsafe extern "C" {
|
||||
safe fn foo();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//@ only-apple
|
||||
//! Tests that deployment target linker warnings are shown as `linker-info`, not `linker-messages`
|
||||
|
||||
use run_make_support::external_deps::c_cxx_compiler::cc;
|
||||
use run_make_support::external_deps::llvm::llvm_ar;
|
||||
use run_make_support::{bare_rustc, diff};
|
||||
|
||||
fn main() {
|
||||
let cwd = std::env::current_dir().unwrap().to_str().unwrap().to_owned();
|
||||
|
||||
cc().arg("-c").arg("-mmacosx-version-min=15.5").output("foo.o").input("foo.c").run();
|
||||
llvm_ar().obj_to_ar().output_input("libfoo.a", "foo.o").run();
|
||||
|
||||
let warnings = bare_rustc()
|
||||
.arg("-L")
|
||||
.arg(format!("native={cwd}"))
|
||||
.arg("-lstatic=foo")
|
||||
.link_arg("-mmacosx-version-min=11.2")
|
||||
.input("main.rs")
|
||||
.crate_type("bin")
|
||||
.run()
|
||||
.stderr_utf8();
|
||||
|
||||
diff()
|
||||
.expected_file("warnings.txt")
|
||||
.actual_text("(rustc -W linker-info)", &warnings)
|
||||
.normalize(r"\(.*/rmake_out/", "(TEST_DIR/")
|
||||
.run()
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
warning: ld: warning: object file (TEST_DIR/libfoo.a[2](foo.o)) was built for newer 'macOS' version (15.5) than being linked (11.2)
|
||||
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> main.rs:1:9
|
||||
|
|
||||
1 | #![warn(linker_info, linker_messages)]
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// ignore-tidy-linelength
|
||||
|
||||
fn main() {
|
||||
println!(
|
||||
"Warning: .drectve `-exclude-symbols:_ZN28windows_gnu_corrupt_drective4main17h291ed884c1aada69E ' unrecognized"
|
||||
);
|
||||
println!("Warning: corrupt .drectve at end of def file");
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//@ only-windows-gnu
|
||||
//@ build-fail
|
||||
//@ compile-flags: -C linker={{src-base}}/linking/auxiliary/fake-linker.ps1
|
||||
#![deny(linker_info)]
|
||||
//~? ERROR Warning: .drectve
|
||||
fn main() {}
|
||||
@@ -0,0 +1,14 @@
|
||||
//@ only-windows-gnu
|
||||
|
||||
use run_make_support::{bare_rustc, rustc};
|
||||
|
||||
fn main() {
|
||||
// bare_rustc so that this doesn't try to cross-compile our linker
|
||||
bare_rustc().input("fake-linker.rs").output("fake-linker").run();
|
||||
rustc()
|
||||
.input("main.rs")
|
||||
.linker("./fake-linker")
|
||||
.arg("-Wlinker-messages")
|
||||
.run()
|
||||
.assert_stderr_contains("Warning: .drectve");
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//@ only-apple
|
||||
//@ compile-flags: -C link-arg=-lc -C link-arg=-lc
|
||||
//@ build-fail
|
||||
#![deny(linker_info)]
|
||||
//~? ERROR ignoring duplicate libraries
|
||||
fn main() {}
|
||||
@@ -0,0 +1,11 @@
|
||||
error: ld: warning: ignoring duplicate libraries: '-lc'
|
||||
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/macos-ignoring-duplicate.rs:4:9
|
||||
|
|
||||
LL | #![deny(linker_info)]
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
//@ only-apple
|
||||
//@ compile-flags: -C link-arg=-Wl,-L/no/such/file/or/directory
|
||||
//@ build-fail
|
||||
#![deny(linker_info)]
|
||||
//~? ERROR search path
|
||||
fn main() {}
|
||||
@@ -0,0 +1,11 @@
|
||||
error: ld: warning: search path '/no/such/file/or/directory' not found
|
||||
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/macos-search-path.rs:4:9
|
||||
|
|
||||
LL | #![deny(linker_info)]
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
@@ -20,7 +20,7 @@ warning: unused attribute
|
||||
LL | #![allow(linker_messages)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
||||
|
|
||||
= note: the `linker_messages` lint can only be controlled at the root of a crate that needs to be linked
|
||||
= note: the `linker_messages` and `linker_info` lints can only be controlled at the root of a crate that needs to be linked
|
||||
|
||||
warning: 2 warnings emitted
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
#![feature(exit_status_error)]
|
||||
#![feature(rustc_private)]
|
||||
// on aarch64, "Using 'getaddrinfo' in statically linked applications requires at runtime the shared
|
||||
// libraries from the glibc version used for linking"
|
||||
#![allow(linker_messages)]
|
||||
extern crate libc;
|
||||
|
||||
use std::os::unix::process::CommandExt;
|
||||
|
||||
Reference in New Issue
Block a user