support link modifier as-needed for raw-dylib-elf

This commit is contained in:
usamoi
2025-08-26 16:24:29 +08:00
parent 839222065a
commit 21dd997aec
8 changed files with 82 additions and 31 deletions

View File

@@ -1,5 +1,5 @@
attr_parsing_as_needed_compatibility = attr_parsing_as_needed_compatibility =
linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds linking modifier `as-needed` is only compatible with `dylib`, `framework` and `raw-dylib` linking kinds
attr_parsing_bundle_needs_static = attr_parsing_bundle_needs_static =
linking modifier `bundle` is only compatible with `static` linking kind linking modifier `bundle` is only compatible with `static` linking kind

View File

@@ -180,7 +180,8 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
} }
(sym::as_dash_needed, Some(NativeLibKind::Dylib { as_needed })) (sym::as_dash_needed, Some(NativeLibKind::Dylib { as_needed }))
| (sym::as_dash_needed, Some(NativeLibKind::Framework { as_needed })) => { | (sym::as_dash_needed, Some(NativeLibKind::Framework { as_needed }))
| (sym::as_dash_needed, Some(NativeLibKind::RawDylib { as_needed })) => {
report_unstable_modifier!(native_link_modifiers_as_needed); report_unstable_modifier!(native_link_modifiers_as_needed);
assign_modifier(as_needed) assign_modifier(as_needed)
} }
@@ -219,12 +220,12 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
// Do this outside of the loop so that `import_name_type` can be specified before `kind`. // Do this outside of the loop so that `import_name_type` can be specified before `kind`.
if let Some((_, span)) = import_name_type { if let Some((_, span)) = import_name_type {
if kind != Some(NativeLibKind::RawDylib) { if !matches!(kind, Some(NativeLibKind::RawDylib { .. })) {
cx.emit_err(ImportNameTypeRaw { span }); cx.emit_err(ImportNameTypeRaw { span });
} }
} }
if let Some(NativeLibKind::RawDylib) = kind if let Some(NativeLibKind::RawDylib { .. }) = kind
&& name.as_str().contains('\0') && name.as_str().contains('\0')
{ {
cx.emit_err(RawDylibNoNul { span: name_span }); cx.emit_err(RawDylibNoNul { span: name_span });
@@ -315,7 +316,7 @@ impl LinkParser {
cx.emit_err(RawDylibOnlyWindows { span: nv.value_span }); cx.emit_err(RawDylibOnlyWindows { span: nv.value_span });
} }
NativeLibKind::RawDylib NativeLibKind::RawDylib { as_needed: None }
} }
sym::link_dash_arg => { sym::link_dash_arg => {
if !features.link_arg_attribute() { if !features.link_arg_attribute() {

View File

@@ -1490,7 +1490,7 @@ fn print_native_static_libs(
NativeLibKind::Static { bundle: None | Some(true), .. } NativeLibKind::Static { bundle: None | Some(true), .. }
| NativeLibKind::LinkArg | NativeLibKind::LinkArg
| NativeLibKind::WasmImportModule | NativeLibKind::WasmImportModule
| NativeLibKind::RawDylib => None, | NativeLibKind::RawDylib { .. } => None,
} }
}) })
// deduplication of consecutive repeated libraries, see rust-lang/rust#113209 // deduplication of consecutive repeated libraries, see rust-lang/rust#113209
@@ -2364,13 +2364,13 @@ fn linker_with_args(
cmd.add_object(&output_path); cmd.add_object(&output_path);
} }
} else { } else {
for link_path in raw_dylib::create_raw_dylib_elf_stub_shared_objects( for (link_path, as_needed) in raw_dylib::create_raw_dylib_elf_stub_shared_objects(
sess, sess,
codegen_results.crate_info.used_libraries.iter(), codegen_results.crate_info.used_libraries.iter(),
&raw_dylib_dir, &raw_dylib_dir,
) { ) {
// Always use verbatim linkage, see comments in create_raw_dylib_elf_stub_shared_objects. // Always use verbatim linkage, see comments in create_raw_dylib_elf_stub_shared_objects.
cmd.link_dylib_by_name(&link_path, true, false); cmd.link_dylib_by_name(&link_path, true, as_needed);
} }
} }
// As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case // As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
@@ -2411,13 +2411,13 @@ fn linker_with_args(
cmd.add_object(&output_path); cmd.add_object(&output_path);
} }
} else { } else {
for link_path in raw_dylib::create_raw_dylib_elf_stub_shared_objects( for (link_path, as_needed) in raw_dylib::create_raw_dylib_elf_stub_shared_objects(
sess, sess,
native_libraries_from_nonstatics, native_libraries_from_nonstatics,
&raw_dylib_dir, &raw_dylib_dir,
) { ) {
// Always use verbatim linkage, see comments in create_raw_dylib_elf_stub_shared_objects. // Always use verbatim linkage, see comments in create_raw_dylib_elf_stub_shared_objects.
cmd.link_dylib_by_name(&link_path, true, false); cmd.link_dylib_by_name(&link_path, true, as_needed);
} }
} }
@@ -2726,7 +2726,7 @@ fn add_native_libs_from_crate(
cmd.link_framework_by_name(name, verbatim, as_needed.unwrap_or(true)) cmd.link_framework_by_name(name, verbatim, as_needed.unwrap_or(true))
} }
} }
NativeLibKind::RawDylib => { NativeLibKind::RawDylib { as_needed: _ } => {
// Handled separately in `linker_with_args`. // Handled separately in `linker_with_args`.
} }
NativeLibKind::WasmImportModule => {} NativeLibKind::WasmImportModule => {}

View File

@@ -31,7 +31,7 @@ fn collate_raw_dylibs_windows<'a>(
let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default(); let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default();
for lib in used_libraries { for lib in used_libraries {
if lib.kind == NativeLibKind::RawDylib { if let NativeLibKind::RawDylib { .. } = lib.kind {
let ext = if lib.verbatim { "" } else { ".dll" }; let ext = if lib.verbatim { "" } else { ".dll" };
let name = format!("{}{}", lib.name, ext); let name = format!("{}{}", lib.name, ext);
let imports = dylib_table.entry(name.clone()).or_default(); let imports = dylib_table.entry(name.clone()).or_default();
@@ -128,12 +128,12 @@ pub(super) fn create_raw_dylib_dll_import_libs<'a>(
fn collate_raw_dylibs_elf<'a>( fn collate_raw_dylibs_elf<'a>(
sess: &Session, sess: &Session,
used_libraries: impl IntoIterator<Item = &'a NativeLib>, used_libraries: impl IntoIterator<Item = &'a NativeLib>,
) -> Vec<(String, Vec<DllImport>)> { ) -> Vec<(String, Vec<DllImport>, bool)> {
// Use index maps to preserve original order of imports and libraries. // Use index maps to preserve original order of imports and libraries.
let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default(); let mut dylib_table = FxIndexMap::<String, (FxIndexMap<Symbol, &DllImport>, bool)>::default();
for lib in used_libraries { for lib in used_libraries {
if lib.kind == NativeLibKind::RawDylib { if let NativeLibKind::RawDylib { as_needed } = lib.kind {
let filename = if lib.verbatim { let filename = if lib.verbatim {
lib.name.as_str().to_owned() lib.name.as_str().to_owned()
} else { } else {
@@ -142,17 +142,19 @@ fn collate_raw_dylibs_elf<'a>(
format!("{prefix}{}{ext}", lib.name) format!("{prefix}{}{ext}", lib.name)
}; };
let imports = dylib_table.entry(filename.clone()).or_default(); let (stub_imports, stub_as_needed) =
dylib_table.entry(filename.clone()).or_insert((Default::default(), true));
for import in &lib.dll_imports { for import in &lib.dll_imports {
imports.insert(import.name, import); stub_imports.insert(import.name, import);
} }
*stub_as_needed = *stub_as_needed && as_needed.unwrap_or(true);
} }
} }
sess.dcx().abort_if_errors(); sess.dcx().abort_if_errors();
dylib_table dylib_table
.into_iter() .into_iter()
.map(|(name, imports)| { .map(|(name, (imports, as_needed))| {
(name, imports.into_iter().map(|(_, import)| import.clone()).collect()) (name, imports.into_iter().map(|(_, import)| import.clone()).collect(), as_needed)
}) })
.collect() .collect()
} }
@@ -161,10 +163,10 @@ pub(super) fn create_raw_dylib_elf_stub_shared_objects<'a>(
sess: &Session, sess: &Session,
used_libraries: impl IntoIterator<Item = &'a NativeLib>, used_libraries: impl IntoIterator<Item = &'a NativeLib>,
raw_dylib_so_dir: &Path, raw_dylib_so_dir: &Path,
) -> Vec<String> { ) -> Vec<(String, bool)> {
collate_raw_dylibs_elf(sess, used_libraries) collate_raw_dylibs_elf(sess, used_libraries)
.into_iter() .into_iter()
.map(|(load_filename, raw_dylib_imports)| { .map(|(load_filename, raw_dylib_imports, as_needed)| {
use std::hash::Hash; use std::hash::Hash;
// `load_filename` is the *target/loader* filename that will end up in NEEDED. // `load_filename` is the *target/loader* filename that will end up in NEEDED.
@@ -205,7 +207,7 @@ pub(super) fn create_raw_dylib_elf_stub_shared_objects<'a>(
}); });
}; };
temporary_lib_name (temporary_lib_name, as_needed)
}) })
.collect() .collect()
} }

View File

@@ -309,7 +309,10 @@ pub enum NativeLibKind {
}, },
/// Dynamic library (e.g. `foo.dll` on Windows) without a corresponding import library. /// Dynamic library (e.g. `foo.dll` on Windows) without a corresponding import library.
/// On Linux, it refers to a generated shared library stub. /// On Linux, it refers to a generated shared library stub.
RawDylib, RawDylib {
/// Whether the dynamic library will be linked only if it satisfies some undefined symbols
as_needed: Option<bool>,
},
/// A macOS-specific kind of dynamic libraries. /// A macOS-specific kind of dynamic libraries.
Framework { Framework {
/// Whether the framework will be linked only if it satisfies some undefined symbols /// Whether the framework will be linked only if it satisfies some undefined symbols
@@ -332,11 +335,10 @@ impl NativeLibKind {
NativeLibKind::Static { bundle, whole_archive } => { NativeLibKind::Static { bundle, whole_archive } => {
bundle.is_some() || whole_archive.is_some() bundle.is_some() || whole_archive.is_some()
} }
NativeLibKind::Dylib { as_needed } | NativeLibKind::Framework { as_needed } => { NativeLibKind::Dylib { as_needed }
as_needed.is_some() | NativeLibKind::Framework { as_needed }
} | NativeLibKind::RawDylib { as_needed } => as_needed.is_some(),
NativeLibKind::RawDylib NativeLibKind::Unspecified
| NativeLibKind::Unspecified
| NativeLibKind::LinkArg | NativeLibKind::LinkArg
| NativeLibKind::WasmImportModule => false, | NativeLibKind::WasmImportModule => false,
} }
@@ -349,7 +351,9 @@ impl NativeLibKind {
pub fn is_dllimport(&self) -> bool { pub fn is_dllimport(&self) -> bool {
matches!( matches!(
self, self,
NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified NativeLibKind::Dylib { .. }
| NativeLibKind::RawDylib { .. }
| NativeLibKind::Unspecified
) )
} }
} }

View File

@@ -218,7 +218,7 @@ impl<'tcx> Collector<'tcx> {
.flatten() .flatten()
{ {
let dll_imports = match attr.kind { let dll_imports = match attr.kind {
NativeLibKind::RawDylib => foreign_items NativeLibKind::RawDylib { .. } => foreign_items
.iter() .iter()
.map(|&child_item| { .map(|&child_item| {
self.build_dll_import( self.build_dll_import(

View File

@@ -135,7 +135,8 @@ fn parse_and_apply_modifier(cx: &ParseNativeLibCx<'_>, modifier: &str, native_li
), ),
("as-needed", NativeLibKind::Dylib { as_needed }) ("as-needed", NativeLibKind::Dylib { as_needed })
| ("as-needed", NativeLibKind::Framework { as_needed }) => { | ("as-needed", NativeLibKind::Framework { as_needed })
| ("as-needed", NativeLibKind::RawDylib { as_needed }) => {
cx.on_unstable_value( cx.on_unstable_value(
"linking modifier `as-needed` is unstable", "linking modifier `as-needed` is unstable",
", the `-Z unstable-options` flag must also be passed to use it", ", the `-Z unstable-options` flag must also be passed to use it",

View File

@@ -0,0 +1,43 @@
//@ only-elf
//@ needs-dynamic-linking
//@ only-gnu
//@ only-x86_64
//@ revisions: as_needed no_as_needed no_modifier merge_1 merge_2 merge_3 merge_4
//@ [as_needed] run-pass
//@ [no_as_needed] run-fail
//@ [no_modifier] run-pass
//@ [merge_1] run-fail
//@ [merge_2] run-fail
//@ [merge_3] run-fail
//@ [merge_4] run-pass
#![allow(incomplete_features)]
#![feature(raw_dylib_elf)]
#![feature(native_link_modifiers_as_needed)]
#[cfg_attr(
as_needed,
link(name = "taiqannf1y28z2rw", kind = "raw-dylib", modifiers = "+as-needed")
)]
#[cfg_attr(
no_as_needed,
link(name = "taiqannf1y28z2rw", kind = "raw-dylib", modifiers = "-as-needed")
)]
#[cfg_attr(no_modifier, link(name = "taiqannf1y28z2rw", kind = "raw-dylib"))]
unsafe extern "C" {}
#[cfg_attr(merge_1, link(name = "k9nm7qxoa79bg7e6", kind = "raw-dylib", modifiers = "+as-needed"))]
#[cfg_attr(merge_2, link(name = "k9nm7qxoa79bg7e6", kind = "raw-dylib", modifiers = "-as-needed"))]
#[cfg_attr(merge_3, link(name = "k9nm7qxoa79bg7e6", kind = "raw-dylib", modifiers = "-as-needed"))]
#[cfg_attr(merge_4, link(name = "k9nm7qxoa79bg7e6", kind = "raw-dylib", modifiers = "+as-needed"))]
unsafe extern "C" {}
#[cfg_attr(merge_1, link(name = "k9nm7qxoa79bg7e6", kind = "raw-dylib", modifiers = "-as-needed"))]
#[cfg_attr(merge_2, link(name = "k9nm7qxoa79bg7e6", kind = "raw-dylib", modifiers = "+as-needed"))]
#[cfg_attr(merge_3, link(name = "k9nm7qxoa79bg7e6", kind = "raw-dylib", modifiers = "-as-needed"))]
#[cfg_attr(merge_4, link(name = "k9nm7qxoa79bg7e6", kind = "raw-dylib", modifiers = "+as-needed"))]
unsafe extern "C" {}
fn main() {}