diff options
| author | Luqman Aden <me@luqman.ca> | 2021-03-24 21:45:09 -0700 |
|---|---|---|
| committer | Luqman Aden <me@luqman.ca> | 2021-05-05 16:04:25 -0700 |
| commit | db555e1284dd37f4f3c76474aabfca09140a7ab3 (patch) | |
| tree | 6e6e96a1c43ac0c193e3ab756bcfe8d4747c904c /compiler/rustc_session/src | |
| parent | bacf770f2983a52f31e3537db5f0fe1ef2eaa874 (diff) | |
| download | rust-db555e1284dd37f4f3c76474aabfca09140a7ab3.tar.gz rust-db555e1284dd37f4f3c76474aabfca09140a7ab3.zip | |
Implement RFC 2951: Native link modifiers
This commit implements both the native linking modifiers infrastructure as well as an initial attempt at the individual modifiers from the RFC. It also introduces a feature flag for the general syntax along with individual feature flags for each modifier.
Diffstat (limited to 'compiler/rustc_session/src')
| -rw-r--r-- | compiler/rustc_session/src/config.rs | 153 | ||||
| -rw-r--r-- | compiler/rustc_session/src/options.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_session/src/utils.rs | 33 |
3 files changed, 143 insertions, 47 deletions
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 08d6f4a46fe..6956b815f19 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -5,7 +5,7 @@ pub use crate::options::*; use crate::lint; use crate::search_paths::SearchPath; -use crate::utils::{CanonicalizedPath, NativeLibKind}; +use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; use crate::{early_error, early_warn, Session}; use rustc_data_structures::fx::FxHashSet; @@ -1027,8 +1027,11 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> { "", "Link the generated crate(s) to the specified native library NAME. The optional KIND can be one of - static, framework, or dylib (the default).", - "[KIND=]NAME", + static, framework, or dylib (the default). + Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed) + may be specified each with a prefix of either '+' to + enable or '-' to disable.", + "[KIND[:MODIFIERS]=]NAME[:RENAME]", ), make_crate_type_option(), opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"), @@ -1591,52 +1594,127 @@ fn select_debuginfo( } } -fn parse_libs( - matches: &getopts::Matches, +fn parse_native_lib_kind(kind: &str, error_format: ErrorOutputType) -> NativeLibKind { + match kind { + "dylib" => NativeLibKind::Dylib { as_needed: None }, + "framework" => NativeLibKind::Framework { as_needed: None }, + "static" => NativeLibKind::Static { bundle: None, whole_archive: None }, + "static-nobundle" => { + early_warn( + error_format, + "library kind `static-nobundle` has been superseded by specifying \ + `-bundle` on library kind `static`. Try `static:-bundle`", + ); + NativeLibKind::Static { bundle: Some(false), whole_archive: None } + } + s => early_error( + error_format, + &format!("unknown library kind `{}`, expected one of dylib, framework, or static", s), + ), + } +} + +fn parse_native_lib_modifiers( + is_nightly: bool, + mut kind: NativeLibKind, + modifiers: &str, error_format: ErrorOutputType, -) -> Vec<(String, Option<String>, NativeLibKind)> { +) -> (NativeLibKind, Option<bool>) { + let mut verbatim = None; + for modifier in modifiers.split(',') { + let (modifier, value) = match modifier.strip_prefix(&['+', '-'][..]) { + Some(m) => (m, modifier.starts_with('+')), + None => early_error( + error_format, + "invalid linking modifier syntax, expected '+' or '-' prefix \ + before one of: bundle, verbatim, whole-archive, as-needed", + ), + }; + + if !is_nightly { + early_error( + error_format, + "linking modifiers are currently unstable and only accepted on \ + the nightly compiler", + ); + } + + match (modifier, &mut kind) { + ("bundle", NativeLibKind::Static { bundle, .. }) => { + *bundle = Some(value); + } + ("bundle", _) => early_error( + error_format, + "bundle linking modifier is only compatible with \ + `static` linking kind", + ), + + ("verbatim", _) => verbatim = Some(value), + + ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => { + *whole_archive = Some(value); + } + ("whole-archive", _) => early_error( + error_format, + "whole-archive linking modifier is only compatible with \ + `static` linking kind", + ), + + ("as-needed", NativeLibKind::Dylib { as_needed }) + | ("as-needed", NativeLibKind::Framework { as_needed }) => { + *as_needed = Some(value); + } + ("as-needed", _) => early_error( + error_format, + "as-needed linking modifier is only compatible with \ + `dylib` and `framework` linking kinds", + ), + + _ => early_error( + error_format, + &format!( + "unrecognized linking modifier `{}`, expected one \ + of: bundle, verbatim, whole-archive, as-needed", + modifier + ), + ), + } + } + + (kind, verbatim) +} + +fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> { + let is_nightly = nightly_options::match_is_nightly_build(matches); matches .opt_strs("l") .into_iter() .map(|s| { - // Parse string of the form "[KIND=]lib[:new_name]", - // where KIND is one of "dylib", "framework", "static". - let (name, kind) = match s.split_once('=') { - None => (s, NativeLibKind::Unspecified), + // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]", + // where KIND is one of "dylib", "framework", "static" and + // where MODIFIERS are a comma separated list of supported modifiers + // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed + // with either + or - to indicate whether it is enabled or disabled. + // The last value specified for a given modifier wins. + let (name, kind, verbatim) = match s.split_once('=') { + None => (s, NativeLibKind::Unspecified, None), Some((kind, name)) => { - let kind = match kind { - "dylib" => NativeLibKind::Dylib, - "framework" => NativeLibKind::Framework, - "static" => NativeLibKind::StaticBundle, - "static-nobundle" => NativeLibKind::StaticNoBundle, - s => { - early_error( - error_format, - &format!( - "unknown library kind `{}`, expected \ - one of dylib, framework, or static", - s - ), - ); + let (kind, verbatim) = match kind.split_once(':') { + None => (parse_native_lib_kind(kind, error_format), None), + Some((kind, modifiers)) => { + let kind = parse_native_lib_kind(kind, error_format); + parse_native_lib_modifiers(is_nightly, kind, modifiers, error_format) } }; - (name.to_string(), kind) + (name.to_string(), kind, verbatim) } }; - if kind == NativeLibKind::StaticNoBundle - && !nightly_options::match_is_nightly_build(matches) - { - early_error( - error_format, - "the library kind 'static-nobundle' is only \ - accepted on the nightly compiler", - ); - } + let (name, new_name) = match name.split_once(':') { None => (name, None), Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())), }; - (name, new_name, kind) + NativeLib { name, new_name, kind, verbatim } }) .collect() } @@ -2316,7 +2394,7 @@ crate mod dep_tracking { }; use crate::lint; use crate::options::WasiExecModel; - use crate::utils::NativeLibKind; + use crate::utils::{NativeLib, NativeLibKind}; use rustc_feature::UnstableFeatures; use rustc_span::edition::Edition; use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel}; @@ -2391,6 +2469,7 @@ crate mod dep_tracking { DebugInfo, UnstableFeatures, OutputTypes, + NativeLib, NativeLibKind, SanitizerSet, CFGuard, @@ -2409,8 +2488,8 @@ crate mod dep_tracking { PathBuf, (PathBuf, PathBuf), CrateType, + NativeLib, (String, lint::Level), - (String, Option<String>, NativeLibKind), (String, u64) ); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index cd28517bfbc..7799dfd1978 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -3,7 +3,7 @@ use crate::config::*; use crate::early_error; use crate::lint; use crate::search_paths::SearchPath; -use crate::utils::NativeLibKind; +use crate::utils::NativeLib; use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet}; use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, TlsModel}; @@ -133,7 +133,7 @@ top_level_options!( describe_lints: bool [UNTRACKED], output_types: OutputTypes [TRACKED], search_paths: Vec<SearchPath> [UNTRACKED], - libs: Vec<(String, Option<String>, NativeLibKind)> [TRACKED], + libs: Vec<NativeLib> [TRACKED], maybe_sysroot: Option<PathBuf> [UNTRACKED], target_triple: TargetTriple [TRACKED], diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index e9d597d1ba6..1a044e677a0 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -19,25 +19,42 @@ impl Session { #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] pub enum NativeLibKind { - /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) included - /// when linking a final binary, but not when archiving an rlib. - StaticNoBundle, - /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) included - /// when linking a final binary, but also included when archiving an rlib. - StaticBundle, + /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) + Static { + /// Whether to bundle objects from static library into produced rlib + bundle: Option<bool>, + /// Whether to link static library without throwing any object files away + whole_archive: Option<bool>, + }, /// Dynamic library (e.g. `libfoo.so` on Linux) /// or an import library corresponding to a dynamic library (e.g. `foo.lib` on Windows/MSVC). - Dylib, + Dylib { + /// Whether the dynamic library will be linked only if it satifies some undefined symbols + as_needed: Option<bool>, + }, /// Dynamic library (e.g. `foo.dll` on Windows) without a corresponding import library. RawDylib, /// A macOS-specific kind of dynamic libraries. - Framework, + Framework { + /// Whether the framework will be linked only if it satifies some undefined symbols + as_needed: Option<bool>, + }, /// The library kind wasn't specified, `Dylib` is currently used as a default. Unspecified, } rustc_data_structures::impl_stable_hash_via_hash!(NativeLibKind); +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] +pub struct NativeLib { + pub name: String, + pub new_name: Option<String>, + pub kind: NativeLibKind, + pub verbatim: Option<bool>, +} + +rustc_data_structures::impl_stable_hash_via_hash!(NativeLib); + /// A path that has been canonicalized along with its original, non-canonicalized form #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct CanonicalizedPath { |
