@@ -15,12 +15,14 @@ use rustc_ast::CRATE_NODE_ID;
15
15
use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
16
16
use rustc_data_structures:: memmap:: Mmap ;
17
17
use rustc_data_structures:: temp_dir:: MaybeTempDir ;
18
- use rustc_errors:: DiagCtxtHandle ;
18
+ use rustc_errors:: { DiagCtxtHandle , LintDiagnostic } ;
19
19
use rustc_fs_util:: { fix_windows_verbatim_for_gcc, try_canonicalize} ;
20
20
use rustc_hir:: def_id:: { CrateNum , LOCAL_CRATE } ;
21
+ use rustc_macros:: LintDiagnostic ;
21
22
use rustc_metadata:: fs:: { METADATA_FILENAME , copy_to_stdout, emit_wrapper_file} ;
22
23
use rustc_metadata:: { find_native_static_library, walk_native_lib_search_dirs} ;
23
24
use rustc_middle:: bug;
25
+ use rustc_middle:: lint:: lint_level;
24
26
use rustc_middle:: middle:: debugger_visualizer:: DebuggerVisualizerFile ;
25
27
use rustc_middle:: middle:: dependency_format:: Linkage ;
26
28
use rustc_middle:: middle:: exported_symbols:: SymbolExportKind ;
@@ -29,6 +31,7 @@ use rustc_session::config::{
29
31
OutputType , PrintKind , SplitDwarfKind , Strip ,
30
32
} ;
31
33
use rustc_session:: cstore:: DllImport ;
34
+ use rustc_session:: lint:: builtin:: LINKER_MESSAGES ;
32
35
use rustc_session:: output:: { check_file_is_writeable, invalid_output_for_target, out_filename} ;
33
36
use rustc_session:: search_paths:: PathKind ;
34
37
use rustc_session:: utils:: NativeLibKind ;
@@ -749,6 +752,14 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out
749
752
}
750
753
}
751
754
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
+
752
763
/// Create a dynamic library or executable.
753
764
///
754
765
/// This will invoke the system linker/cc to create the resulting file. This links to all upstream
@@ -981,6 +992,20 @@ fn link_natively(
981
992
982
993
match prog {
983
994
Ok ( prog) => {
995
+ let is_msvc_link_exe = if let Some ( code) = prog. status . code ( ) {
996
+ sess. target . is_like_msvc
997
+ && flavor == LinkerFlavor :: Msvc ( Lld :: No )
998
+ // Respect the command line override
999
+ && sess. opts . cg . linker . is_none ( )
1000
+ // Match exactly "link.exe"
1001
+ && linker_path. to_str ( ) == Some ( "link.exe" )
1002
+ // All Microsoft `link.exe` linking error codes are
1003
+ // four digit numbers in the range 1000 to 9999 inclusive
1004
+ && ( code < 1000 || code > 9999 )
1005
+ } else {
1006
+ false
1007
+ } ;
1008
+
984
1009
if !prog. status . success ( ) {
985
1010
let mut output = prog. stderr . clone ( ) ;
986
1011
output. extend_from_slice ( & prog. stdout ) ;
@@ -996,40 +1021,70 @@ fn link_natively(
996
1021
// If MSVC's `link.exe` was expected but the return code
997
1022
// is not a Microsoft LNK error then suggest a way to fix or
998
1023
// install the Visual Studio build tools.
999
- 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
- {
1010
- let is_vs_installed = windows_registry:: find_vs_version ( ) . is_ok ( ) ;
1011
- let has_linker =
1012
- windows_registry:: find_tool ( & sess. target . arch , "link.exe" ) . is_some ( ) ;
1013
-
1014
- sess. dcx ( ) . emit_note ( errors:: LinkExeUnexpectedError ) ;
1015
- if is_vs_installed && has_linker {
1016
- // the linker is broken
1017
- sess. dcx ( ) . emit_note ( errors:: RepairVSBuildTools ) ;
1018
- sess. dcx ( ) . emit_note ( errors:: MissingCppBuildToolComponent ) ;
1019
- } else if is_vs_installed {
1020
- // the linker is not installed
1021
- sess. dcx ( ) . emit_note ( errors:: SelectCppBuildToolWorkload ) ;
1022
- } else {
1023
- // visual studio is not installed
1024
- sess. dcx ( ) . emit_note ( errors:: VisualStudioNotInstalled ) ;
1025
- }
1024
+ if is_msvc_link_exe {
1025
+ let is_vs_installed = windows_registry:: find_vs_version ( ) . is_ok ( ) ;
1026
+ let has_linker =
1027
+ windows_registry:: find_tool ( & sess. target . arch , "link.exe" ) . is_some ( ) ;
1028
+
1029
+ sess. dcx ( ) . emit_note ( errors:: LinkExeUnexpectedError ) ;
1030
+ if is_vs_installed && has_linker {
1031
+ // the linker is broken
1032
+ sess. dcx ( ) . emit_note ( errors:: RepairVSBuildTools ) ;
1033
+ sess. dcx ( ) . emit_note ( errors:: MissingCppBuildToolComponent ) ;
1034
+ } else if is_vs_installed {
1035
+ // the linker is not installed
1036
+ sess. dcx ( ) . emit_note ( errors:: SelectCppBuildToolWorkload ) ;
1037
+ } else {
1038
+ // visual studio is not installed
1039
+ sess. dcx ( ) . emit_note ( errors:: VisualStudioNotInstalled ) ;
1026
1040
}
1027
1041
}
1028
1042
1029
1043
sess. dcx ( ) . abort_if_errors ( ) ;
1030
1044
}
1031
- info ! ( "linker stderr:\n {}" , escape_string( & prog. stderr) ) ;
1032
- info ! ( "linker stdout:\n {}" , escape_string( & prog. stdout) ) ;
1045
+
1046
+ let stderr = escape_string ( & prog. stderr ) ;
1047
+ let mut stdout = escape_string ( & prog. stdout ) ;
1048
+ info ! ( "linker stderr:\n {}" , & stderr) ;
1049
+ info ! ( "linker stdout:\n {}" , & stdout) ;
1050
+
1051
+ // Hide some progress messages from link.exe that we don't care about.
1052
+ // See https://github.com/chromium/chromium/blob/bfa41e41145ffc85f041384280caf2949bb7bd72/build/toolchain/win/tool_wrapper.py#L144-L146
1053
+ if is_msvc_link_exe {
1054
+ if let Ok ( str) = str:: from_utf8 ( & prog. stdout ) {
1055
+ let mut output = String :: with_capacity ( str. len ( ) ) ;
1056
+ for line in stdout. lines ( ) {
1057
+ if line. starts_with ( " Creating library" )
1058
+ || line. starts_with ( "Generating code" )
1059
+ || line. starts_with ( "Finished generating code" )
1060
+ {
1061
+ continue ;
1062
+ }
1063
+ output += line;
1064
+ output += "\r \n "
1065
+ }
1066
+ stdout = escape_string ( output. trim ( ) . as_bytes ( ) )
1067
+ }
1068
+ }
1069
+
1070
+ let ( level, src) = codegen_results. crate_info . lint_levels . linker_messages ;
1071
+ let lint = |msg| {
1072
+ lint_level ( sess, LINKER_MESSAGES , level, src, None , |diag| {
1073
+ LinkerOutput { inner : msg } . decorate_lint ( diag)
1074
+ } )
1075
+ } ;
1076
+
1077
+ if !prog. stderr . is_empty ( ) {
1078
+ // We already print `warning:` at the start of the diagnostic. Remove it from the linker output if present.
1079
+ let stderr = stderr
1080
+ . strip_prefix ( "warning: " )
1081
+ . unwrap_or ( & stderr)
1082
+ . replace ( ": warning: " , ": " ) ;
1083
+ lint ( format ! ( "linker stderr: {stderr}" ) ) ;
1084
+ }
1085
+ if !stdout. is_empty ( ) {
1086
+ lint ( format ! ( "linker stdout: {}" , stdout) )
1087
+ }
1033
1088
}
1034
1089
Err ( e) => {
1035
1090
let linker_not_found = e. kind ( ) == io:: ErrorKind :: NotFound ;
0 commit comments