-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[WIP] parameterize -C prefer-dynamic
#88101
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
Changes from 1 commit
a8ed3a4
dbe4d27
bf817f6
5d77479
0099f6b
8d63ba2
172ba70
a2231a4
5509ab2
21778cb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,6 +63,68 @@ pub enum CFGuard { | |
Checks, | ||
} | ||
|
||
/// Handle `-C prefer-dynamic` flag: either its all, or its some explicit | ||
/// subset (potentially the empty set). | ||
#[derive(Clone, PartialEq, Hash, Debug)] | ||
pub enum PreferDynamicSet { | ||
/// Specified by the absence of `-C prefer-dynamic`, or via an explicit `-C prefer-dynamic=...` | ||
/// with value `n`, `no`, or `off`. | ||
/// | ||
/// Under this (default) behavior, the compiler first optimistically attempts to statically | ||
/// link everything, but if that fails, then attempts to dynamically link *everything* with a | ||
/// dylib path available. | ||
Unset, | ||
|
||
/// Specified via `-C prefer-dynamic` with no value. For backwards-compatibility, also | ||
/// specified via `-C prefer-dynamic=...` with value `y`, `yes`, or `on`. | ||
All, | ||
|
||
/// Specified via `-C prefer-dynamic=crate,...`. | ||
Set(BTreeSet<String>), | ||
} | ||
|
||
impl PreferDynamicSet { | ||
pub fn unset() -> Self { | ||
PreferDynamicSet::Unset | ||
} | ||
|
||
pub fn every_crate() -> Self { | ||
PreferDynamicSet::All | ||
} | ||
|
||
pub fn subset(crates: impl Iterator<Item = impl ToString>) -> Self { | ||
PreferDynamicSet::Set(crates.map(|x| x.to_string()).collect()) | ||
} | ||
|
||
pub fn is_unset(&self) -> bool { | ||
if let PreferDynamicSet::Unset = *self { true } else { false } | ||
} | ||
|
||
pub fn is_empty(&self) -> bool { | ||
match self { | ||
PreferDynamicSet::Unset => true, | ||
PreferDynamicSet::All => false, | ||
PreferDynamicSet::Set(s) => s.len() == 0, | ||
} | ||
} | ||
|
||
pub fn is_non_empty(&self) -> bool { | ||
match self { | ||
PreferDynamicSet::Unset => false, | ||
PreferDynamicSet::All => true, | ||
PreferDynamicSet::Set(s) => s.len() > 0, | ||
} | ||
} | ||
|
||
pub fn contains_crate(&self, crate_name: Symbol) -> bool { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think using just the crate name is not a good idea. It doesn't allow distinguishing between two different versions of the same library. Ideally it would accept the StableCrateId, but that is not accessible outside of rustc without depending on nightly ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would some encoding of crate name and an optionally-supplied version be sufficient to satisfy your criteria here? I'm thinking in the common cases, a single crate name is exactly what an end user will want to write down. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that would work I guess. Cargo could specify everything and a user just the crate name. |
||
match self { | ||
PreferDynamicSet::Unset => false, | ||
PreferDynamicSet::All => true, | ||
PreferDynamicSet::Set(s) => s.iter().any(|s| s == &*crate_name.as_str()), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Clone, Copy, Debug, PartialEq, Hash)] | ||
pub enum OptLevel { | ||
No, // -O0 | ||
|
@@ -2420,8 +2482,8 @@ crate mod dep_tracking { | |
use super::LdImpl; | ||
use super::{ | ||
CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto, | ||
LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, | ||
SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths, | ||
LtoCli, OptLevel, OutputType, OutputTypes, Passes, PreferDynamicSet, | ||
SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths, | ||
}; | ||
use crate::lint; | ||
use crate::options::WasiExecModel; | ||
|
@@ -2510,6 +2572,7 @@ crate mod dep_tracking { | |
TrimmedDefPaths, | ||
Option<LdImpl>, | ||
OutputType, | ||
PreferDynamicSet, | ||
RealFileName, | ||
); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -376,6 +376,8 @@ mod desc { | |
"one of supported relocation models (`rustc --print relocation-models`)"; | ||
pub const parse_code_model: &str = "one of supported code models (`rustc --print code-models`)"; | ||
pub const parse_tls_model: &str = "one of supported TLS models (`rustc --print tls-models`)"; | ||
pub const parse_prefer_dynamic: &str = | ||
"one of `y`, `yes`, `on`, `n`, `no`, `off`, or a comma separated list of crates"; | ||
pub const parse_target_feature: &str = parse_string; | ||
pub const parse_wasi_exec_model: &str = "either `command` or `reactor`"; | ||
pub const parse_split_debuginfo: &str = | ||
|
@@ -835,6 +837,38 @@ mod parse { | |
true | ||
} | ||
|
||
crate fn parse_prefer_dynamic(slot: &mut PreferDynamicSet, v: Option<&str>) -> bool { | ||
let s = match v { | ||
// Note: n/no/off do *not* map to an empty-set of crates. | ||
// | ||
// This is to continue supporting rustc's historical behavior where it attempts to | ||
// link everything statically, but failing that, then greedily link as many crates | ||
// dynamically as it can. | ||
// | ||
// If these options mapped to an empty set, then that would denote that no dynamic | ||
// linkage should be given preference over static, which would not correspond to | ||
// historical meaning of `-C prefer-dynamic=no`. | ||
// | ||
// (One requests an empty set by writing `-C prefer-dynamic=`, with an empty string | ||
// as the value.) | ||
Some("n") | Some("no") | Some("off") => PreferDynamicSet::unset(), | ||
|
||
// `-C prefer-dynamic` gives all crates preferred dynamic linkage. | ||
// `-C prefer-dynamic=...` with `y`/`yes`/`on` is a synonym, for backwards | ||
// compatibility. | ||
Some("y") | Some("yes") | Some("on") | None => PreferDynamicSet::every_crate(), | ||
|
||
// `-C prefer-dynamic=crate1,crate2,...` gives *just* crate1, crate2, ... preferred | ||
// dynamic linkage. | ||
Some(s) => { | ||
let v = s.split(',').map(|s| s.to_string()).collect(); | ||
PreferDynamicSet::Set(v) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe it should be a different argument as the new option is not a preference, but mandatory? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm. My intention was that it would still be a preference, in the sense that if you do I probably should add a test illustrating that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Update: I forgot that of course the choice isn't necessarily about which file to link in; you can still statically link a (Or at least, that's my current interpretation of the behavior I'm observing. Still digging a bit deeper.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update 2: Hmm maybe I was wrong about the above: In general There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, I have now made a run-make test that I think illustrates the current behavior of the system, including cases where rlib's end up depending on dylibs. I don't think pre-existing behavior is necessarily intuitive, but my main goal right now is to address missing use cases, not to try to figure out what the ideal behavior is for all cases and potentially inject breaking changes to support that idealized behavior. |
||
}; | ||
*slot = s; | ||
return true; | ||
} | ||
|
||
crate fn parse_src_file_hash( | ||
slot: &mut Option<SourceFileHashAlgorithm>, | ||
v: Option<&str>, | ||
|
@@ -962,7 +996,7 @@ options! { | |
"panic strategy to compile crate with"), | ||
passes: Vec<String> = (Vec::new(), parse_list, [TRACKED], | ||
"a list of extra LLVM passes to run (space separated)"), | ||
prefer_dynamic: bool = (false, parse_bool, [TRACKED], | ||
prefer_dynamic: PreferDynamicSet = (PreferDynamicSet::unset(), parse_prefer_dynamic, [TRACKED], | ||
"prefer dynamic linking to static linking (default: no)"), | ||
profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled, | ||
parse_switch_with_opt_path, [TRACKED], | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -402,6 +402,13 @@ linkage. This flag takes one of the following values: | |
|
||
* `y`, `yes`, `on`, or no value: use dynamic linking. | ||
* `n`, `no`, or `off`: use static linking (the default). | ||
* A comma-separated list of crate names `crate1,crate2,...`: prefer dynamic | ||
linking, but solely for the indicated crates. For example, to statically link | ||
everything except `std`, use `-C prefer-dynamic=std`. | ||
|
||
Note that the explicit list of crate names variant of this flag is gated behind | ||
`-Zprefer-dynamic-subset`; as a special case, one can enable the handling of | ||
the single crate `std` as shown in the example above via `-Zprefer-dynamic-std`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those options don't exist at least as of this commit. Edit: these are introduced in the next commit. |
||
|
||
## profile-generate | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should skip non-linkable crates like proc-macros and their dependencies I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay I'll look into that.