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

Implement unstable -Clink-self-contained values for MCP 510 #96884

Closed
wants to merge 6 commits into from
Closed
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 @@ -1534,7 +1534,7 @@ fn detect_self_contained_mingw(sess: &Session) -> bool {
/// Whether we link to our own CRT objects instead of relying on gcc to pull them.
/// We only provide such support for a very limited number of targets.
fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool {
if let Some(self_contained) = sess.opts.cg.link_self_contained {
if let Some(self_contained) = sess.opts.cg.link_self_contained.crt.is_explicitly_set() {
return self_contained;
}

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::interface::parse_cfgspecs;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
use rustc_session::config::InstrumentCoverage;
use rustc_session::config::LinkSelfContained;
use rustc_session::config::Strip;
use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
use rustc_session::config::{
Expand Down Expand Up @@ -549,7 +550,7 @@ fn test_codegen_options_tracking_hash() {
untracked!(incremental, Some(String::from("abc")));
// `link_arg` is omitted because it just forwards to `link_args`.
untracked!(link_args, vec![String::from("abc"), String::from("def")]);
untracked!(link_self_contained, Some(true));
untracked!(link_self_contained, LinkSelfContained::on());
untracked!(linker, Some(PathBuf::from("linker")));
untracked!(linker_flavor, Some(LinkerFlavor::Gcc));
untracked!(no_stack_check, true);
Expand Down
156 changes: 156 additions & 0 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,142 @@ impl LinkerPluginLto {
}
}

/// The different values `-C link-self-contained` can take.
///
/// They are fine-grained, and control the behavior of:
/// - linking to our own CRT objects (the historical default)
/// - using a linker we distribute
///
/// Since this flag historically targeted the CRT use-case, the defaults haven't changed, but there
/// are new values so that users can choose that behavior in combination with the linker use-case.
///
/// For example:
/// - the absence of the `-C link-self-contained` was the historical default, and therefore this
/// default value still targets `auto` (`LinkSelfContainedCrt::Auto`).
/// - `-C link-self-contained=linker` turns on the linker, while keeping the default CRT behavior.
/// - explicitly turning on the CRT linking can be done as the historical `-C link-self-contained=y`,
/// or the fine-grained `-C link-self-contained=crt`
/// - turning both on can be done with `-C link-self-contained=all`
///
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct LinkSelfContained {
pub crt: LinkSelfContainedCrt,
pub linker: LinkSelfContainedLinker,
}

impl LinkSelfContained {
/// Explicitly turns off the self-contained linker facet, becoming an opt-out that is the
/// historically stable `-C link-self-contained=y` behavior.
fn crt_only() -> Self {
LinkSelfContained { crt: LinkSelfContainedCrt::On, linker: LinkSelfContainedLinker::Off }
}

/// Keeps stable behavior only turning the self-contained CRT linking on.
pub fn on() -> Self {
LinkSelfContained::crt_only()
}

fn off() -> Self {
LinkSelfContained { crt: LinkSelfContainedCrt::Off, linker: LinkSelfContainedLinker::Off }
}

/// Explicitly turns off the self-contained linker facet, becoming an opt-out that is the
/// historically stable default, target-defined, behavior.
///
/// The current default.
fn auto() -> Self {
LinkSelfContained { crt: LinkSelfContainedCrt::Auto, linker: LinkSelfContainedLinker::Off }
}

fn linker() -> Self {
LinkSelfContained { crt: LinkSelfContainedCrt::Auto, linker: LinkSelfContainedLinker::On }
}

fn all() -> Self {
LinkSelfContained { crt: LinkSelfContainedCrt::On, linker: LinkSelfContainedLinker::On }
}
}

impl Default for LinkSelfContained {
fn default() -> Self {
LinkSelfContained::auto()
}
}

impl FromStr for LinkSelfContained {
type Err = ();

fn from_str(s: &str) -> Result<Self, ()> {
// TMP: do we also need "linker_only", crt:off and linker:on ? Except in rare targets, this
// use-case should be taken care of by "linker" for crt:auto linker:on.

Ok(match s {
// Historical value parsing: a bool option
"no" | "n" | "off" => LinkSelfContained::off(),
"yes" | "y" | "on" => LinkSelfContained::on(),

// New fine-grained facets
"crt" => {
// This is the same as `-C link-self-contained=y`, but allows to possibly change
// that while keeping the current only turning on self-contained CRT linking. Also
// makes an explicit value to opt into only a single facet.
LinkSelfContained::crt_only()
}
"auto" => LinkSelfContained::auto(),
"linker" => LinkSelfContained::linker(),

// Composite of both
"all" => LinkSelfContained::all(),
_ => return Err(()),
})
}
}

/// Historically, `-C link-self-contained` was mainly about linking to our own CRT objects. This has
/// been extracted to a few dedicated values, while keeping the existing stable values as-is: the
/// default value, or opt-in for the whole flag are still these CRT-related values.
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum LinkSelfContainedCrt {
/// The historical default value, when `-C link-self-contained` was not specified.The
/// self-contained linking behavior is target-defined in this case.
Auto,

/// The historical value for `-C link-self-contained=y`.
On,

/// When self-contained linking is explicitly turned off, with `-C link-self-contained=n`
Off,
}

impl LinkSelfContainedCrt {
pub fn is_explicitly_set(&self) -> Option<bool> {
match self {
LinkSelfContainedCrt::On => Some(true),
LinkSelfContainedCrt::Off => Some(false),
LinkSelfContainedCrt::Auto => None,
}
}
}

/// The different linker-related options for `-C link-self-contained`, to choose between
/// using system-installed linkers, or one present in the rust distribution.
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum LinkSelfContainedLinker {
/// Whenever `-C link-self-contained=linker` is present. This opts in to using
/// a linker we distribute (e.g. `rust-lld`).
On,

/// The default case: when `-C link-self-contained=linker` is absent, and when self-contained
/// linking is explicitly turned off, with `-C link-self-contained=n`.
Off,
}

impl LinkSelfContainedLinker {
pub fn is_on(&self) -> bool {
*self == LinkSelfContainedLinker::On
}
}

/// The different settings that can be enabled via the `-Z location-detail` flag.
#[derive(Clone, PartialEq, Hash, Debug)]
pub struct LocationDetail {
Expand Down Expand Up @@ -2407,6 +2543,26 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
);
}

// For testing purposes, until we have more feedback about these options: ensure `-Z
// unstable-options` is enabled when using the unstable `-C link-self-contained` options.
if !debugging_opts.unstable_options {
let uses_unstable_self_contained_option =
matches.opt_strs("C").iter().any(|option| match option.as_str() {
"link-self-contained=crt"
| "link-self-contained=auto"
| "link-self-contained=linker"
| "link-self-contained=all" => true,
_ => false,
});
if uses_unstable_self_contained_option {
early_error(
error_format,
"only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off` are stable, \
the `-Z unstable-options` flag must also be passed to use the unstable values",
);
}
}

let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);

let cg = cg;
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_session/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ pub mod output;

pub use getopts;

#[cfg(test)]
mod tests;

/// Requirements for a `StableHashingContext` to be used in this crate.
/// This is a hack to allow using the `HashStable_Generic` derive macro
/// instead of implementing everything in `rustc_middle`.
Expand Down
20 changes: 19 additions & 1 deletion compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,10 @@ mod desc {
pub const parse_split_dwarf_kind: &str =
"one of supported split dwarf modes (`split` or `single`)";
pub const parse_gcc_ld: &str = "one of: no value, `lld`";
// FIXME: add link to reference or other documentation, where the `-Clink-self-contained`
// options will be explained in more detail.
pub const parse_link_self_contained: &str =
"one of: `y`, `yes`, `on`, `n`, `no`, `off`, `auto`, `crt`, `linker`, `all`";
pub const parse_stack_protector: &str =
"one of (`none` (default), `basic`, `strong`, or `all`)";
pub const parse_branch_protection: &str =
Expand Down Expand Up @@ -1027,6 +1031,20 @@ mod parse {
true
}

/// Parses `-C link-self-contained`: it used to be a boolean without a static default, but now
/// also accepts some strings, in addition to the regular boolean values.
pub(crate) fn parse_link_self_contained(slot: &mut LinkSelfContained, v: Option<&str>) -> bool {
// Whenever `-C link-self-contained` is passed without a value, it's an opt-in
// just like `parse_opt_bool`.
let s = v.unwrap_or("y");

match LinkSelfContained::from_str(s).ok() {
Some(value) => *slot = value,
None => return false,
}
true
}

pub(crate) fn parse_stack_protector(slot: &mut StackProtector, v: Option<&str>) -> bool {
match v.and_then(|s| StackProtector::from_str(s).ok()) {
Some(ssp) => *slot = ssp,
Expand Down Expand Up @@ -1116,7 +1134,7 @@ options! {
"extra arguments to append to the linker invocation (space separated)"),
link_dead_code: Option<bool> = (None, parse_opt_bool, [TRACKED],
"keep dead code at link time (useful for code coverage) (default: no)"),
link_self_contained: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
link_self_contained: LinkSelfContained = (LinkSelfContained::default(), parse_link_self_contained, [UNTRACKED],
"control whether to link Rust provided C objects/libraries or rely
on C toolchain installed in the system"),
linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
Expand Down
71 changes: 71 additions & 0 deletions compiler/rustc_session/src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use std::str::FromStr;

use crate::config::{LinkSelfContained, LinkSelfContainedCrt, LinkSelfContainedLinker};

/// When adding support for `-C link-self-contained=linker`, we want to ensure the existing
/// values are still supported as-is: they are option values that can be used on stable.
#[test]
pub fn parse_stable_self_contained() {
// The existing default is when the argument is not used, the behavior depends on the
// target.
assert_eq!(
LinkSelfContained::default(),
LinkSelfContained { crt: LinkSelfContainedCrt::Auto, linker: LinkSelfContainedLinker::Off }
);

// Turning the flag `on` should currently only enable the default on stable.
assert_eq!(
LinkSelfContained::from_str("on"),
Ok(LinkSelfContained {
crt: LinkSelfContainedCrt::On,
linker: LinkSelfContainedLinker::Off
})
);

// Turning the flag `off` applies to both facets.
assert_eq!(
LinkSelfContained::from_str("off"),
Ok(LinkSelfContained {
crt: LinkSelfContainedCrt::Off,
linker: LinkSelfContainedLinker::Off
})
);

assert_eq!(
LinkSelfContained::from_str("crt"),
Ok(LinkSelfContained {
crt: LinkSelfContainedCrt::On,
linker: LinkSelfContainedLinker::Off
})
);
}

#[test]
pub fn parse_self_contained_with_linker() {
// Turning the linker on doesn't change the CRT behavior
assert_eq!(
LinkSelfContained::from_str("linker"),
Ok(LinkSelfContained {
crt: LinkSelfContainedCrt::Auto,
linker: LinkSelfContainedLinker::On
})
);

assert_eq!(
LinkSelfContained::from_str("all"),
Ok(LinkSelfContained {
crt: LinkSelfContainedCrt::On,
linker: LinkSelfContainedLinker::On
})
);

// If `linker` is turned on by default someday, we need to be able to go back to the current
// default.
assert_eq!(
LinkSelfContained::from_str("auto"),
Ok(LinkSelfContained {
crt: LinkSelfContainedCrt::Auto,
linker: LinkSelfContainedLinker::Off
})
);
}
2 changes: 2 additions & 0 deletions src/test/ui/linkers/unstable_link_self_contained.all.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values

2 changes: 2 additions & 0 deletions src/test/ui/linkers/unstable_link_self_contained.auto.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values

2 changes: 2 additions & 0 deletions src/test/ui/linkers/unstable_link_self_contained.crt.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values

11 changes: 11 additions & 0 deletions src/test/ui/linkers/unstable_link_self_contained.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// check-fail
// revisions: crt auto linker all
// [crt] compile-flags: -C link-self-contained=crt
// [auto] compile-flags: -C link-self-contained=auto
// [linker] compile-flags: -C link-self-contained=linker
// [all] compile-flags: -C link-self-contained=all

// Test ensuring that the unstable values of the stable `-C link-self-contained` flag
// require using `-Z unstable options`

fn main() {}