mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Stabilize native library modifier syntax and the whole-archive
modifier specifically
This commit is contained in:
parent
bb5c437a2c
commit
1004783ef9
@ -387,13 +387,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
if attr.has_name(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(&['+', '-']) {
|
||||
@ -412,7 +405,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
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
|
||||
);
|
||||
}
|
||||
|
@ -1844,7 +1844,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
|
||||
// This change is somewhat breaking in practice due to local static libraries being linked
|
||||
// as whole-archive (#85144), so removing whole-archive may be a pre-requisite.
|
||||
if sess.opts.debugging_opts.link_native_libraries {
|
||||
add_local_native_libraries(cmd, sess, codegen_results);
|
||||
add_local_native_libraries(cmd, sess, codegen_results, crate_type);
|
||||
}
|
||||
|
||||
// Upstream rust libraries and their nobundle static libraries
|
||||
@ -2016,6 +2016,16 @@ fn add_order_independent_options(
|
||||
add_rpath_args(cmd, sess, codegen_results, out_filename);
|
||||
}
|
||||
|
||||
// A dylib may reexport symbols from the linked rlib or native static library.
|
||||
// Even if some symbol is reexported it's still not necessarily counted as used and may be
|
||||
// dropped, at least with `ld`-like ELF linkers. So we have to link some rlibs and static
|
||||
// libraries as whole-archive to avoid losing reexported symbols.
|
||||
// FIXME: Find a way to mark reexported symbols as used and avoid this use of whole-archive.
|
||||
fn default_to_whole_archive(sess: &Session, crate_type: CrateType, cmd: &dyn Linker) -> bool {
|
||||
crate_type == CrateType::Dylib
|
||||
&& !(sess.target.limit_rdylib_exports && cmd.exported_symbol_means_used_symbol())
|
||||
}
|
||||
|
||||
/// # Native library linking
|
||||
///
|
||||
/// User-supplied library search paths (-L on the command line). These are the same paths used to
|
||||
@ -2029,6 +2039,7 @@ fn add_local_native_libraries(
|
||||
cmd: &mut dyn Linker,
|
||||
sess: &Session,
|
||||
codegen_results: &CodegenResults,
|
||||
crate_type: CrateType,
|
||||
) {
|
||||
let filesearch = sess.target_filesearch(PathKind::All);
|
||||
for search_path in filesearch.search_paths() {
|
||||
@ -2046,14 +2057,18 @@ fn add_local_native_libraries(
|
||||
codegen_results.crate_info.used_libraries.iter().filter(|l| relevant_lib(sess, l));
|
||||
|
||||
let search_path = OnceCell::new();
|
||||
let mut last = (NativeLibKind::Unspecified, None);
|
||||
let mut last = (None, NativeLibKind::Unspecified, None);
|
||||
for lib in relevant_libs {
|
||||
let Some(name) = lib.name else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Skip if this library is the same as the last.
|
||||
last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
|
||||
last = if (lib.name, lib.kind, lib.verbatim) == last {
|
||||
continue;
|
||||
} else {
|
||||
(lib.name, lib.kind, lib.verbatim)
|
||||
};
|
||||
|
||||
let verbatim = lib.verbatim.unwrap_or(false);
|
||||
match lib.kind {
|
||||
@ -2064,15 +2079,19 @@ fn add_local_native_libraries(
|
||||
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.get_or_init(|| archive_search_paths(sess)),
|
||||
);
|
||||
NativeLibKind::Static { whole_archive, .. } => {
|
||||
if whole_archive == Some(true)
|
||||
|| (whole_archive == None && default_to_whole_archive(sess, crate_type, cmd))
|
||||
{
|
||||
cmd.link_whole_staticlib(
|
||||
name,
|
||||
verbatim,
|
||||
&search_path.get_or_init(|| archive_search_paths(sess)),
|
||||
);
|
||||
} else {
|
||||
cmd.link_staticlib(name, verbatim)
|
||||
}
|
||||
}
|
||||
NativeLibKind::Static { .. } => cmd.link_staticlib(name, verbatim),
|
||||
NativeLibKind::RawDylib => {
|
||||
// FIXME(#58713): Proper handling for raw dylibs.
|
||||
bug!("raw_dylib feature not yet implemented");
|
||||
@ -2197,34 +2216,37 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
|
||||
// external build system already has the native dependencies defined, and it
|
||||
// will provide them to the linker itself.
|
||||
if sess.opts.debugging_opts.link_native_libraries {
|
||||
let mut last = None;
|
||||
let mut last = (None, NativeLibKind::Unspecified, None);
|
||||
for lib in &codegen_results.crate_info.native_libraries[&cnum] {
|
||||
let Some(name) = lib.name else {
|
||||
continue;
|
||||
};
|
||||
if !relevant_lib(sess, lib) {
|
||||
// Skip libraries if they are disabled by `#[link(cfg=...)]`
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip if this library is the same as the last.
|
||||
if last == lib.name {
|
||||
last = if (lib.name, lib.kind, lib.verbatim) == last {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
(lib.name, lib.kind, lib.verbatim)
|
||||
};
|
||||
|
||||
if let Some(static_lib_name) = lib.name {
|
||||
if let NativeLibKind::Static { bundle: Some(false), whole_archive } =
|
||||
lib.kind
|
||||
if let NativeLibKind::Static { bundle: Some(false), whole_archive } =
|
||||
lib.kind
|
||||
{
|
||||
let verbatim = lib.verbatim.unwrap_or(false);
|
||||
if whole_archive == Some(true)
|
||||
|| (whole_archive == None
|
||||
&& default_to_whole_archive(sess, crate_type, cmd))
|
||||
{
|
||||
let verbatim = lib.verbatim.unwrap_or(false);
|
||||
if whole_archive == Some(true) {
|
||||
cmd.link_whole_staticlib(
|
||||
static_lib_name,
|
||||
verbatim,
|
||||
search_path.get_or_init(|| archive_search_paths(sess)),
|
||||
);
|
||||
} else {
|
||||
cmd.link_staticlib(static_lib_name, verbatim);
|
||||
}
|
||||
|
||||
last = lib.name;
|
||||
cmd.link_whole_staticlib(
|
||||
name,
|
||||
verbatim,
|
||||
search_path.get_or_init(|| archive_search_paths(sess)),
|
||||
);
|
||||
} else {
|
||||
cmd.link_staticlib(name, verbatim);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2282,15 +2304,10 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
|
||||
let cratepath = &src.rlib.as_ref().unwrap().0;
|
||||
|
||||
let mut link_upstream = |path: &Path| {
|
||||
// If we're creating a dylib, then we need to include the
|
||||
// whole of each object in our archive into that artifact. This is
|
||||
// because a `dylib` can be reused as an intermediate artifact.
|
||||
//
|
||||
// Note, though, that we don't want to include the whole of a
|
||||
// compiler-builtins crate (e.g., compiler-rt) because it'll get
|
||||
// repeatedly linked anyway.
|
||||
// We don't want to include the whole compiler-builtins crate (e.g., compiler-rt)
|
||||
// regardless of the default because it'll get repeatedly linked anyway.
|
||||
let path = fix_windows_verbatim_for_gcc(path);
|
||||
if crate_type == CrateType::Dylib
|
||||
if default_to_whole_archive(sess, crate_type, cmd)
|
||||
&& codegen_results.crate_info.compiler_builtins != Some(cnum)
|
||||
{
|
||||
cmd.link_whole_rlib(&path);
|
||||
@ -2401,7 +2418,7 @@ fn add_upstream_native_libraries(
|
||||
sess: &Session,
|
||||
codegen_results: &CodegenResults,
|
||||
) {
|
||||
let mut last = (NativeLibKind::Unspecified, None);
|
||||
let mut last = (None, NativeLibKind::Unspecified, None);
|
||||
for &cnum in &codegen_results.crate_info.used_crates {
|
||||
for lib in codegen_results.crate_info.native_libraries[&cnum].iter() {
|
||||
let Some(name) = lib.name else {
|
||||
@ -2412,7 +2429,11 @@ fn add_upstream_native_libraries(
|
||||
}
|
||||
|
||||
// Skip if this library is the same as the last.
|
||||
last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
|
||||
last = if (lib.name, lib.kind, lib.verbatim) == last {
|
||||
continue;
|
||||
} else {
|
||||
(lib.name, lib.kind, lib.verbatim)
|
||||
};
|
||||
|
||||
let verbatim = lib.verbatim.unwrap_or(false);
|
||||
match lib.kind {
|
||||
|
@ -186,6 +186,9 @@ pub trait Linker {
|
||||
fn no_crt_objects(&mut self);
|
||||
fn no_default_libraries(&mut self);
|
||||
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
|
||||
fn exported_symbol_means_used_symbol(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn subsystem(&mut self, subsystem: &str);
|
||||
fn group_start(&mut self);
|
||||
fn group_end(&mut self);
|
||||
@ -724,6 +727,10 @@ impl<'a> Linker for GccLinker<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn exported_symbol_means_used_symbol(&self) -> bool {
|
||||
self.sess.target.is_like_windows || self.sess.target.is_like_osx
|
||||
}
|
||||
|
||||
fn subsystem(&mut self, subsystem: &str) {
|
||||
self.linker_arg("--subsystem");
|
||||
self.linker_arg(&subsystem);
|
||||
@ -1471,6 +1478,10 @@ impl<'a> Linker for L4Bender<'a> {
|
||||
return;
|
||||
}
|
||||
|
||||
fn exported_symbol_means_used_symbol(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn subsystem(&mut self, subsystem: &str) {
|
||||
self.cmd.arg(&format!("--subsystem {}", subsystem));
|
||||
}
|
||||
|
@ -215,6 +215,10 @@ declare_features! (
|
||||
/// Allows patterns with concurrent by-move and by-ref bindings.
|
||||
/// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref.
|
||||
(accepted, move_ref_pattern, "1.49.0", Some(68354), None),
|
||||
/// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]`
|
||||
(accepted, native_link_modifiers, "1.61.0", Some(81490), None),
|
||||
/// Allows specifying the whole-archive link modifier
|
||||
(accepted, native_link_modifiers_whole_archive, "1.61.0", Some(81490), None),
|
||||
/// Allows using `#![no_std]`.
|
||||
(accepted, no_std, "1.6.0", None, None),
|
||||
/// Allows defining identifiers beyond ASCII.
|
||||
|
@ -446,16 +446,12 @@ declare_features! (
|
||||
(active, must_not_suspend, "1.57.0", Some(83310), None),
|
||||
/// Allows using `#[naked]` on functions.
|
||||
(active, naked_functions, "1.9.0", Some(32408), None),
|
||||
/// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]`
|
||||
(active, native_link_modifiers, "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),
|
||||
/// 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),
|
||||
/// Allow negative trait implementations.
|
||||
(active, negative_impls, "1.44.0", Some(68318), None),
|
||||
/// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more.
|
||||
|
@ -1,5 +1,5 @@
|
||||
#![feature(nll)]
|
||||
#![feature(native_link_modifiers)]
|
||||
#![cfg_attr(bootstrap, feature(native_link_modifiers))]
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
|
||||
// NOTE: This crate only exists to allow linking on mingw targets.
|
||||
|
@ -125,13 +125,18 @@ impl<'tcx> 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)) {
|
||||
let mut modifiers_count = 0;
|
||||
for item in items.iter().filter(|item| item.has_name(sym::modifiers)) {
|
||||
if let Some(modifiers) = item.value_str() {
|
||||
modifiers_count += 1;
|
||||
let span = item.name_value_literal_span().unwrap();
|
||||
let mut has_duplicate_modifiers = false;
|
||||
for modifier in modifiers.as_str().split(',') {
|
||||
let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
|
||||
Some(m) => (m, modifier.starts_with('+')),
|
||||
None => {
|
||||
// Note: this error also excludes the case with empty modifier
|
||||
// string, like `modifiers = ""`.
|
||||
sess.span_err(
|
||||
span,
|
||||
"invalid linking modifier syntax, expected '+' or '-' prefix \
|
||||
@ -143,6 +148,9 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> {
|
||||
|
||||
match (modifier, &mut lib.kind) {
|
||||
("bundle", NativeLibKind::Static { bundle, .. }) => {
|
||||
if bundle.is_some() {
|
||||
has_duplicate_modifiers = true;
|
||||
}
|
||||
*bundle = Some(value);
|
||||
}
|
||||
("bundle", _) => {
|
||||
@ -153,9 +161,17 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> {
|
||||
);
|
||||
}
|
||||
|
||||
("verbatim", _) => lib.verbatim = Some(value),
|
||||
("verbatim", _) => {
|
||||
if lib.verbatim.is_some() {
|
||||
has_duplicate_modifiers = true;
|
||||
}
|
||||
lib.verbatim = Some(value);
|
||||
}
|
||||
|
||||
("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
|
||||
if whole_archive.is_some() {
|
||||
has_duplicate_modifiers = true;
|
||||
}
|
||||
*whole_archive = Some(value);
|
||||
}
|
||||
("whole-archive", _) => {
|
||||
@ -168,6 +184,9 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> {
|
||||
|
||||
("as-needed", NativeLibKind::Dylib { as_needed })
|
||||
| ("as-needed", NativeLibKind::Framework { as_needed }) => {
|
||||
if as_needed.is_some() {
|
||||
has_duplicate_modifiers = true;
|
||||
}
|
||||
*as_needed = Some(value);
|
||||
}
|
||||
("as-needed", _) => {
|
||||
@ -190,12 +209,22 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
if has_duplicate_modifiers {
|
||||
let msg =
|
||||
"same modifier is used multiple times in a single `modifiers` argument";
|
||||
sess.span_err(item.span(), msg);
|
||||
}
|
||||
} else {
|
||||
let msg = "must be of the form `#[link(modifiers = \"...\")]`";
|
||||
sess.span_err(item.span(), msg);
|
||||
}
|
||||
}
|
||||
|
||||
if modifiers_count > 1 {
|
||||
let msg = "multiple `modifiers` arguments in a single `#[link]` attribute";
|
||||
sess.span_err(m.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();
|
||||
@ -349,6 +378,15 @@ impl Collector<'_> {
|
||||
.drain_filter(|lib| {
|
||||
if let Some(lib_name) = lib.name {
|
||||
if lib_name.as_str() == passed_lib.name {
|
||||
// FIXME: This whole logic is questionable, whether modifiers are
|
||||
// involved or not, library reordering and kind overriding without
|
||||
// explicit `:rename` in particular.
|
||||
if lib.has_modifiers() || passed_lib.has_modifiers() {
|
||||
self.tcx.sess.span_err(
|
||||
self.tcx.def_span(lib.foreign_module.unwrap()),
|
||||
"overriding linking modifiers from command line is not supported"
|
||||
);
|
||||
}
|
||||
if passed_lib.kind != NativeLibKind::Unspecified {
|
||||
lib.kind = passed_lib.kind;
|
||||
}
|
||||
|
@ -1948,9 +1948,6 @@ fn parse_native_lib_kind(
|
||||
kind: &str,
|
||||
error_format: ErrorOutputType,
|
||||
) -> (NativeLibKind, Option<bool>) {
|
||||
let is_nightly = nightly_options::match_is_nightly_build(matches);
|
||||
let enable_unstable = nightly_options::is_unstable_enabled(matches);
|
||||
|
||||
let (kind, modifiers) = match kind.split_once(':') {
|
||||
None => (kind, None),
|
||||
Some((kind, modifiers)) => (kind, Some(modifiers)),
|
||||
@ -1972,7 +1969,7 @@ fn parse_native_lib_kind(
|
||||
"linking modifier can't be used with library kind `static-nobundle`",
|
||||
)
|
||||
}
|
||||
if !is_nightly {
|
||||
if !nightly_options::match_is_nightly_build(matches) {
|
||||
early_error(
|
||||
error_format,
|
||||
"library kind `static-nobundle` are currently unstable and only accepted on \
|
||||
@ -1988,23 +1985,7 @@ fn parse_native_lib_kind(
|
||||
};
|
||||
match modifiers {
|
||||
None => (kind, None),
|
||||
Some(modifiers) => {
|
||||
if !is_nightly {
|
||||
early_error(
|
||||
error_format,
|
||||
"linking modifiers are currently unstable and only accepted on \
|
||||
the nightly compiler",
|
||||
);
|
||||
}
|
||||
if !enable_unstable {
|
||||
early_error(
|
||||
error_format,
|
||||
"linking modifiers are currently unstable, \
|
||||
the `-Z unstable-options` flag must also be passed to use it",
|
||||
)
|
||||
}
|
||||
parse_native_lib_modifiers(kind, modifiers, error_format)
|
||||
}
|
||||
Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2012,7 +1993,23 @@ fn parse_native_lib_modifiers(
|
||||
mut kind: NativeLibKind,
|
||||
modifiers: &str,
|
||||
error_format: ErrorOutputType,
|
||||
matches: &getopts::Matches,
|
||||
) -> (NativeLibKind, Option<bool>) {
|
||||
let report_unstable_modifier = |modifier| {
|
||||
if !nightly_options::is_unstable_enabled(matches) {
|
||||
let why = if nightly_options::match_is_nightly_build(matches) {
|
||||
" and only accepted on the nightly compiler"
|
||||
} else {
|
||||
", the `-Z unstable-options` flag must also be passed to use it"
|
||||
};
|
||||
early_error(
|
||||
error_format,
|
||||
&format!("{modifier} linking modifier is currently unstable{why}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let mut has_duplicate_modifiers = false;
|
||||
let mut verbatim = None;
|
||||
for modifier in modifiers.split(',') {
|
||||
let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
|
||||
@ -2026,6 +2023,10 @@ fn parse_native_lib_modifiers(
|
||||
|
||||
match (modifier, &mut kind) {
|
||||
("bundle", NativeLibKind::Static { bundle, .. }) => {
|
||||
report_unstable_modifier(modifier);
|
||||
if bundle.is_some() {
|
||||
has_duplicate_modifiers = true;
|
||||
}
|
||||
*bundle = Some(value);
|
||||
}
|
||||
("bundle", _) => early_error(
|
||||
@ -2034,9 +2035,18 @@ fn parse_native_lib_modifiers(
|
||||
`static` linking kind",
|
||||
),
|
||||
|
||||
("verbatim", _) => verbatim = Some(value),
|
||||
("verbatim", _) => {
|
||||
report_unstable_modifier(modifier);
|
||||
if verbatim.is_some() {
|
||||
has_duplicate_modifiers = true;
|
||||
}
|
||||
verbatim = Some(value);
|
||||
}
|
||||
|
||||
("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
|
||||
if whole_archive.is_some() {
|
||||
has_duplicate_modifiers = true;
|
||||
}
|
||||
*whole_archive = Some(value);
|
||||
}
|
||||
("whole-archive", _) => early_error(
|
||||
@ -2047,6 +2057,10 @@ fn parse_native_lib_modifiers(
|
||||
|
||||
("as-needed", NativeLibKind::Dylib { as_needed })
|
||||
| ("as-needed", NativeLibKind::Framework { as_needed }) => {
|
||||
report_unstable_modifier(modifier);
|
||||
if as_needed.is_some() {
|
||||
has_duplicate_modifiers = true;
|
||||
}
|
||||
*as_needed = Some(value);
|
||||
}
|
||||
("as-needed", _) => early_error(
|
||||
@ -2055,6 +2069,8 @@ fn parse_native_lib_modifiers(
|
||||
`dylib` and `framework` linking kinds",
|
||||
),
|
||||
|
||||
// Note: this error also excludes the case with empty modifier
|
||||
// string, like `modifiers = ""`.
|
||||
_ => early_error(
|
||||
error_format,
|
||||
&format!(
|
||||
@ -2064,6 +2080,9 @@ fn parse_native_lib_modifiers(
|
||||
),
|
||||
}
|
||||
}
|
||||
if has_duplicate_modifiers {
|
||||
report_unstable_modifier("duplicating")
|
||||
}
|
||||
|
||||
(kind, verbatim)
|
||||
}
|
||||
|
@ -75,6 +75,12 @@ pub struct NativeLib {
|
||||
pub dll_imports: Vec<DllImport>,
|
||||
}
|
||||
|
||||
impl NativeLib {
|
||||
pub fn has_modifiers(&self) -> bool {
|
||||
self.verbatim.is_some() || self.kind.has_modifiers()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
|
||||
pub struct DllImport {
|
||||
pub name: Symbol,
|
||||
|
@ -43,6 +43,20 @@ pub enum NativeLibKind {
|
||||
Unspecified,
|
||||
}
|
||||
|
||||
impl NativeLibKind {
|
||||
pub fn has_modifiers(&self) -> bool {
|
||||
match self {
|
||||
NativeLibKind::Static { bundle, whole_archive } => {
|
||||
bundle.is_some() || whole_archive.is_some()
|
||||
}
|
||||
NativeLibKind::Dylib { as_needed } | NativeLibKind::Framework { as_needed } => {
|
||||
as_needed.is_some()
|
||||
}
|
||||
NativeLibKind::RawDylib | NativeLibKind::Unspecified => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rustc_data_structures::impl_stable_hash_via_hash!(NativeLibKind);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
|
||||
@ -53,6 +67,12 @@ pub struct NativeLib {
|
||||
pub verbatim: Option<bool>,
|
||||
}
|
||||
|
||||
impl NativeLib {
|
||||
pub fn has_modifiers(&self) -> bool {
|
||||
self.verbatim.is_some() || self.kind.has_modifiers()
|
||||
}
|
||||
}
|
||||
|
||||
rustc_data_structures::impl_stable_hash_via_hash!(NativeLib);
|
||||
|
||||
/// A path that has been canonicalized along with its original, non-canonicalized form
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![no_std]
|
||||
#![unstable(feature = "panic_unwind", issue = "32837")]
|
||||
#![feature(link_cfg)]
|
||||
#![feature(native_link_modifiers)]
|
||||
#![cfg_attr(bootstrap, feature(native_link_modifiers))]
|
||||
#![feature(native_link_modifiers_bundle)]
|
||||
#![feature(nll)]
|
||||
#![feature(staged_api)]
|
||||
|
@ -37,6 +37,8 @@ KIND=PATH` where `KIND` may be one of:
|
||||
<a id="option-l-link-lib"></a>
|
||||
## `-l`: link the generated crate to a native library
|
||||
|
||||
Syntax: `-l [KIND[:MODIFIERS]=]NAME[:RENAME]`.
|
||||
|
||||
This flag allows you to specify linking to a specific native library when building
|
||||
a crate.
|
||||
|
||||
@ -47,7 +49,13 @@ where `KIND` may be one of:
|
||||
- `static` — A native static library (such as a `.a` archive).
|
||||
- `framework` — A macOS framework.
|
||||
|
||||
The kind of library can be specified in a [`#[link]`
|
||||
If the kind is specified, then linking modifiers can be attached to it.
|
||||
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. \
|
||||
Example: `-l static:+whole-archive=mylib`.
|
||||
|
||||
The kind of library and the modifiers can also be specified in a [`#[link]`
|
||||
attribute][link-attribute]. If the kind is not specified in the `link`
|
||||
attribute or on the command-line, it will link a dynamic library if available,
|
||||
otherwise it will use a static library. If the kind is specified on the
|
||||
@ -59,6 +67,22 @@ and `LINK_NAME` is the name of the actual library that will be linked.
|
||||
|
||||
[link-attribute]: ../reference/items/external-blocks.html#the-link-attribute
|
||||
|
||||
### Linking modifiers: `whole-archive`
|
||||
|
||||
This modifier is 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`. \
|
||||
NOTE: The default may currently be different when building dylibs for some targets,
|
||||
but it is not guaranteed.
|
||||
|
||||
<a id="option-crate-type"></a>
|
||||
## `--crate-type`: a list of types of crates for the compiler to emit
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
# `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`.
|
@ -1,11 +0,0 @@
|
||||
# `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.
|
@ -1,6 +1,4 @@
|
||||
#![feature(native_link_modifiers_bundle)]
|
||||
#![feature(native_link_modifiers_whole_archive)]
|
||||
#![feature(native_link_modifiers)]
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![feature(raw_dylib, native_link_modifiers, native_link_modifiers_verbatim)]
|
||||
#![feature(raw_dylib, native_link_modifiers_verbatim)]
|
||||
|
||||
#[link(name = "extern_1.dll", kind = "raw-dylib", modifiers = "+verbatim")]
|
||||
extern {
|
||||
|
@ -1,5 +0,0 @@
|
||||
#[link(name = "foo", modifiers = "")]
|
||||
//~^ ERROR: native link modifiers are experimental
|
||||
extern "C" {}
|
||||
|
||||
fn main() {}
|
@ -1,12 +0,0 @@
|
||||
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`.
|
@ -1,6 +1,3 @@
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(native_link_modifiers)]
|
||||
|
||||
#[link(name = "foo", modifiers = "+as-needed")]
|
||||
//~^ ERROR: `#[link(modifiers="as-needed")]` is unstable
|
||||
extern "C" {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0658]: `#[link(modifiers="as-needed")]` is unstable
|
||||
--> $DIR/feature-gate-native_link_modifiers_as_needed.rs:4:34
|
||||
--> $DIR/feature-gate-native_link_modifiers_as_needed.rs:1:34
|
||||
|
|
||||
LL | #[link(name = "foo", modifiers = "+as-needed")]
|
||||
| ^^^^^^^^^^^^
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Test native_link_modifiers_bundle don't need static-nobundle
|
||||
// check-pass
|
||||
|
||||
#![feature(native_link_modifiers)]
|
||||
#![feature(native_link_modifiers_bundle)]
|
||||
|
||||
#[link(name = "foo", kind = "static", modifiers = "-bundle")]
|
||||
|
@ -1,2 +1,2 @@
|
||||
error: linking modifiers are currently unstable, the `-Z unstable-options` flag must also be passed to use it
|
||||
error: bundle linking modifier is currently unstable and only accepted on the nightly compiler
|
||||
|
||||
|
@ -1,6 +1,3 @@
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(native_link_modifiers)]
|
||||
|
||||
#[link(name = "foo", modifiers = "+bundle")]
|
||||
//~^ ERROR: `#[link(modifiers="bundle")]` is unstable
|
||||
extern "C" {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0658]: `#[link(modifiers="bundle")]` is unstable
|
||||
--> $DIR/feature-gate-native_link_modifiers_bundle.rs:4:34
|
||||
--> $DIR/feature-gate-native_link_modifiers_bundle.rs:1:34
|
||||
|
|
||||
LL | #[link(name = "foo", modifiers = "+bundle")]
|
||||
| ^^^^^^^^^
|
||||
|
@ -1,6 +1,3 @@
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(native_link_modifiers)]
|
||||
|
||||
#[link(name = "foo", modifiers = "+verbatim")]
|
||||
//~^ ERROR: `#[link(modifiers="verbatim")]` is unstable
|
||||
extern "C" {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0658]: `#[link(modifiers="verbatim")]` is unstable
|
||||
--> $DIR/feature-gate-native_link_modifiers_verbatim.rs:4:34
|
||||
--> $DIR/feature-gate-native_link_modifiers_verbatim.rs:1:34
|
||||
|
|
||||
LL | #[link(name = "foo", modifiers = "+verbatim")]
|
||||
| ^^^^^^^^^^^
|
||||
|
@ -1,8 +0,0 @@
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(native_link_modifiers)]
|
||||
|
||||
#[link(name = "foo", modifiers = "+whole-archive")]
|
||||
//~^ ERROR: `#[link(modifiers="whole-archive")]` is unstable
|
||||
extern "C" {}
|
||||
|
||||
fn main() {}
|
@ -1,12 +0,0 @@
|
||||
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`.
|
@ -2,9 +2,7 @@
|
||||
// build-fail
|
||||
// error-pattern: the linking modifiers `+bundle` and `+whole-archive` are not compatible with each other when generating rlibs
|
||||
|
||||
#![feature(native_link_modifiers)]
|
||||
#![feature(native_link_modifiers_bundle)]
|
||||
#![feature(native_link_modifiers_whole_archive)]
|
||||
|
||||
#[link(name = "mylib", kind = "static", modifiers = "+bundle,+whole-archive")]
|
||||
extern "C" { }
|
||||
|
@ -0,0 +1,3 @@
|
||||
// compile-flags:-lstatic:+whole-archive,-whole-archive=foo
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,2 @@
|
||||
error: duplicating linking modifier is currently unstable and only accepted on the nightly compiler
|
||||
|
17
src/test/ui/native-library-link-flags/modifiers-override.rs
Normal file
17
src/test/ui/native-library-link-flags/modifiers-override.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// compile-flags:-ldylib:+as-needed=foo -lstatic=bar -Zunstable-options
|
||||
|
||||
#![feature(native_link_modifiers_bundle)]
|
||||
|
||||
#[link(name = "foo")]
|
||||
#[link( //~ ERROR multiple `modifiers` arguments in a single `#[link]` attribute
|
||||
name = "bar",
|
||||
kind = "static",
|
||||
modifiers = "+whole-archive,-whole-archive",
|
||||
//~^ ERROR same modifier is used multiple times in a single `modifiers` argument
|
||||
modifiers = "+bundle"
|
||||
)]
|
||||
extern "C" {}
|
||||
//~^ ERROR overriding linking modifiers from command line is not supported
|
||||
//~| ERROR overriding linking modifiers from command line is not supported
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,32 @@
|
||||
error: same modifier is used multiple times in a single `modifiers` argument
|
||||
--> $DIR/modifiers-override.rs:9:5
|
||||
|
|
||||
LL | modifiers = "+whole-archive,-whole-archive",
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: multiple `modifiers` arguments in a single `#[link]` attribute
|
||||
--> $DIR/modifiers-override.rs:6:1
|
||||
|
|
||||
LL | / #[link(
|
||||
LL | | name = "bar",
|
||||
LL | | kind = "static",
|
||||
LL | | modifiers = "+whole-archive,-whole-archive",
|
||||
LL | |
|
||||
LL | | modifiers = "+bundle"
|
||||
LL | | )]
|
||||
| |__^
|
||||
|
||||
error: overriding linking modifiers from command line is not supported
|
||||
--> $DIR/modifiers-override.rs:13:1
|
||||
|
|
||||
LL | extern "C" {}
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: overriding linking modifiers from command line is not supported
|
||||
--> $DIR/modifiers-override.rs:13:1
|
||||
|
|
||||
LL | extern "C" {}
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
Loading…
Reference in New Issue
Block a user