Auto merge of #119286 - jyn514:linker-output, r=bjorn3
show linker output even if the linker succeeds
Show stderr and stderr by default, controlled by a new `linker_messages` lint.
fixes https://github.com/rust-lang/rust/issues/83436. fixes https://github.com/rust-lang/rust/issues/38206. cc 408986134
<!-- try-job: dist-x86_64-msvc -->
try-job: aarch64-apple
r? `@bjorn3`
This commit is contained in:
commit
f7cc13af82
26 changed files with 350 additions and 73 deletions
|
@ -15,12 +15,14 @@ use rustc_ast::CRATE_NODE_ID;
|
|||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_errors::{DiagCtxtHandle, LintDiagnostic};
|
||||
use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_macros::LintDiagnostic;
|
||||
use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
|
||||
use rustc_metadata::{find_native_static_library, walk_native_lib_search_dirs};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::lint::lint_level;
|
||||
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||
use rustc_middle::middle::dependency_format::Linkage;
|
||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||
|
@ -29,6 +31,7 @@ use rustc_session::config::{
|
|||
OutputType, PrintKind, SplitDwarfKind, Strip,
|
||||
};
|
||||
use rustc_session::cstore::DllImport;
|
||||
use rustc_session::lint::builtin::LINKER_MESSAGES;
|
||||
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
|
||||
use rustc_session::search_paths::PathKind;
|
||||
use rustc_session::utils::NativeLibKind;
|
||||
|
@ -749,6 +752,14 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[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.
|
||||
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
|
||||
|
@ -981,6 +992,11 @@ fn link_natively(
|
|||
|
||||
match prog {
|
||||
Ok(prog) => {
|
||||
let is_msvc_link_exe = sess.target.is_like_msvc
|
||||
&& flavor == LinkerFlavor::Msvc(Lld::No)
|
||||
// Match exactly "link.exe"
|
||||
&& linker_path.to_str() == Some("link.exe");
|
||||
|
||||
if !prog.status.success() {
|
||||
let mut output = prog.stderr.clone();
|
||||
output.extend_from_slice(&prog.stdout);
|
||||
|
@ -997,16 +1013,9 @@ fn link_natively(
|
|||
// is not a Microsoft LNK error then suggest a way to fix or
|
||||
// install the Visual Studio build tools.
|
||||
if let Some(code) = prog.status.code() {
|
||||
if sess.target.is_like_msvc
|
||||
&& flavor == LinkerFlavor::Msvc(Lld::No)
|
||||
// Respect the command line override
|
||||
&& sess.opts.cg.linker.is_none()
|
||||
// Match exactly "link.exe"
|
||||
&& linker_path.to_str() == Some("link.exe")
|
||||
// All Microsoft `link.exe` linking error codes are
|
||||
// four digit numbers in the range 1000 to 9999 inclusive
|
||||
&& (code < 1000 || code > 9999)
|
||||
{
|
||||
// All Microsoft `link.exe` linking ror codes are
|
||||
// four digit numbers in the range 1000 to 9999 inclusive
|
||||
if is_msvc_link_exe && (code < 1000 || code > 9999) {
|
||||
let is_vs_installed = windows_registry::find_vs_version().is_ok();
|
||||
let has_linker =
|
||||
windows_registry::find_tool(&sess.target.arch, "link.exe").is_some();
|
||||
|
@ -1028,8 +1037,49 @@ fn link_natively(
|
|||
|
||||
sess.dcx().abort_if_errors();
|
||||
}
|
||||
info!("linker stderr:\n{}", escape_string(&prog.stderr));
|
||||
info!("linker stdout:\n{}", escape_string(&prog.stdout));
|
||||
|
||||
let stderr = escape_string(&prog.stderr);
|
||||
let mut stdout = escape_string(&prog.stdout);
|
||||
info!("linker stderr:\n{}", &stderr);
|
||||
info!("linker stdout:\n{}", &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 {
|
||||
if let Ok(str) = str::from_utf8(&prog.stdout) {
|
||||
let mut output = String::with_capacity(str.len());
|
||||
for line in stdout.lines() {
|
||||
if line.starts_with(" Creating library")
|
||||
|| line.starts_with("Generating code")
|
||||
|| line.starts_with("Finished generating code")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
output += line;
|
||||
output += "\r\n"
|
||||
}
|
||||
stdout = escape_string(output.trim().as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
let (level, src) = codegen_results.crate_info.lint_levels.linker_messages;
|
||||
let lint = |msg| {
|
||||
lint_level(sess, LINKER_MESSAGES, level, src, None, |diag| {
|
||||
LinkerOutput { inner: msg }.decorate_lint(diag)
|
||||
})
|
||||
};
|
||||
|
||||
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 = stderr
|
||||
.strip_prefix("warning: ")
|
||||
.unwrap_or(&stderr)
|
||||
.replace(": warning: ", ": ");
|
||||
lint(format!("linker stderr: {stderr}"));
|
||||
}
|
||||
if !stdout.is_empty() {
|
||||
lint(format!("linker stdout: {}", stdout))
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
let linker_not_found = e.kind() == io::ErrorKind::NotFound;
|
||||
|
|
|
@ -44,7 +44,8 @@ use crate::mir::operand::OperandValue;
|
|||
use crate::mir::place::PlaceRef;
|
||||
use crate::traits::*;
|
||||
use crate::{
|
||||
CachedModuleCodegen, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, errors, meth, mir,
|
||||
CachedModuleCodegen, CodegenLintLevels, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
|
||||
errors, meth, mir,
|
||||
};
|
||||
|
||||
pub(crate) fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate {
|
||||
|
@ -924,6 +925,7 @@ impl CrateInfo {
|
|||
dependency_formats: Lrc::clone(tcx.dependency_formats(())),
|
||||
windows_subsystem,
|
||||
natvis_debugger_visualizers: Default::default(),
|
||||
lint_levels: CodegenLintLevels::from_tcx(tcx),
|
||||
};
|
||||
|
||||
info.native_libraries.reserve(n_crates);
|
||||
|
|
|
@ -29,18 +29,23 @@ use rustc_ast as ast;
|
|||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_hir::CRATE_HIR_ID;
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable};
|
||||
use rustc_middle::dep_graph::WorkProduct;
|
||||
use rustc_middle::lint::LintLevelSource;
|
||||
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||
use rustc_middle::middle::dependency_format::Dependencies;
|
||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_serialize::opaque::{FileEncoder, MemDecoder};
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
|
||||
use rustc_session::cstore::{self, CrateSource};
|
||||
use rustc_session::lint::Level;
|
||||
use rustc_session::lint::builtin::LINKER_MESSAGES;
|
||||
use rustc_session::utils::NativeLibKind;
|
||||
use rustc_span::Symbol;
|
||||
|
||||
|
@ -200,6 +205,7 @@ pub struct CrateInfo {
|
|||
pub dependency_formats: Lrc<Dependencies>,
|
||||
pub windows_subsystem: Option<String>,
|
||||
pub natvis_debugger_visualizers: BTreeSet<DebuggerVisualizerFile>,
|
||||
pub lint_levels: CodegenLintLevels,
|
||||
}
|
||||
|
||||
#[derive(Encodable, Decodable)]
|
||||
|
@ -302,3 +308,19 @@ impl CodegenResults {
|
|||
Ok((codegen_results, outputs))
|
||||
}
|
||||
}
|
||||
|
||||
/// A list of lint levels used in codegen.
|
||||
///
|
||||
/// When using `-Z link-only`, we don't have access to the tcx and must work
|
||||
/// solely from the `.rlink` file. `Lint`s are defined too early to be encodeable.
|
||||
/// Instead, encode exactly the information we need.
|
||||
#[derive(Copy, Clone, Debug, Encodable, Decodable)]
|
||||
pub struct CodegenLintLevels {
|
||||
linker_messages: (Level, LintLevelSource),
|
||||
}
|
||||
|
||||
impl CodegenLintLevels {
|
||||
pub fn from_tcx(tcx: TyCtxt<'_>) -> Self {
|
||||
Self { linker_messages: tcx.lint_level_at_node(LINKER_MESSAGES, CRATE_HIR_ID) }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue