Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
lqd committed Sep 20, 2023
1 parent 677d1f5 commit fb7cde3
Show file tree
Hide file tree
Showing 14 changed files with 316 additions and 95 deletions.
1 change: 0 additions & 1 deletion Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4391,7 +4391,6 @@ dependencies = [
name = "rustc_session"
version = "0.0.0"
dependencies = [
"bitflags 1.3.2",
"getopts",
"libc",
"rustc_ast",
Expand Down
43 changes: 33 additions & 10 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ use rustc_session::utils::NativeLibKind;
/// need out of the shared crate context before we get rid of it.
use rustc_session::{filesearch, Session};
use rustc_span::symbol::Symbol;
use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
use rustc_target::spec::crt_objects::CrtObjects;
use rustc_target::spec::LinkSelfContained;
use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld, PanicStrategy};
use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo};

Expand Down Expand Up @@ -1709,21 +1710,37 @@ fn detect_self_contained_mingw(sess: &Session) -> bool {
/// instead of being found somewhere on the host system.
/// We only provide such support for a very limited number of targets.
fn self_contained(sess: &Session, crate_type: CrateType) -> bool {
// Emit an error if the user requested self-contained mode on the CLI but the target explicitly
// refuses it.
if let Some(self_contained) = sess.opts.cg.link_self_contained.explicitly_set {
if sess.target.link_self_contained == LinkSelfContainedDefault::False {
if sess.target.link_self_contained.is_disabled() {
sess.emit_err(errors::UnsupportedLinkSelfContained);
}
return self_contained;
}

match sess.target.link_self_contained {
LinkSelfContainedDefault::False => false,
LinkSelfContainedDefault::True => true,
LinkSelfContained::True => true,
LinkSelfContained::False => false,
LinkSelfContained::WithComponents(components) => {
if components.is_all() {
true
} else if components.is_empty() {
false
} else {
// FIXME: Currently no target makes use of individual components to mean
// self-contained linking is fully enabled, in the sense of what the code downstream
// from here expects. Until components are handled a bit more deeply, we can
// consider that it's disabled and remain backwards compatible.
false
}
}

// FIXME: Find a better heuristic for "native musl toolchain is available",
// based on host and linker path, for example.
// (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237).
LinkSelfContainedDefault::Musl => sess.crt_static(Some(crate_type)),
LinkSelfContainedDefault::Mingw => {
LinkSelfContained::InferredForMusl => sess.crt_static(Some(crate_type)),
LinkSelfContained::InferredForMingw => {
sess.host == sess.target
&& sess.target.vendor != "uwp"
&& detect_self_contained_mingw(&sess)
Expand Down Expand Up @@ -2992,9 +3009,15 @@ fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
}

// 1. Implement the "self-contained" part of this feature by adding rustc distribution
// directories to the tool's search path.
let self_contained_linker = sess.opts.cg.link_self_contained.linker() || unstable_use_lld;
if self_contained_linker {
// directories to the tool's search path, depending on a mix between what users can specify on
// the CLI, and what the target spec enables (as it can't disable components):
// - if the self-contained linker is enabled on the CLI or by the target spec (or by the
// unstable CLI flag that will be removed eventually),
// - and if the self-contained linker is not disabled on the CLI.
let self_contained_linker = sess.target.options.link_self_contained.is_linker_enabled()
|| sess.opts.cg.link_self_contained.is_linker_enabled()
|| unstable_use_lld;
if self_contained_linker && !sess.opts.cg.link_self_contained.is_linker_disabled() {
for path in sess.get_tools_search_paths(false) {
cmd.arg({
let mut arg = OsString::from("-B");
Expand All @@ -3005,7 +3028,7 @@ fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
}

// 2. Implement the "linker flavor" part of this feature by asking `cc` to use some kind of
// `lld` as the linker.
// `lld` as the linker.
cmd.arg("-fuse-ld=lld");

if !flavor.is_gnu() {
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_session/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"

[dependencies]
bitflags = "1.2.1"
getopts = "0.2"
rustc_macros = { path = "../rustc_macros" }
tracing = "0.1"
Expand Down
84 changes: 34 additions & 50 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::{EarlyErrorHandler, Session};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
use rustc_target::abi::Align;
use rustc_target::spec::LinkSelfContainedComponents;
use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo};
use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};

Expand Down Expand Up @@ -232,75 +233,50 @@ pub struct LinkSelfContained {
/// Used for compatibility with the existing opt-in and target inference.
pub explicitly_set: Option<bool>,

/// The components that are enabled.
components: LinkSelfContainedComponents,
}
/// The components that are enabled on the CLI, using the `+component` syntax or one of the
/// `true` shorcuts.
enabled_components: LinkSelfContainedComponents,

bitflags::bitflags! {
#[derive(Default)]
/// The `-C link-self-contained` components that can individually be enabled or disabled.
pub struct LinkSelfContainedComponents: u8 {
/// CRT objects (e.g. on `windows-gnu`, `musl`, `wasi` targets)
const CRT_OBJECTS = 1 << 0;
/// libc static library (e.g. on `musl`, `wasi` targets)
const LIBC = 1 << 1;
/// libgcc/libunwind (e.g. on `windows-gnu`, `fuchsia`, `fortanix`, `gnullvm` targets)
const UNWIND = 1 << 2;
/// Linker, dlltool, and their necessary libraries (e.g. on `windows-gnu` and for `rust-lld`)
const LINKER = 1 << 3;
/// Sanitizer runtime libraries
const SANITIZERS = 1 << 4;
/// Other MinGW libs and Windows import libs
const MINGW = 1 << 5;
}
}

impl FromStr for LinkSelfContainedComponents {
type Err = ();

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"crto" => LinkSelfContainedComponents::CRT_OBJECTS,
"libc" => LinkSelfContainedComponents::LIBC,
"unwind" => LinkSelfContainedComponents::UNWIND,
"linker" => LinkSelfContainedComponents::LINKER,
"sanitizers" => LinkSelfContainedComponents::SANITIZERS,
"mingw" => LinkSelfContainedComponents::MINGW,
_ => return Err(()),
})
}
/// The components that are disabled on the CLI, using the `-component` syntax or one of the
/// `false` shortcuts.
disabled_components: LinkSelfContainedComponents,
}

impl LinkSelfContained {
/// Incorporates an enabled or disabled component as specified on the CLI, if possible.
/// For example: `+linker`, and `-crto`.
pub(crate) fn handle_cli_component(&mut self, component: &str) -> Result<(), ()> {
pub(crate) fn handle_cli_component(&mut self, component: &str) -> Option<()> {
// Note that for example `-Cself-contained=y -Cself-contained=-linker` is not an explicit
// set of all values like `y` or `n` used to be. Therefore, if this flag had previously been
// set in bulk with its historical values, then manually setting a component clears that
// `explicitly_set` state.
if let Some(component_to_enable) = component.strip_prefix('+') {
self.explicitly_set = None;
self.components.insert(component_to_enable.parse()?);
Ok(())
self.enabled_components
.insert(LinkSelfContainedComponents::from_str(component_to_enable)?);
Some(())
} else if let Some(component_to_disable) = component.strip_prefix('-') {
self.explicitly_set = None;
self.components.remove(component_to_disable.parse()?);
Ok(())
self.disabled_components
.insert(LinkSelfContainedComponents::from_str(component_to_disable)?);
Some(())
} else {
Err(())
None
}
}

/// Turns all components on or off and records that this was done explicitly for compatibility
/// purposes.
pub(crate) fn set_all_explicitly(&mut self, enabled: bool) {
self.explicitly_set = Some(enabled);
self.components = if enabled {
LinkSelfContainedComponents::all()

if enabled {
self.enabled_components = LinkSelfContainedComponents::all();
self.disabled_components = LinkSelfContainedComponents::empty();
} else {
LinkSelfContainedComponents::empty()
};
self.enabled_components = LinkSelfContainedComponents::empty();
self.disabled_components = LinkSelfContainedComponents::all();
}
}

/// Helper creating a fully enabled `LinkSelfContained` instance. Used in tests.
Expand All @@ -314,13 +290,21 @@ 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.components.is_empty();
let any_component_set =
!self.enabled_components.is_empty() || !self.disabled_components.is_empty();
self.explicitly_set.is_none() && any_component_set
}

/// Returns whether the self-contained linker component is enabled.
pub fn linker(&self) -> bool {
self.components.contains(LinkSelfContainedComponents::LINKER)
/// Returns whether the self-contained linker component was enabled on the CLI, using the
/// `-C link-self-contained=+linker` syntax, or one of the `true` shorcuts.
pub fn is_linker_enabled(&self) -> bool {
self.enabled_components.contains(LinkSelfContainedComponents::LINKER)
}

/// Returns whether the self-contained linker component was disabled on the CLI, using the
/// `-C link-self-contained=-linker` syntax, or one of the `false` shorcuts.
pub fn is_linker_disabled(&self) -> bool {
self.disabled_components.contains(LinkSelfContainedComponents::LINKER)
}
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1160,7 +1160,7 @@ mod parse {

// 2. Parse a list of enabled and disabled components.
for comp in s.split(',') {
if slot.handle_cli_component(comp).is_err() {
if slot.handle_cli_component(comp).is_none() {
return false;
}
}
Expand Down
13 changes: 0 additions & 13 deletions compiler/rustc_target/src/spec/crt_objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
//! but not gcc's. As a result rustc cannot link with C++ static libraries (#36710)
//! when linking in self-contained mode.

use crate::json::{Json, ToJson};
use crate::spec::LinkOutputKind;
use std::borrow::Cow;
use std::collections::BTreeMap;
Expand Down Expand Up @@ -147,15 +146,3 @@ impl FromStr for LinkSelfContainedDefault {
})
}
}

impl ToJson for LinkSelfContainedDefault {
fn to_json(&self) -> Json {
match *self {
LinkSelfContainedDefault::False => "false",
LinkSelfContainedDefault::True => "true",
LinkSelfContainedDefault::Musl => "musl",
LinkSelfContainedDefault::Mingw => "mingw",
}
.to_json()
}
}
5 changes: 3 additions & 2 deletions compiler/rustc_target/src/spec/linux_musl_base.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::spec::crt_objects::{self, LinkSelfContainedDefault};
use crate::spec::crt_objects;
use crate::spec::LinkSelfContained;
use crate::spec::TargetOptions;

pub fn opts() -> TargetOptions {
Expand All @@ -7,7 +8,7 @@ pub fn opts() -> TargetOptions {
base.env = "musl".into();
base.pre_link_objects_self_contained = crt_objects::pre_musl_self_contained();
base.post_link_objects_self_contained = crt_objects::post_musl_self_contained();
base.link_self_contained = LinkSelfContainedDefault::Musl;
base.link_self_contained = LinkSelfContained::InferredForMusl;

// These targets statically link libc by default
base.crt_static_default = true;
Expand Down
Loading

0 comments on commit fb7cde3

Please sign in to comment.