@@ -205,15 +205,11 @@ impl ToJson for LldFlavor {
205205}
206206
207207impl LinkerFlavor {
208- pub fn from_cli ( cli : LinkerFlavorCli , target : & TargetOptions ) -> LinkerFlavor {
209- Self :: from_cli_impl ( cli, target. linker_flavor . lld_flavor ( ) , target. linker_flavor . is_gnu ( ) )
210- }
211-
212- /// The passed CLI flavor is preferred over other args coming from the default target spec,
213- /// so this function can produce a flavor that is incompatible with the current target.
214- /// FIXME: Produce errors when `-Clinker-flavor` is set to something incompatible
215- /// with the current target.
216- fn from_cli_impl ( cli : LinkerFlavorCli , lld_flavor : LldFlavor , is_gnu : bool ) -> LinkerFlavor {
208+ /// At this point the target's reference linker flavor doesn't yet exist and we need to infer
209+ /// it. The inference always succeds and gives some result, and we don't report any flavor
210+ /// incompatibility errors for json target specs. The CLI flavor is used as the main source
211+ /// of truth, other flags are used in case of ambiguities.
212+ fn from_cli_json ( cli : LinkerFlavorCli , lld_flavor : LldFlavor , is_gnu : bool ) -> LinkerFlavor {
217213 match cli {
218214 LinkerFlavorCli :: Gcc => match lld_flavor {
219215 LldFlavor :: Ld if is_gnu => LinkerFlavor :: Gnu ( Cc :: Yes , Lld :: No ) ,
@@ -257,6 +253,85 @@ impl LinkerFlavor {
257253 }
258254 }
259255
256+ fn infer_cli_hints ( cli : LinkerFlavorCli ) -> ( Option < Cc > , Option < Lld > ) {
257+ match cli {
258+ LinkerFlavorCli :: Gcc | LinkerFlavorCli :: Em => ( Some ( Cc :: Yes ) , None ) ,
259+ LinkerFlavorCli :: Lld ( _) => ( Some ( Cc :: No ) , Some ( Lld :: Yes ) ) ,
260+ LinkerFlavorCli :: Ld | LinkerFlavorCli :: Msvc => ( Some ( Cc :: No ) , Some ( Lld :: No ) ) ,
261+ LinkerFlavorCli :: BpfLinker | LinkerFlavorCli :: PtxLinker => ( None , None ) ,
262+ }
263+ }
264+
265+ fn infer_linker_hints ( linker_stem : & str ) -> ( Option < Cc > , Option < Lld > ) {
266+ // Remove any version postfix.
267+ let stem = linker_stem
268+ . rsplit_once ( '-' )
269+ . and_then ( |( lhs, rhs) | rhs. chars ( ) . all ( char:: is_numeric) . then_some ( lhs) )
270+ . unwrap_or ( linker_stem) ;
271+
272+ // GCC/Clang can have an optional target prefix.
273+ if stem == "emcc"
274+ || stem == "gcc"
275+ || stem. ends_with ( "-gcc" )
276+ || stem == "g++"
277+ || stem. ends_with ( "-g++" )
278+ || stem == "clang"
279+ || stem. ends_with ( "-clang" )
280+ || stem == "clang++"
281+ || stem. ends_with ( "-clang++" )
282+ {
283+ ( Some ( Cc :: Yes ) , None )
284+ } else if stem == "wasm-ld"
285+ || stem. ends_with ( "-wasm-ld" )
286+ || stem == "ld.lld"
287+ || stem == "lld"
288+ || stem == "rust-lld"
289+ || stem == "lld-link"
290+ {
291+ ( Some ( Cc :: No ) , Some ( Lld :: Yes ) )
292+ } else if stem == "ld" || stem. ends_with ( "-ld" ) || stem == "link" {
293+ ( Some ( Cc :: No ) , Some ( Lld :: No ) )
294+ } else {
295+ ( None , None )
296+ }
297+ }
298+
299+ fn with_hints ( self , ( cc_hint, lld_hint) : ( Option < Cc > , Option < Lld > ) ) -> LinkerFlavor {
300+ match self {
301+ LinkerFlavor :: Gnu ( cc, lld) => {
302+ LinkerFlavor :: Gnu ( cc_hint. unwrap_or ( cc) , lld_hint. unwrap_or ( lld) )
303+ }
304+ LinkerFlavor :: Darwin ( cc, lld) => {
305+ LinkerFlavor :: Darwin ( cc_hint. unwrap_or ( cc) , lld_hint. unwrap_or ( lld) )
306+ }
307+ LinkerFlavor :: WasmLld ( cc) => LinkerFlavor :: WasmLld ( cc_hint. unwrap_or ( cc) ) ,
308+ LinkerFlavor :: Unix ( cc) => LinkerFlavor :: Unix ( cc_hint. unwrap_or ( cc) ) ,
309+ LinkerFlavor :: Msvc ( lld) => LinkerFlavor :: Msvc ( lld_hint. unwrap_or ( lld) ) ,
310+ LinkerFlavor :: EmCc | LinkerFlavor :: Bpf | LinkerFlavor :: Ptx => self ,
311+ }
312+ }
313+
314+ pub fn with_cli_hints ( self , cli : LinkerFlavorCli ) -> LinkerFlavor {
315+ self . with_hints ( LinkerFlavor :: infer_cli_hints ( cli) )
316+ }
317+
318+ pub fn with_linker_hints ( self , linker_stem : & str ) -> LinkerFlavor {
319+ self . with_hints ( LinkerFlavor :: infer_linker_hints ( linker_stem) )
320+ }
321+
322+ pub fn check_compatibility ( self , cli : LinkerFlavorCli ) -> Option < String > {
323+ // The CLI flavor should be compatible with the target if it survives this roundtrip.
324+ let compatible = |cli| cli == self . with_cli_hints ( cli) . to_cli ( ) ;
325+ ( !compatible ( cli) ) . then ( || {
326+ LinkerFlavorCli :: all ( )
327+ . iter ( )
328+ . filter ( |cli| compatible ( * * cli) )
329+ . map ( |cli| cli. desc ( ) )
330+ . intersperse ( ", " )
331+ . collect ( )
332+ } )
333+ }
334+
260335 pub fn lld_flavor ( self ) -> LldFlavor {
261336 match self {
262337 LinkerFlavor :: Gnu ( ..)
@@ -278,6 +353,10 @@ impl LinkerFlavor {
278353macro_rules! linker_flavor_cli_impls {
279354 ( $( ( $( $flavor: tt) * ) $string: literal) * ) => (
280355 impl LinkerFlavorCli {
356+ const fn all( ) -> & ' static [ LinkerFlavorCli ] {
357+ & [ $( $( $flavor) * , ) * ]
358+ }
359+
281360 pub const fn one_of( ) -> & ' static str {
282361 concat!( "one of: " , $( $string, " " , ) * )
283362 }
@@ -289,8 +368,8 @@ macro_rules! linker_flavor_cli_impls {
289368 } )
290369 }
291370
292- pub fn desc( & self ) -> & str {
293- match * self {
371+ pub fn desc( self ) -> & ' static str {
372+ match self {
294373 $( $( $flavor) * => $string, ) *
295374 }
296375 }
@@ -1801,7 +1880,7 @@ impl TargetOptions {
18011880 }
18021881
18031882 fn update_from_cli ( & mut self ) {
1804- self . linker_flavor = LinkerFlavor :: from_cli_impl (
1883+ self . linker_flavor = LinkerFlavor :: from_cli_json (
18051884 self . linker_flavor_json ,
18061885 self . lld_flavor_json ,
18071886 self . linker_is_gnu_json ,
@@ -1815,12 +1894,7 @@ impl TargetOptions {
18151894 ] {
18161895 args. clear ( ) ;
18171896 for ( flavor, args_json) in args_json {
1818- // Cannot use `from_cli` due to borrow checker.
1819- let linker_flavor = LinkerFlavor :: from_cli_impl (
1820- * flavor,
1821- self . lld_flavor_json ,
1822- self . linker_is_gnu_json ,
1823- ) ;
1897+ let linker_flavor = self . linker_flavor . with_cli_hints ( * flavor) ;
18241898 // Normalize to no lld to avoid asserts.
18251899 let linker_flavor = match linker_flavor {
18261900 LinkerFlavor :: Gnu ( cc, _) => LinkerFlavor :: Gnu ( cc, Lld :: No ) ,
0 commit comments