@@ -8,14 +8,16 @@ use rustc_fs_util::fix_windows_verbatim_for_gcc;
8
8
use rustc_hir:: def_id:: CrateNum ;
9
9
use rustc_middle:: middle:: dependency_format:: Linkage ;
10
10
use rustc_session:: config:: { self , CFGuard , CrateType , DebugInfo , LdImpl , Strip } ;
11
- use rustc_session:: config:: { OutputFilenames , OutputType , PrintRequest , SplitDwarfKind } ;
11
+ use rustc_session:: config:: {
12
+ LinkerFlavorCli , OutputFilenames , OutputType , PrintRequest , SplitDwarfKind ,
13
+ } ;
12
14
use rustc_session:: cstore:: DllImport ;
13
15
use rustc_session:: output:: { check_file_is_writeable, invalid_output_for_target, out_filename} ;
14
16
use rustc_session:: search_paths:: PathKind ;
15
17
use rustc_session:: utils:: NativeLibKind ;
16
18
/// For all the linkers we support, and information they might
17
19
/// need out of the shared crate context before we get rid of it.
18
- use rustc_session:: { filesearch, Session } ;
20
+ use rustc_session:: { config :: InstrumentCoverage , filesearch, Session } ;
19
21
use rustc_span:: symbol:: Symbol ;
20
22
use rustc_target:: spec:: crt_objects:: { CrtObjects , CrtObjectsFallback } ;
21
23
use rustc_target:: spec:: { LinkOutputKind , LinkerFlavor , LldFlavor , SplitDebuginfo } ;
@@ -1921,7 +1923,7 @@ fn add_order_independent_options(
1921
1923
out_filename : & Path ,
1922
1924
tmpdir : & Path ,
1923
1925
) {
1924
- add_gcc_ld_path ( cmd, sess, flavor) ;
1926
+ handle_cli_linker_flavors ( cmd, sess, flavor, crt_objects_fallback ) ;
1925
1927
1926
1928
add_apple_sdk ( cmd, sess, flavor) ;
1927
1929
@@ -2573,46 +2575,131 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> {
2573
2575
}
2574
2576
}
2575
2577
2576
- fn add_gcc_ld_path ( cmd : & mut dyn Linker , sess : & Session , flavor : LinkerFlavor ) {
2577
- if let Some ( ld_impl) = sess. opts . debugging_opts . gcc_ld {
2578
- if let LinkerFlavor :: Gcc = flavor {
2579
- match ld_impl {
2580
- LdImpl :: Lld => {
2581
- if sess. target . lld_flavor == LldFlavor :: Ld64 {
2582
- let tools_path = sess. get_tools_search_paths ( false ) ;
2583
- let ld64_exe = tools_path
2584
- . into_iter ( )
2585
- . map ( |p| p. join ( "gcc-ld" ) )
2586
- . map ( |p| {
2587
- p. join ( if sess. host . is_like_windows { "ld64.exe" } else { "ld64" } )
2588
- } )
2589
- . find ( |p| p. exists ( ) )
2590
- . unwrap_or_else ( || sess. fatal ( "rust-lld (as ld64) not found" ) ) ;
2591
- cmd. cmd ( ) . arg ( {
2592
- let mut arg = OsString :: from ( "-fuse-ld=" ) ;
2593
- arg. push ( ld64_exe) ;
2594
- arg
2595
- } ) ;
2596
- } else {
2597
- let tools_path = sess. get_tools_search_paths ( false ) ;
2598
- let lld_path = tools_path
2599
- . into_iter ( )
2600
- . map ( |p| p. join ( "gcc-ld" ) )
2601
- . find ( |p| {
2602
- p. join ( if sess. host . is_like_windows { "ld.exe" } else { "ld" } )
2603
- . exists ( )
2604
- } )
2605
- . unwrap_or_else ( || sess. fatal ( "rust-lld (as ld) not found" ) ) ;
2606
- cmd. cmd ( ) . arg ( {
2607
- let mut arg = OsString :: from ( "-B" ) ;
2608
- arg. push ( lld_path) ;
2609
- arg
2610
- } ) ;
2611
- }
2612
- }
2578
+ /// This takes care of the various possible enrichments to the linking that can be requested on the
2579
+ /// CLI (and emitting errors and warnings when applicable):
2580
+ /// - shortcuts to `-fuse-ld` with the `gcc` flavor
2581
+ /// - the unstable `-Zgcc-ld=lld` flag to use `rust-lld`, stabilized as the following item
2582
+ /// - the combination of these two: opting into using `lld` and the self-contained linker, to use
2583
+ /// the `rustup` distributed `rust-lld`
2584
+ fn handle_cli_linker_flavors (
2585
+ cmd : & mut dyn Linker ,
2586
+ sess : & Session ,
2587
+ flavor : LinkerFlavor ,
2588
+ crt_objects_fallback : bool ,
2589
+ ) {
2590
+ let unstable_gcc_lld = sess. opts . debugging_opts . gcc_ld == Some ( LdImpl :: Lld ) ;
2591
+ if unstable_gcc_lld {
2592
+ // Sanity check: ensure `gcc` is the currently selected flavor.
2593
+ if LinkerFlavor :: Gcc != flavor {
2594
+ sess. fatal ( "`-Zgcc-ld` is used even though the linker flavor is not `gcc`" ) ;
2595
+ }
2596
+ }
2597
+
2598
+ let cg = & sess. opts . cg ;
2599
+
2600
+ // The `-C linker-flavor` CLI flag can optionally enrich linker-flavors. Check whether that's
2601
+ // applicable, and emit errors if sanity checks fail. There's currently only one enrichment:
2602
+ // adding an argument to the `cc` invocation to use the `use_ld` given linker.
2603
+ let use_ld = match & cg. linker_flavor {
2604
+ Some ( LinkerFlavorCli :: Gcc { use_ld } ) => {
2605
+ // Ensure `gcc` is the currently selected flavor. Error out cleanly, as `-Zgcc-ld` does
2606
+ // if that happens, but this should be unreachable.
2607
+ if LinkerFlavor :: Gcc != flavor {
2608
+ sess. fatal (
2609
+ "`-Clinker-flavor=gcc:*` flag is used even though the \
2610
+ linker flavor is not `gcc`",
2611
+ ) ;
2612
+ }
2613
+
2614
+ use_ld
2615
+ }
2616
+
2617
+ // Note: exhaustive match arm here, to avoid fallthroughs if new linker-flavor enrichments
2618
+ // are added in the future.
2619
+ Some ( LinkerFlavorCli :: WellKnown ( _) ) | None => {
2620
+ if unstable_gcc_lld {
2621
+ "lld"
2622
+ } else {
2623
+ // We're not in a situation needing enrichments.
2624
+ return ;
2613
2625
}
2626
+ }
2627
+ } ;
2628
+
2629
+ // From now, we handle the `gcc` linker-flavor enrichment.
2630
+ let mut cc_arg = OsString :: new ( ) ;
2631
+
2632
+ // Except for `lld`, the given linker executable will be passed straight to `-fuse-ld`.
2633
+ if use_ld == "lld" {
2634
+ // Start by checking if we're in the context of a known issue that users might hit when
2635
+ // using `lld`:
2636
+ //
2637
+ // 1. when requesting self-contained CRT linking (or on a target that does it
2638
+ // automatically), and coverage/profile generation: point at #79555 "Coverage is not
2639
+ // generated when using rust-lld as linker"
2640
+ let instrument_coverage = cg. instrument_coverage . is_some ( )
2641
+ && cg. instrument_coverage != Some ( InstrumentCoverage :: Off ) ;
2642
+ let generate_profile = cg. profile_generate . enabled ( ) ;
2643
+ if crt_objects_fallback && ( instrument_coverage || generate_profile) {
2644
+ sess. warn (
2645
+ "Using `lld`, self-contained linking, and coverage or profile generation has known \
2646
+ issues. See issue #79555 for more details, at \
2647
+ https://github.com/rust-lang/rust/issues/79555",
2648
+ ) ;
2649
+ }
2650
+
2651
+ // 2. Maybe point at https://github.com/flamegraph-rs/flamegraph/pull/157 or the
2652
+ // corresponding rust/LLVM issue when/if it's tracked, depending on whether we use the
2653
+ // workaround argument `--no-rosegment` by default when invoking `lld`.
2654
+ //
2655
+ // 3. If in the future, other linker flavors and targets are eligible to a `rust-lld`
2656
+ // enrichment, maybe also point at target-specific issues like:
2657
+ // - MSVC + ThinLTO blocker https://github.com/rust-lang/rust/issues/81408
2658
+ // - the "lld on MSVC" tracking issue https://github.com/rust-lang/rust/issues/71520
2659
+ // containing a list of blocking issues
2660
+
2661
+ // Now, handle `rust-lld`. If both the `-Clink-self-contained=linker` and
2662
+ // `-Clinker-flavor=gcc:lld` flags were provided, we use `rust-lld`, the rustup-distributed
2663
+ // version of `lld` (when applicable, i.e. not in distro-builds) by:
2664
+ // - checking the `lld-wrapper`s exist in the sysroot
2665
+ // - adding their folder as a search path, or requesting to use a wrapper directly
2666
+ //
2667
+ // FIXME: make sure rust.lld config flag is turned on before adding the sysroot magic handling
2668
+ if sess. opts . cg . link_self_contained . linker . is_on ( ) || unstable_gcc_lld {
2669
+ // A `gcc-ld` folder (containing the `lld-wrapper`s that will run `rust-lld`) is present in
2670
+ // the sysroot's target-specific tool binaries folder.
2671
+ let tools_path = sess. get_tools_search_paths ( false ) ;
2672
+ let mut possible_gcc_ld_paths = tools_path. into_iter ( ) . map ( |p| p. join ( "gcc-ld" ) ) ;
2673
+
2674
+ // Set-up the correct flag and argument to find the wrapper:
2675
+ // - a path to the `ld64` wrapper needs to be passed with `-fuse-ld` on Apple targets
2676
+ // - otherwise, a `-B` search path to the `gcc-ld` folder is enough
2677
+ let ( cc_flag, lld_wrapper_path) = if sess. target . lld_flavor == LldFlavor :: Ld64 {
2678
+ let ld64_exe = if sess. host . is_like_windows { "ld64.exe" } else { "ld64" } ;
2679
+ let ld64_path = possible_gcc_ld_paths
2680
+ . map ( |p| p. join ( ld64_exe) )
2681
+ . find ( |p| p. exists ( ) )
2682
+ . unwrap_or_else ( || sess. fatal ( "rust-lld (as ld64) not found" ) ) ;
2683
+ ( "-fuse-ld=" , ld64_path)
2684
+ } else {
2685
+ let ld_exe = if sess. host . is_like_windows { "ld.exe" } else { "ld" } ;
2686
+ let ld_path = possible_gcc_ld_paths
2687
+ . find ( |p| p. join ( ld_exe) . exists ( ) )
2688
+ . unwrap_or_else ( || sess. fatal ( "rust-lld (as ld) not found" ) ) ;
2689
+ ( "-B" , ld_path)
2690
+ } ;
2691
+ cc_arg. push ( cc_flag) ;
2692
+ cc_arg. push ( lld_wrapper_path) ;
2614
2693
} else {
2615
- sess. fatal ( "option `-Z gcc-ld` is used even though linker flavor is not gcc" ) ;
2694
+ // We were asked to use `lld` but not `rust-lld`.
2695
+ cc_arg. push ( "-fuse-ld=lld" ) ;
2616
2696
}
2617
- }
2697
+ } else {
2698
+ // Otherwise, we were just asked to use a linker executable, and it's expected that `cc`
2699
+ // will find it on the $PATH.
2700
+ cc_arg. push ( "-fuse-ld=" ) ;
2701
+ cc_arg. push ( use_ld) ;
2702
+ } ;
2703
+
2704
+ cmd. cmd ( ) . arg ( cc_arg) ;
2618
2705
}
0 commit comments