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

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