@@ -15,12 +15,14 @@ use rustc_ast::CRATE_NODE_ID;
1515use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
1616use rustc_data_structures:: memmap:: Mmap ;
1717use rustc_data_structures:: temp_dir:: MaybeTempDir ;
18- use rustc_errors:: DiagCtxtHandle ;
18+ use rustc_errors:: { DiagCtxtHandle , LintDiagnostic } ;
1919use rustc_fs_util:: { fix_windows_verbatim_for_gcc, try_canonicalize} ;
2020use rustc_hir:: def_id:: { CrateNum , LOCAL_CRATE } ;
21+ use rustc_macros:: LintDiagnostic ;
2122use rustc_metadata:: fs:: { METADATA_FILENAME , copy_to_stdout, emit_wrapper_file} ;
2223use rustc_metadata:: { find_native_static_library, walk_native_lib_search_dirs} ;
2324use rustc_middle:: bug;
25+ use rustc_middle:: lint:: lint_level;
2426use rustc_middle:: middle:: debugger_visualizer:: DebuggerVisualizerFile ;
2527use rustc_middle:: middle:: dependency_format:: Linkage ;
2628use rustc_middle:: middle:: exported_symbols:: SymbolExportKind ;
@@ -29,6 +31,7 @@ use rustc_session::config::{
2931 OutputType , PrintKind , SplitDwarfKind , Strip ,
3032} ;
3133use rustc_session:: cstore:: DllImport ;
34+ use rustc_session:: lint:: builtin:: LINKER_MESSAGES ;
3235use rustc_session:: output:: { check_file_is_writeable, invalid_output_for_target, out_filename} ;
3336use rustc_session:: search_paths:: PathKind ;
3437use rustc_session:: utils:: NativeLibKind ;
@@ -749,6 +752,14 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out
749752 }
750753}
751754
755+ #[ derive( LintDiagnostic ) ]
756+ #[ diag( codegen_ssa_linker_output) ]
757+ /// Translating this is kind of useless. We don't pass translation flags to the linker, so we'd just
758+ /// end up with inconsistent languages within the same diagnostic.
759+ struct LinkerOutput {
760+ inner : String ,
761+ }
762+
752763/// Create a dynamic library or executable.
753764///
754765/// This will invoke the system linker/cc to create the resulting file. This links to all upstream
@@ -981,6 +992,11 @@ fn link_natively(
981992
982993 match prog {
983994 Ok ( prog) => {
995+ let is_msvc_link_exe = sess. target . is_like_msvc
996+ && flavor == LinkerFlavor :: Msvc ( Lld :: No )
997+ // Match exactly "link.exe"
998+ && linker_path. to_str ( ) == Some ( "link.exe" ) ;
999+
9841000 if !prog. status . success ( ) {
9851001 let mut output = prog. stderr . clone ( ) ;
9861002 output. extend_from_slice ( & prog. stdout ) ;
@@ -997,16 +1013,9 @@ fn link_natively(
9971013 // is not a Microsoft LNK error then suggest a way to fix or
9981014 // install the Visual Studio build tools.
9991015 if let Some ( code) = prog. status . code ( ) {
1000- if sess. target . is_like_msvc
1001- && flavor == LinkerFlavor :: Msvc ( Lld :: No )
1002- // Respect the command line override
1003- && sess. opts . cg . linker . is_none ( )
1004- // Match exactly "link.exe"
1005- && linker_path. to_str ( ) == Some ( "link.exe" )
1006- // All Microsoft `link.exe` linking error codes are
1007- // four digit numbers in the range 1000 to 9999 inclusive
1008- && ( code < 1000 || code > 9999 )
1009- {
1016+ // All Microsoft `link.exe` linking ror codes are
1017+ // four digit numbers in the range 1000 to 9999 inclusive
1018+ if is_msvc_link_exe && ( code < 1000 || code > 9999 ) {
10101019 let is_vs_installed = windows_registry:: find_vs_version ( ) . is_ok ( ) ;
10111020 let has_linker =
10121021 windows_registry:: find_tool ( & sess. target . arch , "link.exe" ) . is_some ( ) ;
@@ -1028,8 +1037,49 @@ fn link_natively(
10281037
10291038 sess. dcx ( ) . abort_if_errors ( ) ;
10301039 }
1031- info ! ( "linker stderr:\n {}" , escape_string( & prog. stderr) ) ;
1032- info ! ( "linker stdout:\n {}" , escape_string( & prog. stdout) ) ;
1040+
1041+ let stderr = escape_string ( & prog. stderr ) ;
1042+ let mut stdout = escape_string ( & prog. stdout ) ;
1043+ info ! ( "linker stderr:\n {}" , & stderr) ;
1044+ info ! ( "linker stdout:\n {}" , & stdout) ;
1045+
1046+ // Hide some progress messages from link.exe that we don't care about.
1047+ // See https://github.com/chromium/chromium/blob/bfa41e41145ffc85f041384280caf2949bb7bd72/build/toolchain/win/tool_wrapper.py#L144-L146
1048+ if is_msvc_link_exe {
1049+ if let Ok ( str) = str:: from_utf8 ( & prog. stdout ) {
1050+ let mut output = String :: with_capacity ( str. len ( ) ) ;
1051+ for line in stdout. lines ( ) {
1052+ if line. starts_with ( " Creating library" )
1053+ || line. starts_with ( "Generating code" )
1054+ || line. starts_with ( "Finished generating code" )
1055+ {
1056+ continue ;
1057+ }
1058+ output += line;
1059+ output += "\r \n "
1060+ }
1061+ stdout = escape_string ( output. trim ( ) . as_bytes ( ) )
1062+ }
1063+ }
1064+
1065+ let ( level, src) = codegen_results. crate_info . lint_levels . linker_messages ;
1066+ let lint = |msg| {
1067+ lint_level ( sess, LINKER_MESSAGES , level, src, None , |diag| {
1068+ LinkerOutput { inner : msg } . decorate_lint ( diag)
1069+ } )
1070+ } ;
1071+
1072+ if !prog. stderr . is_empty ( ) {
1073+ // We already print `warning:` at the start of the diagnostic. Remove it from the linker output if present.
1074+ let stderr = stderr
1075+ . strip_prefix ( "warning: " )
1076+ . unwrap_or ( & stderr)
1077+ . replace ( ": warning: " , ": " ) ;
1078+ lint ( format ! ( "linker stderr: {stderr}" ) ) ;
1079+ }
1080+ if !stdout. is_empty ( ) {
1081+ lint ( format ! ( "linker stdout: {}" , stdout) )
1082+ }
10331083 }
10341084 Err ( e) => {
10351085 let linker_not_found = e. kind ( ) == io:: ErrorKind :: NotFound ;
0 commit comments