Rollup merge of #150992 - cezarbbb:cstyle-export-rules2, r=bjorn3,petrochenkov

link modifier `export-symbols`: export all global symbols from selected uptream c static libraries

In order to be able to export symbols from a specified upstream C static library, I redesigned a solution that, compared to a previous PR rust-lang/rust#150335 I submitted, will not have any extra symbols leaking out.

The following points should be noted:
 - This attribute will select and import the `Global` symbols of the first matching library it finds.
 - Developers should ensure that there are no libraries with the same name.
 - This modifier is only compatible with `static` linking kind
 - By default, upstream C static libraries will not export their `Global` symbols regardless of whether `LTO` optimization is enabled. However, after enabling this attribute, if the upstream C static library has `LTO` optimization enabled, the compiler will issue an error to inform the developer that the linked C library is invalid.

The test code is the same as the PR rust-lang/rust#150335.
Here are the results:
1. `cargo +include-libs rustc --release -- -L. -lstatic:+export-symbols=c_add`
(or you can use `#[link(name = "c_add", kind= "static", modifier = "+export-symbols")]` in the file)
```bash
                 U abort@GLIBC_2.2.5
                 U bcmp@GLIBC_2.2.5
0000000000014f60 T c_add
                 U calloc@GLIBC_2.2.5
                 U close@GLIBC_2.2.5
0000000000014f70 T c_sub
                 w __cxa_finalize@GLIBC_2.2.5
                 w __cxa_thread_atexit_impl@GLIBC_2.18
                 U dl_iterate_phdr@GLIBC_2.2.5
0000000000014ee0 T downstream_add
                 U __errno_location@GLIBC_2.2.5
                 U free@GLIBC_2.2.5
                 U fstat64@GLIBC_2.33
                 U getcwd@GLIBC_2.2.5
                 U getenv@GLIBC_2.2.5
                 w __gmon_start__
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U lseek64@GLIBC_2.2.5
                 U malloc@GLIBC_2.2.5
                 U memcpy@GLIBC_2.14
                 U memmove@GLIBC_2.2.5
                 U memset@GLIBC_2.2.5
                 U mmap64@GLIBC_2.2.5
                 U munmap@GLIBC_2.2.5
                 U open64@GLIBC_2.2.5
                 U posix_memalign@GLIBC_2.2.5
                 U pthread_key_create@GLIBC_2.34
                 U pthread_key_delete@GLIBC_2.34
                 U pthread_setspecific@GLIBC_2.34
                 U read@GLIBC_2.2.5
                 U readlink@GLIBC_2.2.5
                 U realloc@GLIBC_2.2.5
                 U realpath@GLIBC_2.3
                 U stat64@GLIBC_2.33
                 w statx@GLIBC_2.28
                 U strlen@GLIBC_2.2.5
                 U syscall@GLIBC_2.2.5
                 U __tls_get_addr@GLIBC_2.3
                 U _Unwind_Backtrace@GCC_3.3
                 U _Unwind_DeleteException@GCC_3.0
                 U _Unwind_GetDataRelBase@GCC_3.0
                 U _Unwind_GetIP@GCC_3.0
                 U _Unwind_GetIPInfo@GCC_4.2.0
                 U _Unwind_GetLanguageSpecificData@GCC_3.0
                 U _Unwind_GetRegionStart@GCC_3.0
                 U _Unwind_GetTextRelBase@GCC_3.0
                 U _Unwind_RaiseException@GCC_3.0
                 U _Unwind_Resume@GCC_3.0
                 U _Unwind_SetGR@GCC_3.0
                 U _Unwind_SetIP@GCC_3.0
                 U write@GLIBC_2.2.5
                 U writev@GLIBC_2.2.5
```
3. `cargo +nightly rustc --release -- -L ./`
```bash
                 U abort@GLIBC_2.2.5
                 U bcmp@GLIBC_2.2.5
                 U calloc@GLIBC_2.2.5
                 U close@GLIBC_2.2.5
                 w __cxa_finalize@GLIBC_2.2.5
                 w __cxa_thread_atexit_impl@GLIBC_2.18
                 U dl_iterate_phdr@GLIBC_2.2.5
0000000000011e10 T downstream_add
                 U __errno_location@GLIBC_2.2.5
                 U free@GLIBC_2.2.5
                 U fstat64@GLIBC_2.33
                 U getcwd@GLIBC_2.2.5
                 U getenv@GLIBC_2.2.5
                 w gettid@GLIBC_2.30
                 w __gmon_start__
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U lseek64@GLIBC_2.2.5
                 U malloc@GLIBC_2.2.5
                 U memcpy@GLIBC_2.14
                 U memmove@GLIBC_2.2.5
                 U memset@GLIBC_2.2.5
                 U mmap64@GLIBC_2.2.5
                 U munmap@GLIBC_2.2.5
                 U open64@GLIBC_2.2.5
                 U posix_memalign@GLIBC_2.2.5
                 U pthread_key_create@GLIBC_2.34
                 U pthread_key_delete@GLIBC_2.34
                 U pthread_setspecific@GLIBC_2.34
                 U read@GLIBC_2.2.5
                 U readlink@GLIBC_2.2.5
                 U realloc@GLIBC_2.2.5
                 U realpath@GLIBC_2.3
                 U stat64@GLIBC_2.33
                 w statx@GLIBC_2.28
                 U strlen@GLIBC_2.2.5
                 U syscall@GLIBC_2.2.5
                 U __tls_get_addr@GLIBC_2.3
                 U _Unwind_Backtrace@GCC_3.3
                 U _Unwind_GetDataRelBase@GCC_3.0
                 U _Unwind_GetIP@GCC_3.0
                 U _Unwind_GetIPInfo@GCC_4.2.0
                 U _Unwind_GetLanguageSpecificData@GCC_3.0
                 U _Unwind_GetRegionStart@GCC_3.0
                 U _Unwind_GetTextRelBase@GCC_3.0
                 U _Unwind_RaiseException@GCC_3.0
                 U _Unwind_Resume@GCC_3.0
                 U _Unwind_SetGR@GCC_3.0
                 U _Unwind_SetIP@GCC_3.0
                 U write@GLIBC_2.2.5
                 U writev@GLIBC_2.2.5
```

r? @bjorn3
This commit is contained in:
Jonathan Brouwer 2026-02-04 14:39:17 +01:00 committed by GitHub
commit a1d588b35e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 226 additions and 36 deletions

View file

@ -12,10 +12,10 @@ use super::prelude::*;
use super::util::parse_single_integer;
use crate::attributes::cfg::parse_cfg_entry;
use crate::session_diagnostics::{
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ImportNameTypeRaw, ImportNameTypeX86,
IncompatibleWasmLink, InvalidLinkModifier, LinkFrameworkApple, LinkOrdinalOutOfRange,
LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows,
WholeArchiveNeedsStatic,
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier,
LinkFrameworkApple, LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers,
NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows, WholeArchiveNeedsStatic,
};
pub(crate) struct LinkNameParser;
@ -165,6 +165,14 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
cx.emit_err(BundleNeedsStatic { span });
}
(sym::export_symbols, Some(NativeLibKind::Static { export_symbols, .. })) => {
assign_modifier(export_symbols)
}
(sym::export_symbols, _) => {
cx.emit_err(ExportSymbolsNeedsStatic { span });
}
(sym::verbatim, _) => assign_modifier(&mut verbatim),
(
@ -190,6 +198,7 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
span,
&[
sym::bundle,
sym::export_symbols,
sym::verbatim,
sym::whole_dash_archive,
sym::as_dash_needed,
@ -285,7 +294,9 @@ impl LinkParser {
};
let link_kind = match link_kind {
kw::Static => NativeLibKind::Static { bundle: None, whole_archive: None },
kw::Static => {
NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None }
}
sym::dylib => NativeLibKind::Dylib { as_needed: None },
sym::framework => {
if !sess.target.is_like_darwin {

View file

@ -909,7 +909,7 @@ pub(crate) struct RawDylibOnlyWindows {
#[derive(Diagnostic)]
#[diag(
"invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed"
"invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed, export-symbols"
)]
pub(crate) struct InvalidLinkModifier {
#[primary_span]
@ -938,6 +938,13 @@ pub(crate) struct BundleNeedsStatic {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag("linking modifier `export-symbols` is only compatible with `static` linking kind")]
pub(crate) struct ExportSymbolsNeedsStatic {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag("linking modifier `whole-archive` is only compatible with `static` linking kind")]
pub(crate) struct WholeArchiveNeedsStatic {

View file

@ -11,10 +11,11 @@ use std::{env, fmt, fs, io, mem, str};
use find_msvc_tools;
use itertools::Itertools;
use object::{Object, ObjectSection, ObjectSymbol};
use regex::Regex;
use rustc_arena::TypedArena;
use rustc_attr_parsing::eval_config_entry;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::{DiagCtxtHandle, LintDiagnostic};
@ -2185,6 +2186,71 @@ fn add_rpath_args(
}
}
fn add_c_staticlib_symbols(
sess: &Session,
lib: &NativeLib,
out: &mut Vec<(String, SymbolExportKind)>,
) -> io::Result<()> {
let file_path = find_native_static_library(lib.name.as_str(), lib.verbatim, sess);
let archive_map = unsafe { Mmap::map(File::open(&file_path)?)? };
let archive = object::read::archive::ArchiveFile::parse(&*archive_map)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
for member in archive.members() {
let member = member.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
let data = member
.data(&*archive_map)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
// clang LTO: raw LLVM bitcode
if data.starts_with(b"BC\xc0\xde") {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"LLVM bitcode object in C static library (LTO not supported)",
));
}
let object = object::File::parse(&*data)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
// gcc / clang ELF / Mach-O LTO
if object.sections().any(|s| {
s.name().map(|n| n.starts_with(".gnu.lto_") || n == ".llvm.lto").unwrap_or(false)
}) {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"LTO object in C static library is not supported",
));
}
for symbol in object.symbols() {
if symbol.scope() != object::SymbolScope::Dynamic {
continue;
}
let name = match symbol.name() {
Ok(n) => n,
Err(_) => continue,
};
let export_kind = match symbol.kind() {
object::SymbolKind::Text => SymbolExportKind::Text,
object::SymbolKind::Data => SymbolExportKind::Data,
_ => continue,
};
// FIXME:The symbol mangle rules are slightly different in Windows(32-bit) and Apple.
// Need to be resolved.
out.push((name.to_string(), export_kind));
}
}
Ok(())
}
/// Produce the linker command line containing linker path and arguments.
///
/// When comments in the function say "order-(in)dependent" they mean order-dependence between
@ -2217,6 +2283,25 @@ fn linker_with_args(
);
let link_output_kind = link_output_kind(sess, crate_type);
let mut export_symbols = codegen_results.crate_info.exported_symbols[&crate_type].clone();
if crate_type == CrateType::Cdylib {
let mut seen = FxHashSet::default();
for lib in &codegen_results.crate_info.used_libraries {
if let NativeLibKind::Static { export_symbols: Some(true), .. } = lib.kind
&& seen.insert((lib.name, lib.verbatim))
{
if let Err(err) = add_c_staticlib_symbols(&sess, lib, &mut export_symbols) {
sess.dcx().fatal(format!(
"failed to process C static library `{}`: {}",
lib.name, err
));
}
}
}
}
// ------------ Early order-dependent options ------------
// If we're building something like a dynamic library then some platforms
@ -2224,11 +2309,7 @@ fn linker_with_args(
// dynamic library.
// Must be passed before any libraries to prevent the symbols to export from being thrown away,
// at least on some platforms (e.g. windows-gnu).
cmd.export_symbols(
tmpdir,
crate_type,
&codegen_results.crate_info.exported_symbols[&crate_type],
);
cmd.export_symbols(tmpdir, crate_type, &export_symbols);
// Can be used for adding custom CRT objects or overriding order-dependent options above.
// FIXME: In practice built-in target specs use this for arbitrary order-independent options,
@ -2678,7 +2759,7 @@ fn add_native_libs_from_crate(
let name = lib.name.as_str();
let verbatim = lib.verbatim;
match lib.kind {
NativeLibKind::Static { bundle, whole_archive } => {
NativeLibKind::Static { bundle, whole_archive, .. } => {
if link_static {
let bundle = bundle.unwrap_or(true);
let whole_archive = whole_archive == Some(true);

View file

@ -331,6 +331,8 @@ pub enum NativeLibKind {
bundle: Option<bool>,
/// Whether to link static library without throwing any object files away
whole_archive: Option<bool>,
/// Whether to export c static library symbols
export_symbols: 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).
@ -363,8 +365,8 @@ pub enum NativeLibKind {
impl NativeLibKind {
pub fn has_modifiers(&self) -> bool {
match self {
NativeLibKind::Static { bundle, whole_archive } => {
bundle.is_some() || whole_archive.is_some()
NativeLibKind::Static { bundle, whole_archive, export_symbols } => {
bundle.is_some() || whole_archive.is_some() || export_symbols.is_some()
}
NativeLibKind::Dylib { as_needed }
| NativeLibKind::Framework { as_needed }

View file

@ -379,7 +379,7 @@ fn test_native_libs_tracking_hash_different_values() {
NativeLib {
name: String::from("a"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
verbatim: None,
},
NativeLib {
@ -401,7 +401,7 @@ fn test_native_libs_tracking_hash_different_values() {
NativeLib {
name: String::from("a"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
verbatim: None,
},
NativeLib {
@ -423,13 +423,13 @@ fn test_native_libs_tracking_hash_different_values() {
NativeLib {
name: String::from("a"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
verbatim: None,
},
NativeLib {
name: String::from("b"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
verbatim: None,
},
NativeLib {
@ -445,7 +445,7 @@ fn test_native_libs_tracking_hash_different_values() {
NativeLib {
name: String::from("a"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
verbatim: None,
},
NativeLib {
@ -467,7 +467,7 @@ fn test_native_libs_tracking_hash_different_values() {
NativeLib {
name: String::from("a"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
verbatim: None,
},
NativeLib {
@ -501,7 +501,7 @@ fn test_native_libs_tracking_hash_different_order() {
NativeLib {
name: String::from("a"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
verbatim: None,
},
NativeLib {
@ -528,7 +528,7 @@ fn test_native_libs_tracking_hash_different_order() {
NativeLib {
name: String::from("a"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
verbatim: None,
},
NativeLib {
@ -549,7 +549,7 @@ fn test_native_libs_tracking_hash_different_order() {
NativeLib {
name: String::from("a"),
new_name: None,
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
verbatim: None,
},
NativeLib {

View file

@ -161,7 +161,7 @@ fn find_bundled_library(
tcx: TyCtxt<'_>,
) -> Option<Symbol> {
let sess = tcx.sess;
if let NativeLibKind::Static { bundle: Some(true) | None, whole_archive } = kind
if let NativeLibKind::Static { bundle: Some(true) | None, whole_archive, .. } = kind
&& tcx.crate_types().iter().any(|t| matches!(t, &CrateType::Rlib | CrateType::StaticLib))
&& (sess.opts.unstable_opts.packed_bundled_libs || has_cfg || whole_archive == Some(true))
{

View file

@ -53,7 +53,9 @@ fn parse_native_lib(cx: &ParseNativeLibCx<'_>, value: &str) -> NativeLib {
let NativeLibParts { kind, modifiers, name, new_name } = split_native_lib_value(value);
let kind = kind.map_or(NativeLibKind::Unspecified, |kind| match kind {
"static" => NativeLibKind::Static { bundle: None, whole_archive: None },
"static" => {
NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None }
}
"dylib" => NativeLibKind::Dylib { as_needed: None },
"framework" => NativeLibKind::Framework { as_needed: None },
"link-arg" => {
@ -105,7 +107,7 @@ fn parse_and_apply_modifier(cx: &ParseNativeLibCx<'_>, modifier: &str, native_li
Some(("-", m)) => (m, false),
_ => cx.early_dcx.early_fatal(
"invalid linking modifier syntax, expected '+' or '-' prefix \
before one of: bundle, verbatim, whole-archive, as-needed",
before one of: bundle, verbatim, whole-archive, as-needed, export-symbols",
),
};
@ -125,6 +127,13 @@ fn parse_and_apply_modifier(cx: &ParseNativeLibCx<'_>, modifier: &str, native_li
("bundle", _) => early_dcx
.early_fatal("linking modifier `bundle` is only compatible with `static` linking kind"),
("export-symbols", NativeLibKind::Static { export_symbols, .. }) => {
assign_modifier(export_symbols)
}
("export-symbols", _) => early_dcx.early_fatal(
"linking modifier `export-symbols` is only compatible with `static` linking kind",
),
("verbatim", _) => assign_modifier(&mut native_lib.verbatim),
("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
@ -151,7 +160,7 @@ fn parse_and_apply_modifier(cx: &ParseNativeLibCx<'_>, modifier: &str, native_li
_ => early_dcx.early_fatal(format!(
"unknown linking modifier `{modifier}`, expected one \
of: bundle, verbatim, whole-archive, as-needed"
of: bundle, verbatim, whole-archive, as-needed, export-symbols"
)),
}
}

View file

@ -1002,6 +1002,7 @@ symbols! {
explicit_tail_calls,
export_name,
export_stable,
export_symbols: "export-symbols",
expr,
expr_2021,
expr_fragment_specifier_2024,

View file

@ -0,0 +1 @@
void my_function() {}

View file

@ -0,0 +1,10 @@
extern "C" {
pub fn my_function();
}
#[no_mangle]
pub extern "C" fn rust_entry() {
unsafe {
my_function();
}
}

View file

@ -0,0 +1,10 @@
extern "C" {
fn my_function();
}
#[no_mangle]
pub extern "C" fn rust_entry() {
unsafe {
my_function();
}
}

View file

@ -0,0 +1,36 @@
//@ ignore-nvptx64
//@ ignore-wasm
//@ ignore-cross-compile
// FIXME:The symbol mangle rules are slightly different in Windows(32-bit) and Apple.
// Need to be resolved.
//@ ignore-windows
//@ ignore-apple
// Reason: the compiled binary is executed
use run_make_support::{build_native_static_lib, cc, dynamic_lib_name, is_darwin, llvm_nm, rustc};
fn main() {
cc().input("foo.c").arg("-c").out_exe("foo.o").run();
build_native_static_lib("foo");
rustc().input("foo.rs").arg("-lstatic=foo").crate_type("cdylib").run();
let out = llvm_nm()
.input(dynamic_lib_name("foo"))
.run()
.assert_stdout_not_contains_regex("T *my_function");
rustc().input("foo_export.rs").arg("-lstatic:+export-symbols=foo").crate_type("cdylib").run();
if is_darwin() {
let out = llvm_nm()
.input(dynamic_lib_name("foo_export"))
.run()
.assert_stdout_contains("T _my_function");
} else {
let out = llvm_nm()
.input(dynamic_lib_name("foo_export"))
.run()
.assert_stdout_contains("T my_function");
}
}

View file

@ -1,2 +1,2 @@
error: unknown linking modifier `link-arg`, expected one of: bundle, verbatim, whole-archive, as-needed
error: unknown linking modifier `link-arg`, expected one of: bundle, verbatim, whole-archive, as-needed, export-symbols

View file

@ -0,0 +1,5 @@
//@ compile-flags: -l link-arg:+export-symbols=arg -Z unstable-options
fn main() {}
//~? ERROR linking modifier `export-symbols` is only compatible with `static` linking kind

View file

@ -0,0 +1,2 @@
error: linking modifier `export-symbols` is only compatible with `static` linking kind

View file

@ -0,0 +1,7 @@
#![feature(link_arg_attribute)]
#[link(kind = "link-arg", name = "arg", modifiers = "+export-symbols")]
//~^ ERROR linking modifier `export-symbols` is only compatible with `static` linking kind
extern "C" {}
pub fn main() {}

View file

@ -0,0 +1,8 @@
error: linking modifier `export-symbols` is only compatible with `static` linking kind
--> $DIR/link-arg-from-rs2.rs:3:53
|
LL | #[link(kind = "link-arg", name = "arg", modifiers = "+export-symbols")]
| ^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -178,13 +178,13 @@ LL | #[link(name = "...", wasm_import_module())]
|
= note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed, export-symbols
--> $DIR/link-attr-validation-late.rs:31:34
|
LL | #[link(name = "...", modifiers = "")]
| ^^
error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed, export-symbols
--> $DIR/link-attr-validation-late.rs:32:34
|
LL | #[link(name = "...", modifiers = "no-plus-minus")]
@ -196,7 +196,7 @@ error[E0539]: malformed `link` attribute input
LL | #[link(name = "...", modifiers = "+unknown")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------^^
| |
| valid arguments are "bundle", "verbatim", "whole-archive" or "as-needed"
| valid arguments are "bundle", "export-symbols", "verbatim", "whole-archive" or "as-needed"
|
= note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>

View file

@ -1,2 +1,2 @@
error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed, export-symbols

View file

@ -1,2 +1,2 @@
error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed, export-symbols

View file

@ -1,2 +1,2 @@
error: unknown linking modifier ``, expected one of: bundle, verbatim, whole-archive, as-needed
error: unknown linking modifier ``, expected one of: bundle, verbatim, whole-archive, as-needed, export-symbols

View file

@ -1,2 +1,2 @@
error: unknown linking modifier `ferris`, expected one of: bundle, verbatim, whole-archive, as-needed
error: unknown linking modifier `ferris`, expected one of: bundle, verbatim, whole-archive, as-needed, export-symbols