Skip to content

Commit 045cb0a

Browse files
committed
implement linker-flavor enrichments for MCP
1 parent cc5ac27 commit 045cb0a

File tree

2 files changed

+109
-25
lines changed

2 files changed

+109
-25
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

+108-24
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ use rustc_hir::def_id::CrateNum;
99
use rustc_metadata::fs::{emit_metadata, METADATA_FILENAME};
1010
use rustc_middle::middle::dependency_format::Linkage;
1111
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};
1313
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
1414
use rustc_session::cstore::DllImport;
1515
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
1616
use rustc_session::search_paths::PathKind;
1717
use rustc_session::utils::NativeLibKind;
1818
/// For all the linkers we support, and information they might
1919
/// 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};
2121
use rustc_span::symbol::Symbol;
2222
use rustc_span::DebuggerVisualizerFile;
2323
use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
@@ -2016,7 +2016,7 @@ fn add_order_independent_options(
20162016
out_filename: &Path,
20172017
tmpdir: &Path,
20182018
) {
2019-
add_gcc_ld_path(cmd, sess, flavor);
2019+
handle_cli_linker_flavors(cmd, sess, flavor, crt_objects_fallback);
20202020

20212021
add_apple_sdk(cmd, sess, flavor);
20222022

@@ -2694,29 +2694,113 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> {
26942694
}
26952695
}
26962696

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;
27172742
}
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()));
27182797
} 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");
27202800
}
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));
27212805
}
27222806
}

compiler/rustc_session/src/options.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1618,7 +1618,7 @@ pub enum WasiExecModel {
16181618
Reactor,
16191619
}
16201620

1621-
#[derive(Clone, Copy, Hash)]
1621+
#[derive(Clone, Copy, Hash, PartialEq)]
16221622
pub enum LdImpl {
16231623
Lld,
16241624
}

0 commit comments

Comments
 (0)