Auto merge of #84982 - Dylan-DPC:rollup-q4cbec2, r=Dylan-DPC
Rollup of 8 pull requests Successful merges: - #83507 (Implement RFC 2951: Native link modifiers) - #84328 (Stablize {HashMap,BTreeMap}::into_{keys,values}) - #84712 (Simplify chdir implementation and minimize unsafe block) - #84851 (⬆️ rust-analyzer) - #84923 (Only compute Obligation `cache_key` once in `register_obligation_at`) - #84945 (E0583: Include secondary path in error message) - #84949 (Fix typo in `MaybeUninit::array_assume_init` safety comment) - #84950 (Revert PR 83866) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
d44f647ffc
60 changed files with 885 additions and 273 deletions
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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 {}: {}",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -443,6 +473,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;
|
||||
|
@ -710,8 +750,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) {
|
||||
|
@ -725,8 +769,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) {
|
||||
|
@ -764,13 +808,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);
|
||||
|
@ -919,7 +963,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);
|
||||
}
|
||||
|
||||
|
@ -931,14 +975,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) {
|
||||
|
@ -947,7 +991,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) {
|
||||
|
@ -970,7 +1014,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")
|
||||
}
|
||||
|
||||
|
@ -978,6 +1022,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 {
|
||||
|
@ -1121,11 +1169,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);
|
||||
}
|
||||
|
||||
|
@ -1159,11 +1207,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);
|
||||
}
|
||||
|
||||
|
@ -1175,6 +1223,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",
|
||||
|
@ -1329,7 +1381,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")
|
||||
}
|
||||
|
||||
|
@ -1337,11 +1389,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")
|
||||
}
|
||||
|
||||
|
@ -1349,7 +1401,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")
|
||||
}
|
||||
|
||||
|
@ -1361,6 +1413,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) {}
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -336,12 +336,13 @@ impl<O: ForestObligation> ObligationForest<O> {
|
|||
|
||||
// Returns Err(()) if we already know this obligation failed.
|
||||
fn register_obligation_at(&mut self, obligation: O, parent: Option<usize>) -> Result<(), ()> {
|
||||
if self.done_cache.contains(&obligation.as_cache_key()) {
|
||||
let cache_key = obligation.as_cache_key();
|
||||
if self.done_cache.contains(&cache_key) {
|
||||
debug!("register_obligation_at: ignoring already done obligation: {:?}", obligation);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match self.active_cache.entry(obligation.as_cache_key()) {
|
||||
match self.active_cache.entry(cache_key.clone()) {
|
||||
Entry::Occupied(o) => {
|
||||
let node = &mut self.nodes[*o.get()];
|
||||
if let Some(parent_index) = parent {
|
||||
|
@ -365,7 +366,7 @@ impl<O: ForestObligation> ObligationForest<O> {
|
|||
&& self
|
||||
.error_cache
|
||||
.get(&obligation_tree_id)
|
||||
.map(|errors| errors.contains(&obligation.as_cache_key()))
|
||||
.map(|errors| errors.contains(&cache_key))
|
||||
.unwrap_or(false);
|
||||
|
||||
if already_failed {
|
||||
|
|
|
@ -36,7 +36,7 @@ crate struct ParsedExternalMod {
|
|||
pub enum ModError<'a> {
|
||||
CircularInclusion(Vec<PathBuf>),
|
||||
ModInBlock(Option<Ident>),
|
||||
FileNotFound(Ident, PathBuf),
|
||||
FileNotFound(Ident, PathBuf, PathBuf),
|
||||
MultipleCandidates(Ident, PathBuf, PathBuf),
|
||||
ParserError(DiagnosticBuilder<'a>),
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ pub fn default_submod_path<'a>(
|
|||
file_path: secondary_path,
|
||||
dir_ownership: DirOwnership::Owned { relative: None },
|
||||
}),
|
||||
(false, false) => Err(ModError::FileNotFound(ident, default_path)),
|
||||
(false, false) => Err(ModError::FileNotFound(ident, default_path, secondary_path)),
|
||||
(true, true) => Err(ModError::MultipleCandidates(ident, default_path, secondary_path)),
|
||||
}
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ impl ModError<'_> {
|
|||
}
|
||||
err
|
||||
}
|
||||
ModError::FileNotFound(ident, default_path) => {
|
||||
ModError::FileNotFound(ident, default_path, secondary_path) => {
|
||||
let mut err = struct_span_err!(
|
||||
diag,
|
||||
span,
|
||||
|
@ -256,9 +256,10 @@ impl ModError<'_> {
|
|||
ident,
|
||||
);
|
||||
err.help(&format!(
|
||||
"to create the module `{}`, create file \"{}\"",
|
||||
"to create the module `{}`, create file \"{}\" or \"{}\"",
|
||||
ident,
|
||||
default_path.display(),
|
||||
secondary_path.display(),
|
||||
));
|
||||
err
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue