From 1004783ef9bdcf006f0ed33badacf83a5934feb2 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 11 Feb 2022 15:08:35 +0800 Subject: [PATCH] Stabilize native library modifier syntax and the `whole-archive` modifier specifically --- compiler/rustc_ast_passes/src/feature_gate.rs | 8 -- compiler/rustc_codegen_ssa/src/back/link.rs | 101 +++++++++++------- compiler/rustc_codegen_ssa/src/back/linker.rs | 11 ++ compiler/rustc_feature/src/accepted.rs | 4 + compiler/rustc_feature/src/active.rs | 4 - compiler/rustc_llvm/src/lib.rs | 2 +- compiler/rustc_metadata/src/native_libs.rs | 42 +++++++- compiler/rustc_session/src/config.rs | 63 +++++++---- compiler/rustc_session/src/cstore.rs | 6 ++ compiler/rustc_session/src/utils.rs | 20 ++++ library/unwind/src/lib.rs | 2 +- src/doc/rustc/src/command-line-arguments.md | 26 ++++- .../native-link-modifiers-whole-archive.md | 18 ---- .../native-link-modifiers.md | 11 -- .../native_lib_in_src.rs | 2 - src/test/run-make/raw-dylib-c/lib.rs | 2 +- .../feature-gate-native_link_modifiers.rs | 5 - .../feature-gate-native_link_modifiers.stderr | 12 --- ...re-gate-native_link_modifiers_as_needed.rs | 3 - ...ate-native_link_modifiers_as_needed.stderr | 2 +- ...ure-gate-native_link_modifiers_bundle-2.rs | 1 - ...gate-native_link_modifiers_bundle-3.stderr | 2 +- ...ature-gate-native_link_modifiers_bundle.rs | 3 - ...e-gate-native_link_modifiers_bundle.stderr | 2 +- ...ure-gate-native_link_modifiers_verbatim.rs | 3 - ...gate-native_link_modifiers_verbatim.stderr | 2 +- ...ate-native_link_modifiers_whole_archive.rs | 8 -- ...native_link_modifiers_whole_archive.stderr | 12 --- .../mix-bundle-and-whole-archive-link-attr.rs | 2 - .../modifiers-override-2.rs | 3 + .../modifiers-override-2.stderr | 2 + .../modifiers-override.rs | 17 +++ .../modifiers-override.stderr | 32 ++++++ 33 files changed, 269 insertions(+), 164 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md delete mode 100644 src/doc/unstable-book/src/language-features/native-link-modifiers.md delete mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr delete mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr create mode 100644 src/test/ui/native-library-link-flags/modifiers-override-2.rs create mode 100644 src/test/ui/native-library-link-flags/modifiers-override-2.stderr create mode 100644 src/test/ui/native-library-link-flags/modifiers-override.rs create mode 100644 src/test/ui/native-library-link-flags/modifiers-override.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 5b6147c7223..a778d8c5470 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -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 ); } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index dbbbbd5ecc0..548ae0e411d 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -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 { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index a838787381d..3a66bfafaf3 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -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)); } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index ace0c9df58d..e37251c9c24 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -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. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index feef7295254..90b35b5a83f 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -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. diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index 8476c2bfcc4..0324ac3641e 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -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. diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index c3a76112391..1cbfb0bd554 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -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; } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 44a2e2bdc85..856436e44db 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1948,9 +1948,6 @@ fn parse_native_lib_kind( kind: &str, error_format: ErrorOutputType, ) -> (NativeLibKind, Option) { - 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) { + 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) } diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 281fc887633..c1fd3c7c61b 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -75,6 +75,12 @@ pub struct NativeLib { pub dll_imports: Vec, } +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, diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index a33f94013d2..6a8775bd10b 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -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, } +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 diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 079626f0fea..82f1e63f4b5 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -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)] diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 3759cb632bb..7838696cc12 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -37,6 +37,8 @@ KIND=PATH` where `KIND` may be one of: ## `-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. + ## `--crate-type`: a list of types of crates for the compiler to emit diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md b/src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md deleted file mode 100644 index 4961e88cad1..00000000000 --- a/src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md +++ /dev/null @@ -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`. diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers.md b/src/doc/unstable-book/src/language-features/native-link-modifiers.md deleted file mode 100644 index fc8b5754621..00000000000 --- a/src/doc/unstable-book/src/language-features/native-link-modifiers.md +++ /dev/null @@ -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. diff --git a/src/test/run-make/native-link-modifier-whole-archive/native_lib_in_src.rs b/src/test/run-make/native-link-modifier-whole-archive/native_lib_in_src.rs index 373d89b7936..2436c36e6eb 100644 --- a/src/test/run-make/native-link-modifier-whole-archive/native_lib_in_src.rs +++ b/src/test/run-make/native-link-modifier-whole-archive/native_lib_in_src.rs @@ -1,6 +1,4 @@ #![feature(native_link_modifiers_bundle)] -#![feature(native_link_modifiers_whole_archive)] -#![feature(native_link_modifiers)] use std::io::Write; diff --git a/src/test/run-make/raw-dylib-c/lib.rs b/src/test/run-make/raw-dylib-c/lib.rs index d8e6301f38e..e185c4aec12 100644 --- a/src/test/run-make/raw-dylib-c/lib.rs +++ b/src/test/run-make/raw-dylib-c/lib.rs @@ -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 { diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs deleted file mode 100644 index 2d00aa2a3cf..00000000000 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[link(name = "foo", modifiers = "")] -//~^ ERROR: native link modifiers are experimental -extern "C" {} - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr deleted file mode 100644 index 20a2d6a26fa..00000000000 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr +++ /dev/null @@ -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 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`. diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs index 4cf8067592e..fedee812398 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs @@ -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" {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr index 08ce807851b..96750aa6e80 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr @@ -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")] | ^^^^^^^^^^^^ diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-2.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-2.rs index 1b5fa78ee55..e229564950f 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-2.rs +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-2.rs @@ -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")] diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-3.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-3.stderr index 86ccb4e860b..900605c3b37 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-3.stderr +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-3.stderr @@ -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 diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs index b2b1dc28e47..c3c3cff17c4 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs @@ -1,6 +1,3 @@ -#![allow(incomplete_features)] -#![feature(native_link_modifiers)] - #[link(name = "foo", modifiers = "+bundle")] //~^ ERROR: `#[link(modifiers="bundle")]` is unstable extern "C" {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr index b3e22b0644a..984b90d9b6c 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr @@ -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")] | ^^^^^^^^^ diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs index 042ce0b3f65..57527be1112 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs @@ -1,6 +1,3 @@ -#![allow(incomplete_features)] -#![feature(native_link_modifiers)] - #[link(name = "foo", modifiers = "+verbatim")] //~^ ERROR: `#[link(modifiers="verbatim")]` is unstable extern "C" {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr index 8159416edfa..5c64c0d21bd 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr @@ -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")] | ^^^^^^^^^^^ diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs deleted file mode 100644 index ca801e59114..00000000000 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs +++ /dev/null @@ -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() {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr deleted file mode 100644 index cacaa789ecb..00000000000 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr +++ /dev/null @@ -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 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`. diff --git a/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.rs b/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.rs index c3714a38451..b153ef94626 100644 --- a/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.rs +++ b/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.rs @@ -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" { } diff --git a/src/test/ui/native-library-link-flags/modifiers-override-2.rs b/src/test/ui/native-library-link-flags/modifiers-override-2.rs new file mode 100644 index 00000000000..333f6786b0f --- /dev/null +++ b/src/test/ui/native-library-link-flags/modifiers-override-2.rs @@ -0,0 +1,3 @@ +// compile-flags:-lstatic:+whole-archive,-whole-archive=foo + +fn main() {} diff --git a/src/test/ui/native-library-link-flags/modifiers-override-2.stderr b/src/test/ui/native-library-link-flags/modifiers-override-2.stderr new file mode 100644 index 00000000000..9200d7bfb0c --- /dev/null +++ b/src/test/ui/native-library-link-flags/modifiers-override-2.stderr @@ -0,0 +1,2 @@ +error: duplicating linking modifier is currently unstable and only accepted on the nightly compiler + diff --git a/src/test/ui/native-library-link-flags/modifiers-override.rs b/src/test/ui/native-library-link-flags/modifiers-override.rs new file mode 100644 index 00000000000..f6d770559e6 --- /dev/null +++ b/src/test/ui/native-library-link-flags/modifiers-override.rs @@ -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() {} diff --git a/src/test/ui/native-library-link-flags/modifiers-override.stderr b/src/test/ui/native-library-link-flags/modifiers-override.stderr new file mode 100644 index 00000000000..8644d2382d2 --- /dev/null +++ b/src/test/ui/native-library-link-flags/modifiers-override.stderr @@ -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 +