@@ -9,15 +9,15 @@ use rustc_hir::def_id::CrateNum;
9
9
use rustc_metadata:: fs:: { emit_metadata, METADATA_FILENAME } ;
10
10
use rustc_middle:: middle:: dependency_format:: Linkage ;
11
11
use rustc_middle:: middle:: exported_symbols:: SymbolExportKind ;
12
- use rustc_session:: config:: { self , CFGuard , CrateType , DebugInfo , LdImpl , Strip } ;
12
+ use rustc_session:: config:: { self , CFGuard , CrateType , DebugInfo , LdImpl , LinkerFlavorCli , Strip } ;
13
13
use rustc_session:: config:: { OutputFilenames , OutputType , PrintRequest , SplitDwarfKind } ;
14
14
use rustc_session:: cstore:: DllImport ;
15
15
use rustc_session:: output:: { check_file_is_writeable, invalid_output_for_target, out_filename} ;
16
16
use rustc_session:: search_paths:: PathKind ;
17
17
use rustc_session:: utils:: NativeLibKind ;
18
18
/// For all the linkers we support, and information they might
19
19
/// need out of the shared crate context before we get rid of it.
20
- use rustc_session:: { filesearch, Session } ;
20
+ use rustc_session:: { config :: InstrumentCoverage , filesearch, Session } ;
21
21
use rustc_span:: symbol:: Symbol ;
22
22
use rustc_span:: DebuggerVisualizerFile ;
23
23
use rustc_target:: spec:: crt_objects:: { CrtObjects , CrtObjectsFallback } ;
@@ -2016,7 +2016,7 @@ fn add_order_independent_options(
2016
2016
out_filename : & Path ,
2017
2017
tmpdir : & Path ,
2018
2018
) {
2019
- add_gcc_ld_path ( cmd, sess, flavor) ;
2019
+ handle_cli_linker_flavors ( cmd, sess, flavor, crt_objects_fallback ) ;
2020
2020
2021
2021
add_apple_sdk ( cmd, sess, flavor) ;
2022
2022
@@ -2694,29 +2694,113 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> {
2694
2694
}
2695
2695
}
2696
2696
2697
- fn add_gcc_ld_path ( cmd : & mut dyn Linker , sess : & Session , flavor : LinkerFlavor ) {
2698
- if let Some ( ld_impl) = sess. opts . unstable_opts . gcc_ld {
2699
- if let LinkerFlavor :: Gcc = flavor {
2700
- match ld_impl {
2701
- LdImpl :: Lld => {
2702
- let tools_path = sess. get_tools_search_paths ( false ) ;
2703
- let gcc_ld_dir = tools_path
2704
- . into_iter ( )
2705
- . map ( |p| p. join ( "gcc-ld" ) )
2706
- . find ( |p| {
2707
- p. join ( if sess. host . is_like_windows { "ld.exe" } else { "ld" } ) . exists ( )
2708
- } )
2709
- . unwrap_or_else ( || sess. fatal ( "rust-lld (as ld) not found" ) ) ;
2710
- cmd. arg ( {
2711
- let mut arg = OsString :: from ( "-B" ) ;
2712
- arg. push ( gcc_ld_dir) ;
2713
- arg
2714
- } ) ;
2715
- cmd. arg ( format ! ( "-Wl,-rustc-lld-flavor={}" , sess. target. lld_flavor. as_str( ) ) ) ;
2716
- }
2697
+ /// This takes care of the various possible enrichments to the linking that can be requested on the
2698
+ /// CLI (and emitting errors and warnings when applicable):
2699
+ /// - shortcuts to `-fuse-ld` with the `gcc` flavor
2700
+ /// - the unstable `-Zgcc-ld=lld` flag to use `rust-lld`, stabilized as the following item
2701
+ fn handle_cli_linker_flavors (
2702
+ cmd : & mut dyn Linker ,
2703
+ sess : & Session ,
2704
+ flavor : LinkerFlavor ,
2705
+ crt_objects_fallback : bool ,
2706
+ ) {
2707
+ let unstable_gcc_lld = sess. opts . unstable_opts . gcc_ld == Some ( LdImpl :: Lld ) ;
2708
+ if unstable_gcc_lld {
2709
+ // Sanity check: ensure `gcc` is the currently selected flavor.
2710
+ if LinkerFlavor :: Gcc != flavor {
2711
+ sess. fatal ( "`-Zgcc-ld` is used even though the linker flavor is not `gcc`" ) ;
2712
+ }
2713
+ }
2714
+
2715
+ let cg = & sess. opts . cg ;
2716
+
2717
+ // The `-C linker-flavor` CLI flag can optionally enrich linker-flavors. Check whether that's
2718
+ // applicable, and emit errors if sanity checks fail. There's currently only one enrichment:
2719
+ // adding an argument to the `cc` invocation to use the `use_ld` given linker.
2720
+ let use_ld = match & cg. linker_flavor {
2721
+ Some ( LinkerFlavorCli :: Gcc { use_ld } ) => {
2722
+ // Ensure `gcc` is the currently selected flavor. Error out cleanly, as `-Zgcc-ld` does
2723
+ // if that happens, but this should be unreachable.
2724
+ if LinkerFlavor :: Gcc != flavor {
2725
+ sess. fatal (
2726
+ "`-Clinker-flavor=gcc:*` flag is used even though the \
2727
+ linker flavor is not `gcc`",
2728
+ ) ;
2729
+ }
2730
+
2731
+ use_ld
2732
+ }
2733
+
2734
+ // Note: exhaustive match arm here, to avoid fallthroughs if new linker-flavor enrichments
2735
+ // are added in the future.
2736
+ Some ( LinkerFlavorCli :: WellKnown ( _) ) | None => {
2737
+ if unstable_gcc_lld {
2738
+ "lld"
2739
+ } else {
2740
+ // We're not in a situation needing enrichments.
2741
+ return ;
2717
2742
}
2743
+ }
2744
+ } ;
2745
+
2746
+ // From now on in this function, we handle the `gcc` linker-flavor enrichment.
2747
+
2748
+ // Except for `lld`, the given linker executable will be passed straight to `-fuse-ld`.
2749
+ if use_ld == "lld" {
2750
+ // Start by checking if we're in the context of a known issue that users might hit when
2751
+ // using `lld`:
2752
+ //
2753
+ // 1. when requesting self-contained CRT linking (or on a target that does it
2754
+ // automatically), and coverage/profile generation: point at #79555 "Coverage is not
2755
+ // generated when using rust-lld as linker"
2756
+ let instrument_coverage = cg. instrument_coverage . is_some ( )
2757
+ && cg. instrument_coverage != Some ( InstrumentCoverage :: Off ) ;
2758
+ let generate_profile = cg. profile_generate . enabled ( ) ;
2759
+ if crt_objects_fallback && ( instrument_coverage || generate_profile) {
2760
+ sess. warn (
2761
+ "Using `lld`, self-contained linking, and coverage or profile generation has known \
2762
+ issues. See issue #79555 for more details, at \
2763
+ https://github.com/rust-lang/rust/issues/79555",
2764
+ ) ;
2765
+ }
2766
+
2767
+ // 2. Maybe point at https://github.com/flamegraph-rs/flamegraph/pull/157 or the
2768
+ // corresponding rust/LLVM issue when/if it's tracked, depending on whether we use the
2769
+ // workaround argument `--no-rosegment` by default when invoking `lld`.
2770
+ //
2771
+ // 3. If in the future, other linker flavors and targets are eligible to a `rust-lld`
2772
+ // enrichment, maybe also point at target-specific issues like:
2773
+ // - MSVC + ThinLTO blocker https://github.com/rust-lang/rust/issues/81408
2774
+ // - the "lld on MSVC" tracking issue https://github.com/rust-lang/rust/issues/71520
2775
+ // containing a list of blocking issues
2776
+
2777
+ // Now, handle `rust-lld`. If the `-Zgcc-ld=lld` flag was provided, we use `rust-lld`, the
2778
+ // rustup-distributed version of `lld` (when applicable, i.e. not in distro-builds) by:
2779
+ // - checking the `lld-wrapper`s exist in the sysroot
2780
+ // - adding their folder as a search path, or requesting to use a wrapper directly
2781
+ if unstable_gcc_lld {
2782
+ // A `gcc-ld` folder (containing the `lld-wrapper`s that will run `rust-lld`) is present in
2783
+ // the sysroot's target-specific tool binaries folder.
2784
+ let tools_path = sess. get_tools_search_paths ( false ) ;
2785
+ let gcc_ld_dir = tools_path
2786
+ . into_iter ( )
2787
+ . map ( |p| p. join ( "gcc-ld" ) )
2788
+ . find ( |p| p. join ( if sess. host . is_like_windows { "ld.exe" } else { "ld" } ) . exists ( ) )
2789
+ . unwrap_or_else ( || sess. fatal ( "rust-lld (as ld) not found" ) ) ;
2790
+
2791
+ cmd. arg ( {
2792
+ let mut arg = OsString :: from ( "-B" ) ;
2793
+ arg. push ( gcc_ld_dir) ;
2794
+ arg
2795
+ } ) ;
2796
+ cmd. arg ( format ! ( "-Wl,-rustc-lld-flavor={}" , sess. target. lld_flavor. as_str( ) ) ) ;
2718
2797
} else {
2719
- sess. fatal ( "option `-Z gcc-ld` is used even though linker flavor is not gcc" ) ;
2798
+ // We were asked to use `lld` but not `rust-lld`.
2799
+ cmd. arg ( "-fuse-ld=lld" ) ;
2720
2800
}
2801
+ } else {
2802
+ // Otherwise, we were just asked to use a linker executable, and it's expected that `cc`
2803
+ // will find it on the $PATH.
2804
+ cmd. arg ( format ! ( "-fuse-ld={}" , use_ld) ) ;
2721
2805
}
2722
2806
}
0 commit comments