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
Show file tree
Hide file tree
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
Expand Up @@ -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
Expand Down
66 changes: 57 additions & 9 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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`.
Expand Down Expand Up @@ -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",
Expand All @@ -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",
);
}
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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],
Expand Down
15 changes: 13 additions & 2 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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)
Expand Down
4 changes: 1 addition & 3 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}

Expand Down
6 changes: 1 addition & 5 deletions src/bootstrap/src/core/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
34 changes: 30 additions & 4 deletions src/doc/rustc/src/codegen-options/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down
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
Expand Up @@ -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
Expand Up @@ -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",
];
Expand Down
3 changes: 1 addition & 2 deletions tests/run-make/compressed-debuginfo-zstd/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
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
Expand Up @@ -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
Expand Up @@ -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")
Expand Down
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
Loading