From 0fb80715bbf2ee63e17f3cf65fc60a3db8768e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 21 Jun 2023 21:46:36 +0000 Subject: [PATCH] use `LinkSelfContained` for `-C link-self-contained` --- compiler/rustc_codegen_ssa/src/back/link.rs | 2 +- compiler/rustc_interface/src/tests.rs | 3 +- compiler/rustc_session/src/config.rs | 56 +++++++++++++++++++++ compiler/rustc_session/src/options.rs | 34 ++++++++++++- 4 files changed, 91 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 557b120b2c8f..7e839520dfe7 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1688,7 +1688,7 @@ 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 { - if let Some(self_contained) = sess.opts.cg.link_self_contained { + if let Some(self_contained) = sess.opts.cg.link_self_contained.explicitly_set { if sess.target.link_self_contained == LinkSelfContainedDefault::False { sess.emit_err(errors::UnsupportedLinkSelfContained); } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 6054b48b0b53..0f5dba1df147 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -8,6 +8,7 @@ use rustc_session::config::rustc_optgroups; use rustc_session::config::DebugInfo; use rustc_session::config::Input; use rustc_session::config::InstrumentXRay; +use rustc_session::config::LinkSelfContained; use rustc_session::config::TraitSolver; use rustc_session::config::{build_configuration, build_session_options, to_crate_config}; use rustc_session::config::{ @@ -579,7 +580,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(LinkerFlavorCli::Gcc)); untracked!(no_stack_check, true); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 1aeb983c23eb..dc252d8b6888 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -253,6 +253,62 @@ bitflags::bitflags! { } } +impl FromStr for LinkSelfContainedComponents { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "crto" => LinkSelfContainedComponents::CRT_OBJECTS, + "libc" => LinkSelfContainedComponents::LIBC, + "unwind" => LinkSelfContainedComponents::UNWIND, + "linker" => LinkSelfContainedComponents::LINKER, + "sanitizers" => LinkSelfContainedComponents::SANITIZERS, + "mingw" => LinkSelfContainedComponents::MINGW, + _ => return Err(()), + }) + } +} + +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<(), ()> { + // 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(()) + } else if let Some(component_to_disable) = component.strip_prefix("-") { + self.explicitly_set = None; + self.components.remove(component_to_disable.parse()?); + Ok(()) + } else { + Err(()) + } + } + + /// 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() + } else { + LinkSelfContainedComponents::empty() + }; + } + + /// Helper creating a fully enabled `LinkSelfContained` instance. Used in tests. + pub fn on() -> Self { + let mut on = LinkSelfContained::default(); + on.set_all_explicitly(true); + on + } +} + /// Used with `-Z assert-incr-state`. #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum IncrementalStateAssertion { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index e5063eef47af..65cb94a9ab8f 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -410,6 +410,8 @@ 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`"; + pub const parse_link_self_contained: &str = "one of: `y`, `yes`, `on`, `n`, `no`, `off`, or a list of enabled (`+` prefix) and disabled (`-` prefix) \ + components: `crto`, `libc`, `unwind`, `linker`, `sanitizers`, `mingw`"; pub const parse_stack_protector: &str = "one of (`none` (default), `basic`, `strong`, or `all`)"; pub const parse_branch_protection: &str = @@ -1122,6 +1124,34 @@ mod parse { } } + 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`, the historical value of this flag. + // + // 1. Parse historical single bool values + let s = v.unwrap_or("y"); + match s { + "y" | "yes" | "on" => { + slot.set_all_explicitly(true); + return true; + } + "n" | "no" | "off" => { + slot.set_all_explicitly(false); + return true; + } + _ => {} + } + + // 2. Parse a list of enabled and disabled components. + for comp in s.split(",") { + if slot.handle_cli_component(comp).is_err() { + return false; + } + } + + true + } + pub(crate) fn parse_wasi_exec_model(slot: &mut Option, v: Option<&str>) -> bool { match v { Some("command") => *slot = Some(WasiExecModel::Command), @@ -1265,9 +1295,9 @@ options! { #[rustc_lint_opt_deny_field_access("use `Session::link_dead_code` instead of this field")] link_dead_code: Option = (None, parse_opt_bool, [TRACKED], "keep dead code at link time (useful for code coverage) (default: no)"), - link_self_contained: Option = (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"), + on a C toolchain or linker installed in the system"), linker: Option = (None, parse_opt_pathbuf, [UNTRACKED], "system linker to link outputs with"), linker_flavor: Option = (None, parse_linker_flavor, [UNTRACKED],