Skip to content

Commit 5ec7157

Browse files
committed
Add __isOSVersionAtLeast and __isPlatformVersionAtLeast symbols
Allows users to link to Objective-C code using `@available(...)`.
1 parent bdb04d6 commit 5ec7157

File tree

12 files changed

+1125
-4
lines changed

12 files changed

+1125
-4
lines changed

compiler/rustc_symbol_mangling/src/v0.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,16 @@ pub(super) fn mangle<'tcx>(
8282
}
8383

8484
pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> String {
85-
if item_name == "rust_eh_personality" {
85+
match item_name {
8686
// rust_eh_personality must not be renamed as LLVM hard-codes the name
87-
return "rust_eh_personality".to_owned();
88-
} else if item_name == "__rust_no_alloc_shim_is_unstable" {
87+
"rust_eh_personality" => return item_name.to_owned(),
8988
// Temporary back compat hack to give people the chance to migrate to
9089
// include #[rustc_std_internal_symbol].
91-
return "__rust_no_alloc_shim_is_unstable".to_owned();
90+
"__rust_no_alloc_shim_is_unstable" => return item_name.to_owned(),
91+
// Apple availability symbols need to not be mangled to be usable by
92+
// C/Objective-C code.
93+
"__isPlatformVersionAtLeast" | "__isOSVersionAtLeast" => return item_name.to_owned(),
94+
_ => {}
9295
}
9396

9497
let prefix = "_R";

library/std/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@
347347
#![feature(hasher_prefixfree_extras)]
348348
#![feature(hashmap_internals)]
349349
#![feature(hint_must_use)]
350+
#![feature(int_from_ascii)]
350351
#![feature(ip)]
351352
#![feature(lazy_get)]
352353
#![feature(maybe_uninit_slice)]
@@ -362,6 +363,7 @@
362363
#![feature(slice_internals)]
363364
#![feature(slice_ptr_get)]
364365
#![feature(slice_range)]
366+
#![feature(slice_split_once)]
365367
#![feature(std_internals)]
366368
#![feature(str_internals)]
367369
#![feature(strict_provenance_atomic_ptr)]

library/std/src/sys/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub mod io;
2121
pub mod net;
2222
pub mod os_str;
2323
pub mod path;
24+
pub mod platform_version;
2425
pub mod process;
2526
pub mod random;
2627
pub mod stdio;
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
//! Minimal utilities for interfacing with a dynamically loaded CoreFoundation.
2+
#![allow(non_snake_case, non_upper_case_globals)]
3+
use super::root_relative;
4+
use crate::ffi::{CStr, c_char, c_void};
5+
use crate::ptr::null_mut;
6+
use crate::sys::common::small_c_string::run_path_with_cstr;
7+
8+
// MacTypes.h
9+
pub(super) type Boolean = u8;
10+
// CoreFoundation/CFBase.h
11+
pub(super) type CFTypeID = usize;
12+
pub(super) type CFOptionFlags = usize;
13+
pub(super) type CFIndex = isize;
14+
pub(super) type CFTypeRef = *mut c_void;
15+
pub(super) type CFAllocatorRef = CFTypeRef;
16+
pub(super) const kCFAllocatorDefault: CFAllocatorRef = null_mut();
17+
// CoreFoundation/CFError.h
18+
pub(super) type CFErrorRef = CFTypeRef;
19+
// CoreFoundation/CFData.h
20+
pub(super) type CFDataRef = CFTypeRef;
21+
// CoreFoundation/CFPropertyList.h
22+
pub(super) const kCFPropertyListImmutable: CFOptionFlags = 0;
23+
pub(super) type CFPropertyListFormat = CFIndex;
24+
pub(super) type CFPropertyListRef = CFTypeRef;
25+
// CoreFoundation/CFString.h
26+
pub(super) type CFStringRef = CFTypeRef;
27+
pub(super) type CFStringEncoding = u32;
28+
pub(super) const kCFStringEncodingUTF8: CFStringEncoding = 0x08000100;
29+
// CoreFoundation/CFDictionary.h
30+
pub(super) type CFDictionaryRef = CFTypeRef;
31+
32+
/// An open handle to the dynamically loaded CoreFoundation framework.
33+
///
34+
/// This is `dlopen`ed, and later `dlclose`d. This is done to try to avoid
35+
/// "leaking" the CoreFoundation symbols to the rest of the user's binary if
36+
/// they decided to not link CoreFoundation themselves.
37+
///
38+
/// It is also faster to look up symbols directly via this handle than with
39+
/// `RTLD_DEFAULT`.
40+
pub(super) struct CFHandle(*mut c_void);
41+
42+
macro_rules! dlsym_fn {
43+
(
44+
unsafe fn $name:ident($($param:ident: $param_ty:ty),* $(,)?) $(-> $ret:ty)?;
45+
) => {
46+
pub(super) unsafe fn $name(&self, $($param: $param_ty),*) $(-> $ret)? {
47+
let ptr = unsafe {
48+
libc::dlsym(
49+
self.0,
50+
concat!(stringify!($name), '\0').as_bytes().as_ptr().cast(),
51+
)
52+
};
53+
if ptr.is_null() {
54+
let err = unsafe { CStr::from_ptr(libc::dlerror()) };
55+
panic!("could not find function {}: {err:?}", stringify!($name));
56+
}
57+
58+
// SAFETY: Just checked that the symbol isn't NULL, and macro invoker verifies that
59+
// the signature is correct.
60+
let fnptr = unsafe {
61+
crate::mem::transmute::<
62+
*mut c_void,
63+
unsafe extern "C" fn($($param_ty),*) $(-> $ret)?,
64+
>(ptr)
65+
};
66+
67+
// SAFETY: Upheld by caller.
68+
unsafe { fnptr($($param),*) }
69+
}
70+
};
71+
}
72+
73+
impl CFHandle {
74+
/// Link to the CoreFoundation dylib, and look up symbols from that.
75+
pub(super) fn new() -> Self {
76+
// We explicitly use non-versioned path here, to allow this to work on older iOS devices.
77+
let cf_path =
78+
root_relative("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation");
79+
80+
let handle = run_path_with_cstr(&cf_path, &|path| unsafe {
81+
Ok(libc::dlopen(path.as_ptr(), libc::RTLD_LAZY | libc::RTLD_LOCAL))
82+
})
83+
.expect("failed allocating string");
84+
85+
if handle.is_null() {
86+
let err = unsafe { CStr::from_ptr(libc::dlerror()) };
87+
panic!("could not open CoreFoundation.framework: {err:?}");
88+
}
89+
90+
Self(handle)
91+
}
92+
93+
pub(super) fn kCFAllocatorNull(&self) -> CFAllocatorRef {
94+
// Available: in all CF versions.
95+
let static_ptr = unsafe { libc::dlsym(self.0, c"kCFAllocatorNull".as_ptr()) };
96+
if static_ptr.is_null() {
97+
let err = unsafe { CStr::from_ptr(libc::dlerror()) };
98+
panic!("could not find kCFAllocatorNull: {err:?}");
99+
}
100+
unsafe { *static_ptr.cast() }
101+
}
102+
103+
// CoreFoundation/CFBase.h
104+
dlsym_fn!(
105+
// Available: in all CF versions.
106+
unsafe fn CFRelease(cf: CFTypeRef);
107+
);
108+
dlsym_fn!(
109+
// Available: in all CF versions.
110+
unsafe fn CFGetTypeID(cf: CFTypeRef) -> CFTypeID;
111+
);
112+
113+
// CoreFoundation/CFData.h
114+
dlsym_fn!(
115+
// Available: in all CF versions.
116+
unsafe fn CFDataCreateWithBytesNoCopy(
117+
allocator: CFAllocatorRef,
118+
bytes: *const u8,
119+
length: CFIndex,
120+
bytes_deallocator: CFAllocatorRef,
121+
) -> CFDataRef;
122+
);
123+
124+
// CoreFoundation/CFPropertyList.h
125+
dlsym_fn!(
126+
// Available: since macOS 10.6.
127+
unsafe fn CFPropertyListCreateWithData(
128+
allocator: CFAllocatorRef,
129+
data: CFDataRef,
130+
options: CFOptionFlags,
131+
format: *mut CFPropertyListFormat,
132+
error: *mut CFErrorRef,
133+
) -> CFPropertyListRef;
134+
);
135+
136+
// CoreFoundation/CFString.h
137+
dlsym_fn!(
138+
// Available: in all CF versions.
139+
unsafe fn CFStringGetTypeID() -> CFTypeID;
140+
);
141+
dlsym_fn!(
142+
// Available: in all CF versions.
143+
unsafe fn CFStringCreateWithCStringNoCopy(
144+
alloc: CFAllocatorRef,
145+
c_str: *const c_char,
146+
encoding: CFStringEncoding,
147+
contents_deallocator: CFAllocatorRef,
148+
) -> CFStringRef;
149+
);
150+
dlsym_fn!(
151+
// Available: in all CF versions.
152+
unsafe fn CFStringGetCString(
153+
the_string: CFStringRef,
154+
buffer: *mut c_char,
155+
buffer_size: CFIndex,
156+
encoding: CFStringEncoding,
157+
) -> Boolean;
158+
);
159+
160+
// CoreFoundation/CFDictionary.h
161+
dlsym_fn!(
162+
// Available: in all CF versions.
163+
unsafe fn CFDictionaryGetTypeID() -> CFTypeID;
164+
);
165+
dlsym_fn!(
166+
// Available: in all CF versions.
167+
unsafe fn CFDictionaryGetValue(
168+
the_dict: CFDictionaryRef,
169+
key: *const c_void,
170+
) -> *const c_void;
171+
);
172+
}
173+
174+
impl Drop for CFHandle {
175+
fn drop(&mut self) {
176+
// Ignore errors when closing. This is also what `libloading` does:
177+
// https://docs.rs/libloading/0.8.6/src/libloading/os/unix/mod.rs.html#374
178+
let _ = unsafe { libc::dlclose(self.0) };
179+
}
180+
}

0 commit comments

Comments
 (0)