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.
This commit is contained in:
Luqman Aden 2021-03-24 21:45:09 -07:00
parent bacf770f29
commit db555e1284
38 changed files with 829 additions and 170 deletions

View File

@ -326,6 +326,45 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
);
}
}
// Check for unstable modifiers on `#[link(..)]` attribute
if self.sess.check_name(attr, sym::link) {
for nested_meta in attr.meta_item_list().unwrap_or_default() {
if nested_meta.has_name(sym::modifiers) {
gate_feature_post!(
self,
native_link_modifiers,
nested_meta.span(),
"native link modifiers are experimental"
);
if let Some(modifiers) = nested_meta.value_str() {
for modifier in modifiers.as_str().split(',') {
if let Some(modifier) = modifier.strip_prefix(&['+', '-'][..]) {
macro_rules! gate_modifier { ($($name:literal => $feature:ident)*) => {
$(if modifier == $name {
let msg = concat!("`#[link(modifiers=\"", $name, "\")]` is unstable");
gate_feature_post!(
self,
$feature,
nested_meta.name_value_literal_span().unwrap(),
msg
);
})*
}}
gate_modifier!(
"bundle" => native_link_modifiers_bundle
"verbatim" => native_link_modifiers_verbatim
"whole-archive" => native_link_modifiers_whole_archive
"as-needed" => native_link_modifiers_as_needed
);
}
}
}
}
}
}
}
fn visit_item(&mut self, i: &'a ast::Item) {

View File

@ -85,8 +85,8 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
));
}
fn add_native_library(&mut self, name: rustc_span::symbol::Symbol) {
let location = find_library(name, &self.lib_search_paths, self.sess);
fn add_native_library(&mut self, name: rustc_span::symbol::Symbol, verbatim: bool) {
let location = find_library(name, verbatim, &self.lib_search_paths, self.sess);
self.add_archive(location.clone(), |_| false).unwrap_or_else(|e| {
panic!("failed to add native library {}: {}", location.to_string_lossy(), e);
});

View File

@ -100,8 +100,9 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
/// Adds all of the contents of a native library to this archive. This will
/// search in the relevant locations for a library named `name`.
fn add_native_library(&mut self, name: Symbol) {
let location = find_library(name, &self.config.lib_search_paths, self.config.sess);
fn add_native_library(&mut self, name: Symbol, verbatim: bool) {
let location =
find_library(name, verbatim, &self.config.lib_search_paths, self.config.sess);
self.add_archive(&location, |_| false).unwrap_or_else(|e| {
self.config.sess.fatal(&format!(
"failed to add native library {}: {}",

View File

@ -4,11 +4,19 @@ use rustc_span::symbol::Symbol;
use std::io;
use std::path::{Path, PathBuf};
pub fn find_library(name: Symbol, search_paths: &[PathBuf], sess: &Session) -> PathBuf {
pub fn find_library(
name: Symbol,
verbatim: bool,
search_paths: &[PathBuf],
sess: &Session,
) -> PathBuf {
// On Windows, static libraries sometimes show up as libfoo.a and other
// times show up as foo.lib
let oslibname =
format!("{}{}{}", sess.target.staticlib_prefix, name, sess.target.staticlib_suffix);
let oslibname = if verbatim {
name.to_string()
} else {
format!("{}{}{}", sess.target.staticlib_prefix, name, sess.target.staticlib_suffix)
};
let unixlibname = format!("lib{}.a", name);
for path in search_paths {
@ -45,7 +53,7 @@ pub trait ArchiveBuilder<'a> {
lto: bool,
skip_objects: bool,
) -> io::Result<()>;
fn add_native_library(&mut self, name: Symbol);
fn add_native_library(&mut self, name: Symbol, verbatim: bool);
fn update_symbols(&mut self);
fn build(self);

View File

@ -329,15 +329,15 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
// metadata of the rlib we're generating somehow.
for lib in codegen_results.crate_info.used_libraries.iter() {
match lib.kind {
NativeLibKind::StaticBundle => {}
NativeLibKind::StaticNoBundle
| NativeLibKind::Dylib
| NativeLibKind::Framework
NativeLibKind::Static { bundle: None | Some(true), .. } => {}
NativeLibKind::Static { bundle: Some(false), .. }
| NativeLibKind::Dylib { .. }
| NativeLibKind::Framework { .. }
| NativeLibKind::RawDylib
| NativeLibKind::Unspecified => continue,
}
if let Some(name) = lib.name {
ab.add_native_library(name);
ab.add_native_library(name, lib.verbatim.unwrap_or(false));
}
}
@ -430,9 +430,10 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>(
// Clearly this is not sufficient for a general purpose feature, and
// we'd want to read from the library's metadata to determine which
// object files come from where and selectively skip them.
let skip_object_files = native_libs
.iter()
.any(|lib| lib.kind == NativeLibKind::StaticBundle && !relevant_lib(sess, lib));
let skip_object_files = native_libs.iter().any(|lib| {
matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
&& !relevant_lib(sess, lib)
});
ab.add_rlib(
path,
&name.as_str(),
@ -931,7 +932,7 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
let path = find_sanitizer_runtime(&sess, &filename);
let rpath = path.to_str().expect("non-utf8 component in path");
linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
linker.link_dylib(Symbol::intern(&filename));
linker.link_dylib(Symbol::intern(&filename), false, true);
} else {
let filename = format!("librustc{}_rt.{}.a", channel, name);
let path = find_sanitizer_runtime(&sess, &filename).join(&filename);
@ -1080,21 +1081,25 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
.filter_map(|lib| {
let name = lib.name?;
match lib.kind {
NativeLibKind::StaticNoBundle
| NativeLibKind::Dylib
NativeLibKind::Static { bundle: Some(false), .. }
| NativeLibKind::Dylib { .. }
| NativeLibKind::Unspecified => {
let verbatim = lib.verbatim.unwrap_or(false);
if sess.target.is_like_msvc {
Some(format!("{}.lib", name))
Some(format!("{}{}", name, if verbatim { "" } else { ".lib" }))
} else if sess.target.linker_is_gnu {
Some(format!("-l{}{}", if verbatim { ":" } else { "" }, name))
} else {
Some(format!("-l{}", name))
}
}
NativeLibKind::Framework => {
NativeLibKind::Framework { .. } => {
// ld-only syntax, since there are no frameworks in MSVC
Some(format!("-framework {}", name))
}
// These are included, no need to print them
NativeLibKind::StaticBundle | NativeLibKind::RawDylib => None,
NativeLibKind::Static { bundle: None | Some(true), .. }
| NativeLibKind::RawDylib => None,
}
})
.collect();
@ -1812,11 +1817,20 @@ fn add_local_native_libraries(
Some(l) => l,
None => continue,
};
let verbatim = lib.verbatim.unwrap_or(false);
match lib.kind {
NativeLibKind::Dylib | NativeLibKind::Unspecified => cmd.link_dylib(name),
NativeLibKind::Framework => cmd.link_framework(name),
NativeLibKind::StaticNoBundle => cmd.link_staticlib(name),
NativeLibKind::StaticBundle => cmd.link_whole_staticlib(name, &search_path),
NativeLibKind::Dylib { as_needed } => {
cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true))
}
NativeLibKind::Unspecified => cmd.link_dylib(name, verbatim, true),
NativeLibKind::Framework { as_needed } => {
cmd.link_framework(name, as_needed.unwrap_or(true))
}
NativeLibKind::Static { bundle: None | Some(true), .. }
| NativeLibKind::Static { whole_archive: Some(true), .. } => {
cmd.link_whole_staticlib(name, verbatim, &search_path);
}
NativeLibKind::Static { .. } => cmd.link_staticlib(name, verbatim),
NativeLibKind::RawDylib => {
// FIXME(#58713): Proper handling for raw dylibs.
bug!("raw_dylib feature not yet implemented");
@ -2000,9 +2014,10 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
// there's a static library that's not relevant we skip all object
// files.
let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
let skip_native = native_libs
.iter()
.any(|lib| lib.kind == NativeLibKind::StaticBundle && !relevant_lib(sess, lib));
let skip_native = native_libs.iter().any(|lib| {
matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
&& !relevant_lib(sess, lib)
});
if (!are_upstream_rust_objects_already_included(sess)
|| ignored_for_lto(sess, &codegen_results.crate_info, cnum))
@ -2144,22 +2159,28 @@ fn add_upstream_native_libraries(
if !relevant_lib(sess, &lib) {
continue;
}
let verbatim = lib.verbatim.unwrap_or(false);
match lib.kind {
NativeLibKind::Dylib | NativeLibKind::Unspecified => cmd.link_dylib(name),
NativeLibKind::Framework => cmd.link_framework(name),
NativeLibKind::StaticNoBundle => {
NativeLibKind::Dylib { as_needed } => {
cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true))
}
NativeLibKind::Unspecified => cmd.link_dylib(name, verbatim, true),
NativeLibKind::Framework { as_needed } => {
cmd.link_framework(name, as_needed.unwrap_or(true))
}
NativeLibKind::Static { bundle: Some(false), .. } => {
// Link "static-nobundle" native libs only if the crate they originate from
// is being linked statically to the current crate. If it's linked dynamically
// or is an rlib already included via some other dylib crate, the symbols from
// native libs will have already been included in that dylib.
if data[cnum.as_usize() - 1] == Linkage::Static {
cmd.link_staticlib(name)
cmd.link_staticlib(name, verbatim)
}
}
// ignore statically included native libraries here as we've
// already included them when we included the rust library
// previously
NativeLibKind::StaticBundle => {}
NativeLibKind::Static { bundle: None | Some(true), .. } => {}
NativeLibKind::RawDylib => {
// FIXME(#58713): Proper handling for raw dylibs.
bug!("raw_dylib feature not yet implemented");

View File

@ -103,18 +103,19 @@ impl LinkerInfo {
pub trait Linker {
fn cmd(&mut self) -> &mut Command;
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
fn link_dylib(&mut self, lib: Symbol);
fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool);
fn link_rust_dylib(&mut self, lib: Symbol, path: &Path);
fn link_framework(&mut self, framework: Symbol);
fn link_staticlib(&mut self, lib: Symbol);
fn link_framework(&mut self, framework: Symbol, as_needed: bool);
fn link_staticlib(&mut self, lib: Symbol, verbatim: bool);
fn link_rlib(&mut self, lib: &Path);
fn link_whole_rlib(&mut self, lib: &Path);
fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]);
fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]);
fn include_path(&mut self, path: &Path);
fn framework_path(&mut self, path: &Path);
fn output_filename(&mut self, path: &Path);
fn add_object(&mut self, path: &Path);
fn gc_sections(&mut self, keep_metadata: bool);
fn no_gc_sections(&mut self);
fn full_relro(&mut self);
fn partial_relro(&mut self);
fn no_relro(&mut self);
@ -338,13 +339,32 @@ impl<'a> Linker for GccLinker<'a> {
}
}
fn link_dylib(&mut self, lib: Symbol) {
fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool) {
if !as_needed {
if self.sess.target.is_like_osx {
// FIXME(81490): ld64 doesn't support these flags but macOS 11
// has -needed-l{} / -needed_library {}
// but we have no way to detect that here.
self.sess.warn("`as-needed` modifier not implemented yet for ld64");
} else if self.sess.target.linker_is_gnu {
self.linker_arg("--no-as-needed");
} else {
self.sess.warn("`as-needed` modifier not supported for current linker");
}
}
self.hint_dynamic();
self.cmd.arg(format!("-l{}", lib));
self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib));
if !as_needed {
if self.sess.target.is_like_osx {
// See above FIXME comment
} else if self.sess.target.linker_is_gnu {
self.linker_arg("--as-needed");
}
}
}
fn link_staticlib(&mut self, lib: Symbol) {
fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) {
self.hint_static();
self.cmd.arg(format!("-l{}", lib));
self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib));
}
fn link_rlib(&mut self, lib: &Path) {
self.hint_static();
@ -378,8 +398,14 @@ impl<'a> Linker for GccLinker<'a> {
self.cmd.arg(format!("-l{}", lib));
}
fn link_framework(&mut self, framework: Symbol) {
fn link_framework(&mut self, framework: Symbol, as_needed: bool) {
self.hint_dynamic();
if !as_needed {
// FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
// flag but we have no way to detect that here.
// self.cmd.arg("-needed_framework").sym_arg(framework);
self.sess.warn("`as-needed` modifier not implemented yet for ld64");
}
self.cmd.arg("-framework").sym_arg(framework);
}
@ -389,17 +415,21 @@ impl<'a> Linker for GccLinker<'a> {
// don't otherwise explicitly reference them. This can occur for
// libraries which are just providing bindings, libraries with generic
// functions, etc.
fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]) {
fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]) {
self.hint_static();
let target = &self.sess.target;
if !target.is_like_osx {
self.linker_arg("--whole-archive").cmd.arg(format!("-l{}", lib));
self.linker_arg("--whole-archive").cmd.arg(format!(
"-l{}{}",
if verbatim { ":" } else { "" },
lib
));
self.linker_arg("--no-whole-archive");
} else {
// -force_load is the macOS equivalent of --whole-archive, but it
// involves passing the full path to the library to link.
self.linker_arg("-force_load");
let lib = archive::find_library(lib, search_path, &self.sess);
let lib = archive::find_library(lib, verbatim, search_path, &self.sess);
self.linker_arg(&lib);
}
}
@ -445,6 +475,16 @@ impl<'a> Linker for GccLinker<'a> {
}
}
fn no_gc_sections(&mut self) {
if self.sess.target.is_like_osx {
self.linker_arg("-no_dead_strip");
} else if self.sess.target.is_like_solaris {
self.linker_arg("-zrecord");
} else {
self.linker_arg("--no-gc-sections");
}
}
fn optimize(&mut self) {
if !self.sess.target.linker_is_gnu {
return;
@ -708,8 +748,12 @@ impl<'a> Linker for MsvcLinker<'a> {
}
}
fn link_dylib(&mut self, lib: Symbol) {
self.cmd.arg(&format!("{}.lib", lib));
fn no_gc_sections(&mut self) {
self.cmd.arg("/OPT:NOREF,NOICF");
}
fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) {
self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
}
fn link_rust_dylib(&mut self, lib: Symbol, path: &Path) {
@ -723,8 +767,8 @@ impl<'a> Linker for MsvcLinker<'a> {
}
}
fn link_staticlib(&mut self, lib: Symbol) {
self.cmd.arg(&format!("{}.lib", lib));
fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) {
self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
}
fn full_relro(&mut self) {
@ -762,13 +806,13 @@ impl<'a> Linker for MsvcLinker<'a> {
fn framework_path(&mut self, _path: &Path) {
bug!("frameworks are not supported on windows")
}
fn link_framework(&mut self, _framework: Symbol) {
fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
bug!("frameworks are not supported on windows")
}
fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
self.link_staticlib(lib);
self.cmd.arg(format!("/WHOLEARCHIVE:{}.lib", lib));
fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) {
self.link_staticlib(lib, verbatim);
self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" }));
}
fn link_whole_rlib(&mut self, path: &Path) {
self.link_rlib(path);
@ -917,7 +961,7 @@ impl<'a> Linker for EmLinker<'a> {
self.cmd.arg("-L").arg(path);
}
fn link_staticlib(&mut self, lib: Symbol) {
fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
self.cmd.arg("-l").sym_arg(lib);
}
@ -929,14 +973,14 @@ impl<'a> Linker for EmLinker<'a> {
self.cmd.arg(path);
}
fn link_dylib(&mut self, lib: Symbol) {
fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) {
// Emscripten always links statically
self.link_staticlib(lib);
self.link_staticlib(lib, verbatim);
}
fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) {
// not supported?
self.link_staticlib(lib);
self.link_staticlib(lib, verbatim);
}
fn link_whole_rlib(&mut self, lib: &Path) {
@ -945,7 +989,7 @@ impl<'a> Linker for EmLinker<'a> {
}
fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
self.link_dylib(lib);
self.link_dylib(lib, false, true);
}
fn link_rlib(&mut self, lib: &Path) {
@ -968,7 +1012,7 @@ impl<'a> Linker for EmLinker<'a> {
bug!("frameworks are not supported on Emscripten")
}
fn link_framework(&mut self, _framework: Symbol) {
fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
bug!("frameworks are not supported on Emscripten")
}
@ -976,6 +1020,10 @@ impl<'a> Linker for EmLinker<'a> {
// noop
}
fn no_gc_sections(&mut self) {
// noop
}
fn optimize(&mut self) {
// Emscripten performs own optimizations
self.cmd.arg(match self.sess.opts.optimize {
@ -1119,11 +1167,11 @@ impl<'a> Linker for WasmLd<'a> {
}
}
fn link_dylib(&mut self, lib: Symbol) {
fn link_dylib(&mut self, lib: Symbol, _verbatim: bool, _as_needed: bool) {
self.cmd.arg("-l").sym_arg(lib);
}
fn link_staticlib(&mut self, lib: Symbol) {
fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
self.cmd.arg("-l").sym_arg(lib);
}
@ -1157,11 +1205,11 @@ impl<'a> Linker for WasmLd<'a> {
self.cmd.arg("-l").sym_arg(lib);
}
fn link_framework(&mut self, _framework: Symbol) {
fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
panic!("frameworks not supported")
}
fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
self.cmd.arg("-l").sym_arg(lib);
}
@ -1173,6 +1221,10 @@ impl<'a> Linker for WasmLd<'a> {
self.cmd.arg("--gc-sections");
}
fn no_gc_sections(&mut self) {
self.cmd.arg("--no-gc-sections");
}
fn optimize(&mut self) {
self.cmd.arg(match self.sess.opts.optimize {
OptLevel::No => "-O0",
@ -1327,7 +1379,7 @@ impl<'a> Linker for PtxLinker<'a> {
});
}
fn link_dylib(&mut self, _lib: Symbol) {
fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
panic!("external dylibs not supported")
}
@ -1335,11 +1387,11 @@ impl<'a> Linker for PtxLinker<'a> {
panic!("external dylibs not supported")
}
fn link_staticlib(&mut self, _lib: Symbol) {
fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) {
panic!("staticlibs not supported")
}
fn link_whole_staticlib(&mut self, _lib: Symbol, _search_path: &[PathBuf]) {
fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
panic!("staticlibs not supported")
}
@ -1347,7 +1399,7 @@ impl<'a> Linker for PtxLinker<'a> {
panic!("frameworks not supported")
}
fn link_framework(&mut self, _framework: Symbol) {
fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
panic!("frameworks not supported")
}
@ -1359,6 +1411,8 @@ impl<'a> Linker for PtxLinker<'a> {
fn gc_sections(&mut self, _keep_metadata: bool) {}
fn no_gc_sections(&mut self) {}
fn pgo_gen(&mut self) {}
fn no_crt_objects(&mut self) {}

View File

@ -114,11 +114,12 @@ pub struct NativeLib {
pub kind: NativeLibKind,
pub name: Option<Symbol>,
pub cfg: Option<ast::MetaItem>,
pub verbatim: Option<bool>,
}
impl From<&cstore::NativeLib> for NativeLib {
fn from(lib: &cstore::NativeLib) -> Self {
NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone() }
NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone(), verbatim: lib.verbatim }
}
}

View File

@ -656,6 +656,21 @@ declare_features! (
/// Allows using imported `main` function
(active, imported_main, "1.53.0", Some(28937), None),
/// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]`
(active, native_link_modifiers, "1.53.0", Some(81490), None),
/// Allows specifying the bundle link modifier
(active, native_link_modifiers_bundle, "1.53.0", Some(81490), None),
/// Allows specifying the verbatim link modifier
(active, native_link_modifiers_verbatim, "1.53.0", Some(81490), None),
/// Allows specifying the whole-archive link modifier
(active, native_link_modifiers_whole_archive, "1.53.0", Some(81490), None),
/// Allows specifying the as-needed link modifier
(active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None),
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
@ -683,6 +698,11 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
sym::const_generics_defaults,
sym::inherent_associated_types,
sym::type_alias_impl_trait,
sym::native_link_modifiers,
sym::native_link_modifiers_bundle,
sym::native_link_modifiers_verbatim,
sym::native_link_modifiers_whole_archive,
sym::native_link_modifiers_as_needed,
];
/// Some features are not allowed to be used together at the same time, if

View File

@ -12,7 +12,7 @@ use rustc_session::config::{
};
use rustc_session::lint::Level;
use rustc_session::search_paths::SearchPath;
use rustc_session::utils::{CanonicalizedPath, NativeLibKind};
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
use rustc_session::{build_session, getopts, DiagnosticOutput, Session};
use rustc_span::edition::{Edition, DEFAULT_EDITION};
use rustc_span::symbol::sym;
@ -303,38 +303,122 @@ fn test_native_libs_tracking_hash_different_values() {
let mut v2 = Options::default();
let mut v3 = Options::default();
let mut v4 = Options::default();
let mut v5 = Options::default();
// Reference
v1.libs = vec![
(String::from("a"), None, NativeLibKind::StaticBundle),
(String::from("b"), None, NativeLibKind::Framework),
(String::from("c"), None, NativeLibKind::Unspecified),
NativeLib {
name: String::from("a"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
verbatim: None,
},
NativeLib {
name: String::from("b"),
new_name: None,
kind: NativeLibKind::Framework { as_needed: None },
verbatim: None,
},
NativeLib {
name: String::from("c"),
new_name: None,
kind: NativeLibKind::Unspecified,
verbatim: None,
},
];
// Change label
v2.libs = vec![
(String::from("a"), None, NativeLibKind::StaticBundle),
(String::from("X"), None, NativeLibKind::Framework),
(String::from("c"), None, NativeLibKind::Unspecified),
NativeLib {
name: String::from("a"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
verbatim: None,
},
NativeLib {
name: String::from("X"),
new_name: None,
kind: NativeLibKind::Framework { as_needed: None },
verbatim: None,
},
NativeLib {
name: String::from("c"),
new_name: None,
kind: NativeLibKind::Unspecified,
verbatim: None,
},
];
// Change kind
v3.libs = vec![
(String::from("a"), None, NativeLibKind::StaticBundle),
(String::from("b"), None, NativeLibKind::StaticBundle),
(String::from("c"), None, NativeLibKind::Unspecified),
NativeLib {
name: String::from("a"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
verbatim: None,
},
NativeLib {
name: String::from("b"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
verbatim: None,
},
NativeLib {
name: String::from("c"),
new_name: None,
kind: NativeLibKind::Unspecified,
verbatim: None,
},
];
// Change new-name
v4.libs = vec![
(String::from("a"), None, NativeLibKind::StaticBundle),
(String::from("b"), Some(String::from("X")), NativeLibKind::Framework),
(String::from("c"), None, NativeLibKind::Unspecified),
NativeLib {
name: String::from("a"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
verbatim: None,
},
NativeLib {
name: String::from("b"),
new_name: Some(String::from("X")),
kind: NativeLibKind::Framework { as_needed: None },
verbatim: None,
},
NativeLib {
name: String::from("c"),
new_name: None,
kind: NativeLibKind::Unspecified,
verbatim: None,
},
];
// Change verbatim
v5.libs = vec![
NativeLib {
name: String::from("a"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
verbatim: None,
},
NativeLib {
name: String::from("b"),
new_name: None,
kind: NativeLibKind::Framework { as_needed: None },
verbatim: Some(true),
},
NativeLib {
name: String::from("c"),
new_name: None,
kind: NativeLibKind::Unspecified,
verbatim: None,
},
];
assert_different_hash(&v1, &v2);
assert_different_hash(&v1, &v3);
assert_different_hash(&v1, &v4);
assert_different_hash(&v1, &v5);
}
#[test]
@ -345,21 +429,66 @@ fn test_native_libs_tracking_hash_different_order() {
// Reference
v1.libs = vec![
(String::from("a"), None, NativeLibKind::StaticBundle),
(String::from("b"), None, NativeLibKind::Framework),
(String::from("c"), None, NativeLibKind::Unspecified),
NativeLib {
name: String::from("a"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
verbatim: None,
},
NativeLib {
name: String::from("b"),
new_name: None,
kind: NativeLibKind::Framework { as_needed: None },
verbatim: None,
},
NativeLib {
name: String::from("c"),
new_name: None,
kind: NativeLibKind::Unspecified,
verbatim: None,
},
];
v2.libs = vec![
(String::from("b"), None, NativeLibKind::Framework),
(String::from("a"), None, NativeLibKind::StaticBundle),
(String::from("c"), None, NativeLibKind::Unspecified),
NativeLib {
name: String::from("b"),
new_name: None,
kind: NativeLibKind::Framework { as_needed: None },
verbatim: None,
},
NativeLib {
name: String::from("a"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
verbatim: None,
},
NativeLib {
name: String::from("c"),
new_name: None,
kind: NativeLibKind::Unspecified,
verbatim: None,
},
];
v3.libs = vec![
(String::from("c"), None, NativeLibKind::Unspecified),
(String::from("a"), None, NativeLibKind::StaticBundle),
(String::from("b"), None, NativeLibKind::Framework),
NativeLib {
name: String::from("c"),
new_name: None,
kind: NativeLibKind::Unspecified,
verbatim: None,
},
NativeLib {
name: String::from("a"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
verbatim: None,
},
NativeLib {
name: String::from("b"),
new_name: None,
kind: NativeLibKind::Framework { as_needed: None },
verbatim: None,
},
];
assert_same_hash(&v1, &v2);

View File

@ -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 {

View File

@ -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)

View File

@ -94,6 +94,7 @@ pub struct NativeLib {
pub cfg: Option<ast::MetaItem>,
pub foreign_module: Option<DefId>,
pub wasm_import_module: Option<Symbol>,
pub verbatim: Option<bool>,
}
#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]

View File

@ -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)
);

View File

@ -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],

View File

@ -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 {

View File

@ -748,6 +748,7 @@ symbols! {
minnumf64,
mips_target_feature,
misc,
modifiers,
module,
module_path,
more_struct_aliases,
@ -763,6 +764,11 @@ symbols! {
naked,
naked_functions,
name,
native_link_modifiers,
native_link_modifiers_as_needed,
native_link_modifiers_bundle,
native_link_modifiers_verbatim,
native_link_modifiers_whole_archive,
ne,
nearbyintf32,
nearbyintf64,

View File

@ -0,0 +1,18 @@
# `native_link_modifiers_as_needed`
The tracking issue for this feature is: [#81490]
[#81490]: https://github.com/rust-lang/rust/issues/81490
------------------------
The `native_link_modifiers_as_needed` feature allows you to use the `as-needed` modifier.
`as-needed` is only compatible with the `dynamic` and `framework` linking kinds. Using any other kind will result in a compiler error.
`+as-needed` means that the library will be actually linked only if it satisfies some undefined symbols at the point at which it is specified on the command line, making it similar to static libraries in this regard.
This modifier translates to `--as-needed` for ld-like linkers, and to `-dead_strip_dylibs` / `-needed_library` / `-needed_framework` for ld64.
The modifier does nothing for linkers that don't support it (e.g. `link.exe`).
The default for this modifier is unclear, some targets currently specify it as `+as-needed`, some do not. We may want to try making `+as-needed` a default for all targets.

View File

@ -0,0 +1,19 @@
# `native_link_modifiers_bundle`
The tracking issue for this feature is: [#81490]
[#81490]: https://github.com/rust-lang/rust/issues/81490
------------------------
The `native_link_modifiers_bundle` feature allows you to use the `bundle` modifier.
Only compatible with the `static` linking kind. Using any other kind will result in a compiler error.
`+bundle` means objects from the static library are bundled into the produced crate (a rlib, for example) and are used from this crate later during linking of the final binary.
`-bundle` means the static library is included into the produced rlib "by name" and object files from it are included only during linking of the final binary, the file search by that name is also performed during final linking.
This modifier is supposed to supersede the `static-nobundle` linking kind defined by [RFC 1717](https://github.com/rust-lang/rfcs/pull/1717).
The default for this modifier is currently `+bundle`, but it could be changed later on some future edition boundary.

View File

@ -0,0 +1,20 @@
# `native_link_modifiers_verbatim`
The tracking issue for this feature is: [#81490]
[#81490]: https://github.com/rust-lang/rust/issues/81490
------------------------
The `native_link_modifiers_verbatim` feature allows you to use the `verbatim` modifier.
`+verbatim` means that rustc itself won't add any target-specified library prefixes or suffixes (like `lib` or `.a`) to the library name, and will try its best to ask for the same thing from the linker.
For `ld`-like linkers rustc will use the `-l:filename` syntax (note the colon) when passing the library, so the linker won't add any prefixes or suffixes as well.
See [`-l namespec`](https://sourceware.org/binutils/docs/ld/Options.html) in ld documentation for more details.
For linkers not supporting any verbatim modifiers (e.g. `link.exe` or `ld64`) the library name will be passed as is.
The default for this modifier is `-verbatim`.
This RFC changes the behavior of `raw-dylib` linking kind specified by [RFC 2627](https://github.com/rust-lang/rfcs/pull/2627). The `.dll` suffix (or other target-specified suffixes for other targets) is now added automatically.
If your DLL doesn't have the `.dll` suffix, it can be specified with `+verbatim`.

View File

@ -0,0 +1,18 @@
# `native_link_modifiers_whole_archive`
The tracking issue for this feature is: [#81490]
[#81490]: https://github.com/rust-lang/rust/issues/81490
------------------------
The `native_link_modifiers_whole_archive` feature allows you to use the `whole-archive` modifier.
Only compatible with the `static` linking kind. Using any other kind will result in a compiler error.
`+whole-archive` means that the static library is linked as a whole archive without throwing any object files away.
This modifier translates to `--whole-archive` for `ld`-like linkers, to `/WHOLEARCHIVE` for `link.exe`, and to `-force_load` for `ld64`.
The modifier does nothing for linkers that don't support it.
The default for this modifier is `-whole-archive`.

View File

@ -0,0 +1,11 @@
# `native_link_modifiers`
The tracking issue for this feature is: [#81490]
[#81490]: https://github.com/rust-lang/rust/issues/81490
------------------------
The `native_link_modifiers` feature allows you to use the `modifiers` syntax with the `#[link(..)]` attribute.
Modifiers are specified as a comma-delimited string with each modifier prefixed with either a `+` or `-` to indicate that the modifier is enabled or disabled, respectively. The last boolean value specified for a given modifier wins.

View File

@ -0,0 +1,5 @@
#[link(name = "foo", modifiers = "")]
//~^ ERROR: native link modifiers are experimental
extern "C" {}
fn main() {}

View File

@ -0,0 +1,12 @@
error[E0658]: native link modifiers are experimental
--> $DIR/feature-gate-native_link_modifiers.rs:1:22
|
LL | #[link(name = "foo", modifiers = "")]
| ^^^^^^^^^^^^^^
|
= note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
= help: add `#![feature(native_link_modifiers)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View File

@ -0,0 +1,8 @@
#![allow(incomplete_features)]
#![feature(native_link_modifiers)]
#[link(name = "foo", modifiers = "+as-needed")]
//~^ ERROR: `#[link(modifiers="as-needed")]` is unstable
extern "C" {}
fn main() {}

View File

@ -0,0 +1,12 @@
error[E0658]: `#[link(modifiers="as-needed")]` is unstable
--> $DIR/feature-gate-native_link_modifiers_as_needed.rs:4:34
|
LL | #[link(name = "foo", modifiers = "+as-needed")]
| ^^^^^^^^^^^^
|
= note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
= help: add `#![feature(native_link_modifiers_as_needed)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View File

@ -0,0 +1,8 @@
#![allow(incomplete_features)]
#![feature(native_link_modifiers)]
#[link(name = "foo", modifiers = "+bundle")]
//~^ ERROR: `#[link(modifiers="bundle")]` is unstable
extern "C" {}
fn main() {}

View File

@ -0,0 +1,12 @@
error[E0658]: `#[link(modifiers="bundle")]` is unstable
--> $DIR/feature-gate-native_link_modifiers_bundle.rs:4:34
|
LL | #[link(name = "foo", modifiers = "+bundle")]
| ^^^^^^^^^
|
= note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
= help: add `#![feature(native_link_modifiers_bundle)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View File

@ -0,0 +1,8 @@
#![allow(incomplete_features)]
#![feature(native_link_modifiers)]
#[link(name = "foo", modifiers = "+verbatim")]
//~^ ERROR: `#[link(modifiers="verbatim")]` is unstable
extern "C" {}
fn main() {}

View File

@ -0,0 +1,12 @@
error[E0658]: `#[link(modifiers="verbatim")]` is unstable
--> $DIR/feature-gate-native_link_modifiers_verbatim.rs:4:34
|
LL | #[link(name = "foo", modifiers = "+verbatim")]
| ^^^^^^^^^^^
|
= note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
= help: add `#![feature(native_link_modifiers_verbatim)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View File

@ -0,0 +1,8 @@
#![allow(incomplete_features)]
#![feature(native_link_modifiers)]
#[link(name = "foo", modifiers = "+whole-archive")]
//~^ ERROR: `#[link(modifiers="whole-archive")]` is unstable
extern "C" {}
fn main() {}

View File

@ -0,0 +1,12 @@
error[E0658]: `#[link(modifiers="whole-archive")]` is unstable
--> $DIR/feature-gate-native_link_modifiers_whole_archive.rs:4:34
|
LL | #[link(name = "foo", modifiers = "+whole-archive")]
| ^^^^^^^^^^^^^^^^
|
= note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
= help: add `#![feature(native_link_modifiers_whole_archive)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View File

@ -1,3 +1,5 @@
warning: library kind `static-nobundle` has been superseded by specifying `-bundle` on library kind `static`. Try `static:-bundle`
error[E0658]: kind="static-nobundle" is unstable
|
= note: see issue #37403 <https://github.com/rust-lang/rust/issues/37403> for more information

View File

@ -1,5 +1,6 @@
#[link(name = "foo", kind = "static-nobundle")]
//~^ ERROR: kind="static-nobundle" is unstable
//~^ WARNING: library kind `static-nobundle` has been superseded by specifying modifier `-bundle` with library kind `static`
//~^^ ERROR: kind="static-nobundle" is unstable
extern "C" {}
fn main() {}

View File

@ -1,3 +1,9 @@
warning: library kind `static-nobundle` has been superseded by specifying modifier `-bundle` with library kind `static`
--> $DIR/feature-gate-static-nobundle.rs:1:22
|
LL | #[link(name = "foo", kind = "static-nobundle")]
| ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0658]: kind="static-nobundle" is unstable
--> $DIR/feature-gate-static-nobundle.rs:1:1
|
@ -7,6 +13,6 @@ LL | #[link(name = "foo", kind = "static-nobundle")]
= note: see issue #37403 <https://github.com/rust-lang/rust/issues/37403> for more information
= help: add `#![feature(static_nobundle)]` to the crate attributes to enable
error: aborting due to previous error
error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0658`.

View File

@ -0,0 +1,6 @@
// Unspecified kind should fail with an error
// compile-flags: -l =mylib
// error-pattern: unknown library kind ``, expected one of dylib, framework, or static
fn main() {}

View File

@ -0,0 +1,2 @@
error: unknown library kind ``, expected one of dylib, framework, or static

View File

@ -0,0 +1,6 @@
// Unspecified kind should fail with an error
// compile-flags: -l :+bundle=mylib
// error-pattern: unknown library kind ``, expected one of dylib, framework, or static
fn main() {}

View File

@ -0,0 +1,2 @@
error: unknown library kind ``, expected one of dylib, framework, or static