Skip to content

Commit 4350550

Browse files
committed
Use _NSGetArgc/_NSGetArgv on iOS/tvOS/watchOS/visionOS
If we're comfortable using `_NSGetEnviron` from `crt_externs.h`, there shouldn't be an issue with using these either, and then we can merge with the macOS implementation. This also fixes two test cases on Mac Catalyst: - `tests/ui/command/command-argv0.rs`, maybe because `[[NSProcessInfo processInfo] arguments]` somehow converts the name of the first argument? - `tests/ui/env-funky-keys.rs` since we no longer link to Foundation.
1 parent 30e2e43 commit 4350550

File tree

2 files changed

+19
-84
lines changed

2 files changed

+19
-84
lines changed

std/src/sys/pal/unix/args.rs

+14-78
Original file line numberDiff line numberDiff line change
@@ -168,16 +168,28 @@ mod imp {
168168
}
169169
}
170170

171+
// Use `_NSGetArgc` and `_NSGetArgv` on Apple platforms.
172+
//
173+
// Even though these have underscores in their names, they've been available
174+
// since since the first versions of both macOS and iOS, and are declared in
175+
// the header `crt_externs.h`.
176+
//
177+
// NOTE: This header was added to the iOS 13.0 SDK, which has been the source
178+
// of a great deal of confusion in the past about the availability of these
179+
// APIs.
180+
//
181+
// NOTE(madsmtm): This has not strictly been verified to not cause App Store
182+
// rejections; if this is found to be the case, the previous implementation
183+
// of this used `[[NSProcessInfo processInfo] arguments]`.
171184
#[cfg(target_vendor = "apple")]
172185
mod imp {
173186
use super::Args;
174187
use crate::ffi::CStr;
188+
use crate::os::unix::prelude::*;
175189

176190
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
177191

178-
#[cfg(target_os = "macos")]
179192
pub fn args() -> Args {
180-
use crate::os::unix::prelude::*;
181193
extern "C" {
182194
// These functions are in crt_externs.h.
183195
fn _NSGetArgc() -> *mut libc::c_int;
@@ -196,82 +208,6 @@ mod imp {
196208
};
197209
Args { iter: vec.into_iter() }
198210
}
199-
200-
// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
201-
// and use underscores in their names - they're most probably
202-
// are considered private and therefore should be avoided.
203-
// Here is another way to get arguments using the Objective-C
204-
// runtime.
205-
//
206-
// In general it looks like:
207-
// res = Vec::new()
208-
// let args = [[NSProcessInfo processInfo] arguments]
209-
// for i in (0..[args count])
210-
// res.push([args objectAtIndex:i])
211-
// res
212-
#[cfg(not(target_os = "macos"))]
213-
pub fn args() -> Args {
214-
use crate::ffi::{c_char, c_void, OsString};
215-
use crate::mem;
216-
use crate::str;
217-
218-
type Sel = *const c_void;
219-
type NsId = *const c_void;
220-
type NSUInteger = usize;
221-
222-
extern "C" {
223-
fn sel_registerName(name: *const c_char) -> Sel;
224-
fn objc_getClass(class_name: *const c_char) -> NsId;
225-
226-
// This must be transmuted to an appropriate function pointer type before being called.
227-
fn objc_msgSend();
228-
}
229-
230-
const MSG_SEND_PTR: unsafe extern "C" fn() = objc_msgSend;
231-
const MSG_SEND_NO_ARGUMENTS_RETURN_PTR: unsafe extern "C" fn(NsId, Sel) -> *const c_void =
232-
unsafe { mem::transmute(MSG_SEND_PTR) };
233-
const MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER: unsafe extern "C" fn(
234-
NsId,
235-
Sel,
236-
) -> NSUInteger = unsafe { mem::transmute(MSG_SEND_PTR) };
237-
const MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR: unsafe extern "C" fn(
238-
NsId,
239-
Sel,
240-
NSUInteger,
241-
)
242-
-> *const c_void = unsafe { mem::transmute(MSG_SEND_PTR) };
243-
244-
let mut res = Vec::new();
245-
246-
unsafe {
247-
let process_info_sel = sel_registerName(c"processInfo".as_ptr());
248-
let arguments_sel = sel_registerName(c"arguments".as_ptr());
249-
let count_sel = sel_registerName(c"count".as_ptr());
250-
let object_at_index_sel = sel_registerName(c"objectAtIndex:".as_ptr());
251-
let utf8string_sel = sel_registerName(c"UTF8String".as_ptr());
252-
253-
let klass = objc_getClass(c"NSProcessInfo".as_ptr());
254-
// `+[NSProcessInfo processInfo]` returns an object with +0 retain count, so no need to manually `retain/release`.
255-
let info = MSG_SEND_NO_ARGUMENTS_RETURN_PTR(klass, process_info_sel);
256-
257-
// `-[NSProcessInfo arguments]` returns an object with +0 retain count, so no need to manually `retain/release`.
258-
let args = MSG_SEND_NO_ARGUMENTS_RETURN_PTR(info, arguments_sel);
259-
260-
let cnt = MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER(args, count_sel);
261-
for i in 0..cnt {
262-
// `-[NSArray objectAtIndex:]` returns an object whose lifetime is tied to the array, so no need to manually `retain/release`.
263-
let ns_string =
264-
MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR(args, object_at_index_sel, i);
265-
// The lifetime of this pointer is tied to the NSString, as well as the current autorelease pool, which is why we heap-allocate the string below.
266-
let utf_c_str: *const c_char =
267-
MSG_SEND_NO_ARGUMENTS_RETURN_PTR(ns_string, utf8string_sel).cast();
268-
let bytes = CStr::from_ptr(utf_c_str).to_bytes();
269-
res.push(OsString::from(str::from_utf8(bytes).unwrap()))
270-
}
271-
}
272-
273-
Args { iter: res.into_iter() }
274-
}
275211
}
276212

277213
#[cfg(any(target_os = "espidf", target_os = "vita"))]

std/src/sys/pal/unix/mod.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -399,14 +399,13 @@ cfg_if::cfg_if! {
399399
// Use libumem for the (malloc-compatible) allocator
400400
#[link(name = "umem")]
401401
extern "C" {}
402-
} else if #[cfg(target_os = "macos")] {
402+
} else if #[cfg(target_vendor = "apple")] {
403+
// Link to `libSystem.dylib`.
404+
//
405+
// Don't get confused by the presence of `System.framework`,
406+
// it is a deprecated wrapper over the dynamic library.
403407
#[link(name = "System")]
404408
extern "C" {}
405-
} else if #[cfg(all(target_vendor = "apple", not(target_os = "macos")))] {
406-
#[link(name = "System")]
407-
#[link(name = "objc")]
408-
#[link(name = "Foundation", kind = "framework")]
409-
extern "C" {}
410409
} else if #[cfg(target_os = "fuchsia")] {
411410
#[link(name = "zircon")]
412411
#[link(name = "fdio")]

0 commit comments

Comments
 (0)