Skip to content

Commit 0fb8071

Browse files
committed
use LinkSelfContained for -C link-self-contained
1 parent 5d91c1c commit 0fb8071

File tree

4 files changed

+91
-4
lines changed

4 files changed

+91
-4
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1688,7 +1688,7 @@ fn detect_self_contained_mingw(sess: &Session) -> bool {
16881688
/// instead of being found somewhere on the host system.
16891689
/// We only provide such support for a very limited number of targets.
16901690
fn self_contained(sess: &Session, crate_type: CrateType) -> bool {
1691-
if let Some(self_contained) = sess.opts.cg.link_self_contained {
1691+
if let Some(self_contained) = sess.opts.cg.link_self_contained.explicitly_set {
16921692
if sess.target.link_self_contained == LinkSelfContainedDefault::False {
16931693
sess.emit_err(errors::UnsupportedLinkSelfContained);
16941694
}

compiler/rustc_interface/src/tests.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_session::config::rustc_optgroups;
88
use rustc_session::config::DebugInfo;
99
use rustc_session::config::Input;
1010
use rustc_session::config::InstrumentXRay;
11+
use rustc_session::config::LinkSelfContained;
1112
use rustc_session::config::TraitSolver;
1213
use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
1314
use rustc_session::config::{
@@ -579,7 +580,7 @@ fn test_codegen_options_tracking_hash() {
579580
untracked!(incremental, Some(String::from("abc")));
580581
// `link_arg` is omitted because it just forwards to `link_args`.
581582
untracked!(link_args, vec![String::from("abc"), String::from("def")]);
582-
untracked!(link_self_contained, Some(true));
583+
untracked!(link_self_contained, LinkSelfContained::on());
583584
untracked!(linker, Some(PathBuf::from("linker")));
584585
untracked!(linker_flavor, Some(LinkerFlavorCli::Gcc));
585586
untracked!(no_stack_check, true);

compiler/rustc_session/src/config.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,62 @@ bitflags::bitflags! {
253253
}
254254
}
255255

256+
impl FromStr for LinkSelfContainedComponents {
257+
type Err = ();
258+
259+
fn from_str(s: &str) -> Result<Self, Self::Err> {
260+
Ok(match s {
261+
"crto" => LinkSelfContainedComponents::CRT_OBJECTS,
262+
"libc" => LinkSelfContainedComponents::LIBC,
263+
"unwind" => LinkSelfContainedComponents::UNWIND,
264+
"linker" => LinkSelfContainedComponents::LINKER,
265+
"sanitizers" => LinkSelfContainedComponents::SANITIZERS,
266+
"mingw" => LinkSelfContainedComponents::MINGW,
267+
_ => return Err(()),
268+
})
269+
}
270+
}
271+
272+
impl LinkSelfContained {
273+
/// Incorporates an enabled or disabled component as specified on the CLI, if possible.
274+
/// For example: `+linker`, and `-crto`.
275+
pub(crate) fn handle_cli_component(&mut self, component: &str) -> Result<(), ()> {
276+
// Note that for example `-Cself-contained=y -Cself-contained=-linker` is not an explicit
277+
// set of all values like `y` or `n` used to be. Therefore, if this flag had previously been
278+
// set in bulk with its historical values, then manually setting a component clears that
279+
// `explicitly_set` state.
280+
if let Some(component_to_enable) = component.strip_prefix("+") {
281+
self.explicitly_set = None;
282+
self.components.insert(component_to_enable.parse()?);
283+
Ok(())
284+
} else if let Some(component_to_disable) = component.strip_prefix("-") {
285+
self.explicitly_set = None;
286+
self.components.remove(component_to_disable.parse()?);
287+
Ok(())
288+
} else {
289+
Err(())
290+
}
291+
}
292+
293+
/// Turns all components on or off and records that this was done explicitly for compatibility
294+
/// purposes.
295+
pub(crate) fn set_all_explicitly(&mut self, enabled: bool) {
296+
self.explicitly_set = Some(enabled);
297+
self.components = if enabled {
298+
LinkSelfContainedComponents::all()
299+
} else {
300+
LinkSelfContainedComponents::empty()
301+
};
302+
}
303+
304+
/// Helper creating a fully enabled `LinkSelfContained` instance. Used in tests.
305+
pub fn on() -> Self {
306+
let mut on = LinkSelfContained::default();
307+
on.set_all_explicitly(true);
308+
on
309+
}
310+
}
311+
256312
/// Used with `-Z assert-incr-state`.
257313
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
258314
pub enum IncrementalStateAssertion {

compiler/rustc_session/src/options.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,8 @@ mod desc {
410410
pub const parse_split_dwarf_kind: &str =
411411
"one of supported split dwarf modes (`split` or `single`)";
412412
pub const parse_gcc_ld: &str = "one of: no value, `lld`";
413+
pub const parse_link_self_contained: &str = "one of: `y`, `yes`, `on`, `n`, `no`, `off`, or a list of enabled (`+` prefix) and disabled (`-` prefix) \
414+
components: `crto`, `libc`, `unwind`, `linker`, `sanitizers`, `mingw`";
413415
pub const parse_stack_protector: &str =
414416
"one of (`none` (default), `basic`, `strong`, or `all`)";
415417
pub const parse_branch_protection: &str =
@@ -1122,6 +1124,34 @@ mod parse {
11221124
}
11231125
}
11241126

1127+
pub(crate) fn parse_link_self_contained(slot: &mut LinkSelfContained, v: Option<&str>) -> bool {
1128+
// Whenever `-C link-self-contained` is passed without a value, it's an opt-in
1129+
// just like `parse_opt_bool`, the historical value of this flag.
1130+
//
1131+
// 1. Parse historical single bool values
1132+
let s = v.unwrap_or("y");
1133+
match s {
1134+
"y" | "yes" | "on" => {
1135+
slot.set_all_explicitly(true);
1136+
return true;
1137+
}
1138+
"n" | "no" | "off" => {
1139+
slot.set_all_explicitly(false);
1140+
return true;
1141+
}
1142+
_ => {}
1143+
}
1144+
1145+
// 2. Parse a list of enabled and disabled components.
1146+
for comp in s.split(",") {
1147+
if slot.handle_cli_component(comp).is_err() {
1148+
return false;
1149+
}
1150+
}
1151+
1152+
true
1153+
}
1154+
11251155
pub(crate) fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool {
11261156
match v {
11271157
Some("command") => *slot = Some(WasiExecModel::Command),
@@ -1265,9 +1295,9 @@ options! {
12651295
#[rustc_lint_opt_deny_field_access("use `Session::link_dead_code` instead of this field")]
12661296
link_dead_code: Option<bool> = (None, parse_opt_bool, [TRACKED],
12671297
"keep dead code at link time (useful for code coverage) (default: no)"),
1268-
link_self_contained: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
1298+
link_self_contained: LinkSelfContained = (LinkSelfContained::default(), parse_link_self_contained, [UNTRACKED],
12691299
"control whether to link Rust provided C objects/libraries or rely
1270-
on C toolchain installed in the system"),
1300+
on a C toolchain or linker installed in the system"),
12711301
linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
12721302
"system linker to link outputs with"),
12731303
linker_flavor: Option<LinkerFlavorCli> = (None, parse_linker_flavor, [UNTRACKED],

0 commit comments

Comments
 (0)