Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[do not merge] Preparation for LLD stabilization #138645

Draft
wants to merge 15 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
@@ -1414,7 +1414,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
}
}

let features = sess.opts.unstable_opts.linker_features;
let features = sess.opts.cg.linker_features;

// linker and linker flavor specified via command line have precedence over what the target
// specification specifies
66 changes: 57 additions & 9 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
@@ -362,9 +362,14 @@ impl LinkSelfContained {
/// components was set individually. This would also require the `-Zunstable-options` flag, to
/// be allowed.
fn are_unstable_variants_set(&self) -> bool {
let any_component_set =
!self.enabled_components.is_empty() || !self.disabled_components.is_empty();
self.explicitly_set.is_none() && any_component_set
if self.explicitly_set.is_some() {
return false;
}

// Only the linker component is stable, anything else is thus unstable.
let mentioned_components = self.enabled_components.union(self.disabled_components);
let unstable_components = mentioned_components - LinkSelfContainedComponents::LINKER;
!unstable_components.is_empty()
}

/// Returns whether the self-contained linker component was enabled on the CLI, using the
@@ -391,7 +396,7 @@ impl LinkSelfContained {
}
}

/// The different values that `-Z linker-features` can take on the CLI: a list of individually
/// The different values that `-C linker-features` can take on the CLI: a list of individually
/// enabled or disabled features used during linking.
///
/// There is no need to enable or disable them in bulk. Each feature is fine-grained, and can be
@@ -431,6 +436,44 @@ impl LinkerFeaturesCli {
_ => None,
}
}

/// When *not* using `-Z unstable-options` on the CLI, ensure only stable linker features are
/// used, for the given `TargetTuple`. Returns `Ok` if no unstable variants are used.
/// The caller should ensure that e.g. `nightly_options::is_unstable_enabled()`
/// returns false.
pub(crate) fn check_unstable_variants(&self, target_tuple: &TargetTuple) -> Result<(), String> {
// `-C linker-features=[-+]lld` is only stable on x64 linux.
let check_lld = |features: LinkerFeatures, polarity: &str| {
let has_lld = features.is_lld_enabled();
if has_lld && target_tuple.tuple() != "x86_64-unknown-linux-gnu" {
return Err(format!(
"`-C linker-features={polarity}lld` is unstable on the `{target_tuple}` \
target. The `-Z unstable-options` flag must also be passed to use it on this target",
));
}
Ok(())
};
check_lld(self.enabled, "+")?;
check_lld(self.disabled, "-")?;

// Since only lld is stable, any non-lld feature used is unstable, and that's an error.
let unstable_enabled = self.enabled - LinkerFeatures::LLD;
let unstable_disabled = self.disabled - LinkerFeatures::LLD;
if !unstable_enabled.union(unstable_disabled).is_empty() {
let unstable_features: Vec<_> = unstable_enabled
.iter()
.map(|f| format!("+{}", f.as_str().unwrap()))
.chain(unstable_disabled.iter().map(|f| format!("-{}", f.as_str().unwrap())))
.collect();
return Err(format!(
"the requested `-C linker-features={}` are unstable, and also require the \
`-Z unstable-options` flag to be usable",
unstable_features.join(","),
));
}

Ok(())
}
}

/// Used with `-Z assert-incr-state`.
@@ -2486,9 +2529,8 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
}
}

if !nightly_options::is_unstable_enabled(matches)
&& cg.force_frame_pointers == FramePointer::NonLeaf
{
let unstable_options_enabled = nightly_options::is_unstable_enabled(matches);
if !unstable_options_enabled && cg.force_frame_pointers == FramePointer::NonLeaf {
early_dcx.early_fatal(
"`-Cforce-frame-pointers=non-leaf` or `always` also requires `-Zunstable-options` \
and a nightly compiler",
@@ -2498,12 +2540,12 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
// For testing purposes, until we have more feedback about these options: ensure `-Z
// unstable-options` is required when using the unstable `-C link-self-contained` and `-C
// linker-flavor` options.
if !nightly_options::is_unstable_enabled(matches) {
if !unstable_options_enabled {
let uses_unstable_self_contained_option =
cg.link_self_contained.are_unstable_variants_set();
if uses_unstable_self_contained_option {
early_dcx.early_fatal(
"only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off` are stable, \
"only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker`/`+linker` are stable, \
the `-Z unstable-options` flag must also be passed to use the unstable values",
);
}
@@ -2546,6 +2588,12 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
let debuginfo = select_debuginfo(matches, &cg);
let debuginfo_compression = unstable_opts.debuginfo_compression;

if !unstable_options_enabled {
if let Err(error) = cg.linker_features.check_unstable_variants(&target_triple) {
early_dcx.early_fatal(error);
}
}

let crate_name = matches.opt_str("crate-name");
let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref());
// Parse any `-l` flags, which link to native libraries.
4 changes: 2 additions & 2 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
@@ -1988,6 +1988,8 @@ options! {
on a C toolchain or linker installed in the system"),
linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
"system linker to link outputs with"),
linker_features: LinkerFeaturesCli = (LinkerFeaturesCli::default(), parse_linker_features, [UNTRACKED],
"a comma-separated list of linker features to enable (+) or disable (-): `lld`"),
linker_flavor: Option<LinkerFlavorCli> = (None, parse_linker_flavor, [UNTRACKED],
"linker flavor"),
linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
@@ -2273,8 +2275,6 @@ options! {
"link native libraries in the linker invocation (default: yes)"),
link_only: bool = (false, parse_bool, [TRACKED],
"link the `.rlink` file generated by `-Z no-link` (default: no)"),
linker_features: LinkerFeaturesCli = (LinkerFeaturesCli::default(), parse_linker_features, [UNTRACKED],
"a comma-separated list of linker features to enable (+) or disable (-): `lld`"),
lint_llvm_ir: bool = (false, parse_bool, [TRACKED],
"lint LLVM IR (default: no)"),
lint_mir: bool = (false, parse_bool, [UNTRACKED],
15 changes: 13 additions & 2 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
@@ -718,7 +718,7 @@ impl ToJson for LinkSelfContainedComponents {
}

bitflags::bitflags! {
/// The `-Z linker-features` components that can individually be enabled or disabled.
/// The `-C linker-features` components that can individually be enabled or disabled.
///
/// They are feature flags intended to be a more flexible mechanism than linker flavors, and
/// also to prevent a combinatorial explosion of flavors whenever a new linker feature is
@@ -749,7 +749,7 @@ bitflags::bitflags! {
rustc_data_structures::external_bitflags_debug! { LinkerFeatures }

impl LinkerFeatures {
/// Parses a single `-Z linker-features` well-known feature, not a set of flags.
/// Parses a single `-C linker-features` well-known feature, not a set of flags.
pub fn from_str(s: &str) -> Option<LinkerFeatures> {
Some(match s {
"cc" => LinkerFeatures::CC,
@@ -758,6 +758,17 @@ impl LinkerFeatures {
})
}

/// Return the linker feature name, as would be passed on the CLI.
///
/// Returns `None` if the bitflags aren't a singular component (but a mix of multiple flags).
pub fn as_str(self) -> Option<&'static str> {
Some(match self {
LinkerFeatures::CC => "cc",
LinkerFeatures::LLD => "lld",
_ => return None,
})
}

/// Returns whether the `lld` linker feature is enabled.
pub fn is_lld_enabled(self) -> bool {
self.contains(LinkerFeatures::LLD)
4 changes: 1 addition & 3 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
@@ -1331,9 +1331,7 @@ pub fn rustc_cargo_env(
}

// Enable rustc's env var for `rust-lld` when requested.
if builder.config.lld_enabled
&& (builder.config.channel == "dev" || builder.config.channel == "nightly")
{
if builder.config.lld_enabled {
cargo.env("CFG_USE_SELF_CONTAINED_LINKER", "1");
}

6 changes: 1 addition & 5 deletions src/bootstrap/src/core/config/config.rs
Original file line number Diff line number Diff line change
@@ -2356,7 +2356,6 @@ impl Config {
// build our internal lld and use it as the default linker, by setting the `rust.lld` config
// to true by default:
// - on the `x86_64-unknown-linux-gnu` target
// - on the `dev` and `nightly` channels
// - when building our in-tree llvm (i.e. the target has not set an `llvm-config`), so that
// we're also able to build the corresponding lld
// - or when using an external llvm that's downloaded from CI, which also contains our prebuilt
@@ -2365,10 +2364,7 @@ impl Config {
// thus, disabled
// - similarly, lld will not be built nor used by default when explicitly asked not to, e.g.
// when the config sets `rust.lld = false`
if config.build.triple == "x86_64-unknown-linux-gnu"
&& config.hosts == [config.build]
&& (config.channel == "dev" || config.channel == "nightly")
{
if config.build.triple == "x86_64-unknown-linux-gnu" && config.hosts == [config.build] {
let no_llvm_config = config
.target_config
.get(&config.build)
34 changes: 30 additions & 4 deletions src/doc/rustc/src/codegen-options/index.md
Original file line number Diff line number Diff line change
@@ -218,15 +218,22 @@ coverage measurement. Its use is not recommended.

## link-self-contained

On `windows-gnu`, `linux-musl`, and `wasi` targets, this flag controls whether the
linker will use libraries and objects shipped with Rust instead of those in the system.
It takes one of the following values:
This flag controls whether the linker will use libraries and objects shipped with Rust instead
of those in the system. This allows overriding cases when detection fails or user wants to use shipped
libraries.

You can enable or disable the usage of any self-contained objects using one of the following values:

* no value: rustc will use heuristic to disable self-contained mode if system has necessary tools.
* `y`, `yes`, `on`, `true`: use only libraries/objects shipped with Rust.
* `n`, `no`, `off` or `false`: rely on the user or the linker to provide non-Rust libraries/objects.

This allows overriding cases when detection fails or user wants to use shipped libraries.
It is also possible to enable or disable specific self-contained objects in a more granular way.
You can pass a comma-separated list of self-contained objects, individually enabled (`+object`) or
disabled (`-object`).

Currently, only the `linker` granular option is stabilized:
- `linker`: toggle the usage of self-contained linker objects (linker, dlltool, and their necessary libraries)

## linker

@@ -235,6 +242,25 @@ path to the linker executable. If this flag is not specified, the linker will
be inferred based on the target. See also the [linker-flavor](#linker-flavor)
flag for another way to specify the linker.

## linker-features

The `-Clinker-features` flag allows enabling or disabling specific features used during linking.

These feature flags are a flexible extension mechanism that is complementary to linker flavors,
designed to avoid the combinatorial explosion of having to create a new set of flavors for each
linker feature we'd want to use.

The flag accepts a comma-separated list of features, individually enabled (`+feature`) or disabled
(`-feature`).

Currently only one is stable, and only on the `x86_64-unknown-linux-gnu` target:
- `lld`: to toggle using the lld linker, either the system-installed binary, or the self-contained
`rust-lld` linker (via the `-Clink-self-contained=+linker` flag).

For example, use:
- `-Clinker-features=+lld` to opt in to using the `lld` linker
- `-Clinker-features=-lld` to opt out instead, for targets where it is configured as the default linker

## linker-flavor

This flag controls the linker flavor used by `rustc`. If a linker is given with
4 changes: 2 additions & 2 deletions src/doc/unstable-book/src/compiler-flags/codegen-options.md
Original file line number Diff line number Diff line change
@@ -51,10 +51,10 @@ instead of those in the system. The stable boolean values for this flag are coar
- `mingw`: other MinGW libs and Windows import libs

Out of the above self-contained linking components, `linker` is the only one currently implemented
(beyond parsing the CLI options).
(beyond parsing the CLI options) and stabilized.

It refers to the LLD linker, built from the same LLVM revision used by rustc (named `rust-lld` to
avoid naming conflicts), that is distributed via `rustup` with the compiler (and is used by default
for the wasm targets). One can also opt-in to use it by combining this flag with an appropriate
for the wasm targets). One can also opt in to use it by combining this flag with an appropriate
linker flavor: for example, `-Clinker-flavor=gnu-lld-cc -Clink-self-contained=+linker` will use the
toolchain's `rust-lld` as the linker.
35 changes: 0 additions & 35 deletions src/doc/unstable-book/src/compiler-flags/linker-features.md

This file was deleted.

3 changes: 3 additions & 0 deletions src/tools/opt-dist/src/tests.rs
Original file line number Diff line number Diff line change
@@ -104,7 +104,10 @@ llvm-config = "{llvm_config}"
"tests/incremental",
"tests/mir-opt",
"tests/pretty",
// Make sure that we don't use too new GLIBC symbols on x64
"tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu",
// Make sure that we use LLD by default on x64
"tests/run-make/rust-lld-x86_64-unknown-linux-gnu-dist",
"tests/ui",
"tests/crashes",
];
3 changes: 1 addition & 2 deletions tests/run-make/compressed-debuginfo-zstd/rmake.rs
Original file line number Diff line number Diff line change
@@ -26,9 +26,8 @@ fn prepare_and_check<F: FnOnce(&mut Rustc) -> &mut Rustc>(to_find: &str, prepare
run_in_tmpdir(|| {
let mut rustc = Rustc::new();
rustc
.arg("-Zlinker-features=+lld")
.arg("-Clinker-features=+lld")
.arg("-Clink-self-contained=+linker")
.arg("-Zunstable-options")
.arg("-Cdebuginfo=full")
.input("main.rs");
prepare_rustc(&mut rustc).run();
1 change: 0 additions & 1 deletion tests/run-make/rust-lld-by-default-beta-stable/main.rs

This file was deleted.

14 changes: 0 additions & 14 deletions tests/run-make/rust-lld-by-default-beta-stable/rmake.rs

This file was deleted.

3 changes: 2 additions & 1 deletion tests/run-make/rust-lld-custom-target/rmake.rs
Original file line number Diff line number Diff line change
@@ -23,7 +23,8 @@ fn main() {
rustc()
.crate_type("cdylib")
.target("custom-target.json")
.arg("-Zlinker-features=-lld")
.arg("-Clinker-features=-lld")
.arg("-Zunstable-options")
.input("lib.rs"),
);
}
2 changes: 1 addition & 1 deletion tests/run-make/rust-lld-link-script-provide/rmake.rs
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ use run_make_support::rustc;
fn main() {
rustc()
.input("main.rs")
.arg("-Zlinker-features=+lld")
.arg("-Clinker-features=+lld")
.arg("-Clink-self-contained=+linker")
.arg("-Zunstable-options")
.link_arg("-Tscript.t")
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
// Ensure that rust-lld is used as the default linker on `x86_64-unknown-linux-gnu` on the nightly
// channel, and that it can also be turned off with a CLI flag.
// Ensure that rust-lld is used as the default linker on `x86_64-unknown-linux-gnu`
// dist artifacts and that it can also be turned off with a CLI flag.

//@ needs-rust-lld
//@ ignore-beta
//@ ignore-stable
//@ only-dist
//@ only-x86_64-unknown-linux-gnu

use run_make_support::linker::{assert_rustc_doesnt_use_lld, assert_rustc_uses_lld};
use run_make_support::rustc;

fn main() {
// A regular compilation should use rust-lld by default. We'll check that by asking the linker
// to display its version number with a link-arg.
// A regular compilation should use rust-lld by default.
assert_rustc_uses_lld(rustc().input("main.rs"));

// But it can still be disabled by turning the linker feature off.
assert_rustc_doesnt_use_lld(rustc().arg("-Zlinker-features=-lld").input("main.rs"));
assert_rustc_doesnt_use_lld(rustc().arg("-Clinker-features=-lld").input("main.rs"));
}
5 changes: 5 additions & 0 deletions tests/run-make/rust-lld-x86_64-unknown-linux-gnu/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Test linking using `cc` with `rust-lld`, which is on by default on the x86_64-unknown-linux-gnu
// target.
// See https://github.com/rust-lang/compiler-team/issues/510 for more info

fn main() {}
Loading
Oops, something went wrong.
Loading
Oops, something went wrong.