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_metadata/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_metadata/src')
| -rw-r--r-- | compiler/rustc_metadata/src/native_libs.rs | 122 | ||||
| -rw-r--r-- | compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 11 |
2 files changed, 104 insertions, 29 deletions
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 523e016eeb9..bc342119efb 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -8,8 +8,8 @@ use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; use rustc_session::utils::NativeLibKind; use rustc_session::Session; -use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::Span; use rustc_target::spec::abi::Abi; crate fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> { @@ -56,6 +56,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { cfg: None, foreign_module: Some(it.def_id.to_def_id()), wasm_import_module: None, + verbatim: None, }; let mut kind_specified = false; @@ -67,10 +68,18 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { None => continue, // skip like historical compilers }; lib.kind = match &*kind.as_str() { - "static" => NativeLibKind::StaticBundle, - "static-nobundle" => NativeLibKind::StaticNoBundle, - "dylib" => NativeLibKind::Dylib, - "framework" => NativeLibKind::Framework, + "static" => NativeLibKind::Static { bundle: None, whole_archive: None }, + "static-nobundle" => { + sess.struct_span_warn( + item.span(), + "library kind `static-nobundle` has been superseded by specifying \ + modifier `-bundle` with library kind `static`", + ) + .emit(); + NativeLibKind::Static { bundle: Some(false), whole_archive: None } + } + "dylib" => NativeLibKind::Dylib { as_needed: None }, + "framework" => NativeLibKind::Framework { as_needed: None }, "raw-dylib" => NativeLibKind::RawDylib, k => { struct_span_err!(sess, item.span(), E0458, "unknown kind: `{}`", k) @@ -108,6 +117,71 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { } } + // Do this outside the above loop so we don't depend on modifiers coming + // after kinds + if let Some(item) = items.iter().find(|item| item.has_name(sym::modifiers)) { + if let Some(modifiers) = item.value_str() { + let span = item.name_value_literal_span().unwrap(); + for modifier in modifiers.as_str().split(',') { + let (modifier, value) = match modifier.strip_prefix(&['+', '-'][..]) { + Some(m) => (m, modifier.starts_with('+')), + None => { + sess.span_err( + span, + "invalid linking modifier syntax, expected '+' or '-' prefix \ + before one of: bundle, verbatim, whole-archive, as-needed", + ); + continue; + } + }; + + match (modifier, &mut lib.kind) { + ("bundle", NativeLibKind::Static { bundle, .. }) => { + *bundle = Some(value); + } + ("bundle", _) => sess.span_err( + span, + "bundle linking modifier is only compatible with \ + `static` linking kind", + ), + + ("verbatim", _) => lib.verbatim = Some(value), + + ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => { + *whole_archive = Some(value); + } + ("whole-archive", _) => sess.span_err( + span, + "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", _) => sess.span_err( + span, + "as-needed linking modifier is only compatible with \ + `dylib` and `framework` linking kinds", + ), + + _ => sess.span_err( + span, + &format!( + "unrecognized linking modifier `{}`, expected one \ + of: bundle, verbatim, whole-archive, as-needed", + modifier + ), + ), + } + } + } else { + let msg = "must be of the form `#[link(modifiers = \"...\")]`"; + sess.span_err(item.span(), msg); + } + } + // In general we require #[link(name = "...")] but we allow // #[link(wasm_import_module = "...")] without the `name`. let requires_name = kind_specified || lib.wasm_import_module.is_none(); @@ -152,7 +226,7 @@ impl Collector<'tcx> { return; } let is_osx = self.tcx.sess.target.is_like_osx; - if lib.kind == NativeLibKind::Framework && !is_osx { + if matches!(lib.kind, NativeLibKind::Framework { .. }) && !is_osx { let msg = "native frameworks are only available on macOS targets"; match span { Some(span) => struct_span_err!(self.tcx.sess, span, E0455, "{}", msg).emit(), @@ -168,7 +242,9 @@ impl Collector<'tcx> { ) .emit(); } - if lib.kind == NativeLibKind::StaticNoBundle && !self.tcx.features().static_nobundle { + if matches!(lib.kind, NativeLibKind::Static { bundle: Some(false), .. }) + && !self.tcx.features().static_nobundle + { feature_err( &self.tcx.sess.parse_sess, sym::static_nobundle, @@ -193,30 +269,30 @@ impl Collector<'tcx> { fn process_command_line(&mut self) { // First, check for errors let mut renames = FxHashSet::default(); - for (name, new_name, _) in &self.tcx.sess.opts.libs { - if let Some(ref new_name) = new_name { + for lib in &self.tcx.sess.opts.libs { + if let Some(ref new_name) = lib.new_name { let any_duplicate = self .libs .iter() .filter_map(|lib| lib.name.as_ref()) - .any(|n| &n.as_str() == name); + .any(|n| &n.as_str() == &lib.name); if new_name.is_empty() { self.tcx.sess.err(&format!( "an empty renaming target was specified for library `{}`", - name + lib.name )); } else if !any_duplicate { self.tcx.sess.err(&format!( "renaming of the library `{}` was specified, \ however this crate contains no `#[link(...)]` \ attributes referencing this library.", - name + lib.name )); - } else if !renames.insert(name) { + } else if !renames.insert(&lib.name) { self.tcx.sess.err(&format!( "multiple renamings were \ specified for library `{}` .", - name + lib.name )); } } @@ -229,7 +305,7 @@ impl Collector<'tcx> { // it. (This ensures that the linker is able to see symbols from // all possible dependent libraries before linking in the library // in question.) - for &(ref name, ref new_name, kind) in &self.tcx.sess.opts.libs { + for passed_lib in &self.tcx.sess.opts.libs { // If we've already added any native libraries with the same // name, they will be pulled out into `existing`, so that we // can move them to the end of the list below. @@ -237,13 +313,14 @@ impl Collector<'tcx> { .libs .drain_filter(|lib| { if let Some(lib_name) = lib.name { - if lib_name.as_str() == *name { - if kind != NativeLibKind::Unspecified { - lib.kind = kind; + if lib_name.as_str() == passed_lib.name { + if passed_lib.kind != NativeLibKind::Unspecified { + lib.kind = passed_lib.kind; } - if let Some(new_name) = new_name { + if let Some(new_name) = &passed_lib.new_name { lib.name = Some(Symbol::intern(new_name)); } + lib.verbatim = passed_lib.verbatim; return true; } } @@ -252,13 +329,14 @@ impl Collector<'tcx> { .collect::<Vec<_>>(); if existing.is_empty() { // Add if not found - let new_name = new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str> + let new_name = passed_lib.new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str> let lib = NativeLib { - name: Some(Symbol::intern(new_name.unwrap_or(name))), - kind, + name: Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name))), + kind: passed_lib.kind, cfg: None, foreign_module: None, wasm_import_module: None, + verbatim: passed_lib.verbatim, }; self.register_native_lib(None, lib); } else { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 8595a70dd94..b11ad6c7ff8 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -256,16 +256,13 @@ pub fn provide(providers: &mut Providers) { // resolve! Does this work? Unsure! That's what the issue is about *providers = Providers { is_dllimport_foreign_item: |tcx, id| match tcx.native_library_kind(id) { - Some(NativeLibKind::Dylib | NativeLibKind::RawDylib | NativeLibKind::Unspecified) => { - true - } + Some( + NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified, + ) => true, _ => false, }, is_statically_included_foreign_item: |tcx, id| { - matches!( - tcx.native_library_kind(id), - Some(NativeLibKind::StaticBundle | NativeLibKind::StaticNoBundle) - ) + matches!(tcx.native_library_kind(id), Some(NativeLibKind::Static { .. })) }, native_library_kind: |tcx, id| { tcx.native_libraries(id.krate) |
