1919// There are a variety of `#[cfg]`s controlling which targets are involved in
2020// each instance of `weak!` and `syscall!`. Rather than trying to unify all of
2121// that, we'll just allow that some unix targets don't use this module at all.
22- #![ allow( dead_code, unused_macros) ]
22+ #![ allow( dead_code, unused_macros, unused_imports ) ]
2323
2424use crate :: ffi:: CStr ;
2525use crate :: marker:: PhantomData ;
@@ -28,11 +28,12 @@ use crate::{mem, ptr};
2828
2929// We can use true weak linkage on ELF targets.
3030#[ cfg( all( unix, not( target_vendor = "apple" ) ) ) ]
31- pub ( crate ) macro weak {
32- ( fn $name: ident( $( $t: ty) , * ) -> $ret: ty) => (
31+ pub ( crate ) macro weak_impl {
32+ ( fn $name: ident( $( $t: ty) , * ) -> $ret: ty $ ( , $sym : expr ) ? ) => (
3333 let ref $name: ExternWeak <unsafe extern "C" fn( $( $t) , * ) -> $ret> = {
3434 unsafe extern "C" {
3535 #[ linkage = "extern_weak" ]
36+ $( #[ link_name = $sym] ) ?
3637 static $name: Option <unsafe extern "C" fn ( $( $t) , * ) -> $ret>;
3738 }
3839 #[ allow( unused_unsafe) ]
@@ -41,9 +42,44 @@ pub(crate) macro weak {
4142 )
4243}
4344
44- // On non-ELF targets, use the dlsym approximation of weak linkage.
45+ // On Apple targets, we use `dlsym` instead of real weak linkage, since that requires an Xcode SDK
46+ // with the item available in `*.tbd` files for the linker, and we support compiling and linking
47+ // the standard library with older Xcode versions.
4548#[ cfg( target_vendor = "apple" ) ]
46- pub( crate ) use self :: dlsym as weak ;
49+ pub ( crate ) use dlsym as weak_impl;
50+
51+ /// Try to use the symbol directly if always available, and fall back to weak linking if not.
52+ pub ( crate ) macro maybe_weak {
53+ {
54+ #[ cfg_always_available_on( $( $cfg: tt) * ) ]
55+ $( #[ link_name = $sym: expr] ) ?
56+ fn $name: ident( $( $param: ident : $t: ty) , * $( , ) ?) -> $ret: ty;
57+ } => {
58+ // If the symbol is known to be available at compile-time, use it directly.
59+ #[ cfg( $( $cfg) * ) ]
60+ let $name = {
61+ extern "C" {
62+ $( #[ link_name = $sym] ) ?
63+ fn $name( $( $param : $t) , * ) -> $ret;
64+ }
65+ Known ( $name)
66+ } ;
67+
68+ // Otherwise it needs to be weakly linked.
69+ #[ cfg( not( $( $cfg) * ) ) ]
70+ weak_impl ! ( fn $name( $( $t) , * ) -> $ret $( , $sym) ?) ;
71+ }
72+ }
73+
74+ /// The function is statically known here.
75+ pub ( crate ) struct Known < F > ( F ) ;
76+
77+ impl < F : Copy > Known < F > {
78+ #[ inline]
79+ pub ( crate ) fn get ( & self ) -> Option < F > {
80+ Some ( self . 0 )
81+ }
82+ }
4783
4884pub ( crate ) struct ExternWeak < F : Copy > {
4985 weak_ptr : Option < F > ,
@@ -145,7 +181,7 @@ unsafe fn fetch(name: &str) -> *mut libc::c_void {
145181pub ( crate ) macro syscall {
146182 ( fn $name: ident( $( $arg_name: ident: $t: ty) , * ) -> $ret: ty) => (
147183 unsafe fn $name( $( $arg_name: $t) , * ) -> $ret {
148- weak ! { fn $name( $( $t) , * ) -> $ret }
184+ weak_impl ! { fn $name( $( $t) , * ) -> $ret }
149185
150186 if let Some ( fun) = $name. get ( ) {
151187 fun ( $( $arg_name) , * )
@@ -161,7 +197,7 @@ pub(crate) macro syscall {
161197pub( crate ) macro syscall {
162198 ( fn $name: ident( $( $arg_name: ident: $t: ty) , * ) -> $ret: ty) => (
163199 unsafe fn $name( $( $arg_name: $t) , * ) -> $ret {
164- weak ! { fn $name( $( $t) , * ) -> $ret }
200+ weak_impl ! { fn $name( $( $t) , * ) -> $ret }
165201
166202 // Use a weak symbol from libc when possible, allowing `LD_PRELOAD`
167203 // interposition, but if it's not found just use a raw syscall.
0 commit comments