@@ -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,72 @@ 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+
260322 pub fn lld_flavor ( self ) -> LldFlavor {
261323 match self {
262324 LinkerFlavor :: Gnu ( ..)
@@ -1801,7 +1863,7 @@ impl TargetOptions {
18011863 }
18021864
18031865 fn update_from_cli ( & mut self ) {
1804- self . linker_flavor = LinkerFlavor :: from_cli_impl (
1866+ self . linker_flavor = LinkerFlavor :: from_cli_json (
18051867 self . linker_flavor_json ,
18061868 self . lld_flavor_json ,
18071869 self . linker_is_gnu_json ,
@@ -1815,12 +1877,7 @@ impl TargetOptions {
18151877 ] {
18161878 args. clear ( ) ;
18171879 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- ) ;
1880+ let linker_flavor = self . linker_flavor . with_cli_hints ( * flavor) ;
18241881 // Normalize to no lld to avoid asserts.
18251882 let linker_flavor = match linker_flavor {
18261883 LinkerFlavor :: Gnu ( cc, _) => LinkerFlavor :: Gnu ( cc, Lld :: No ) ,
0 commit comments