- У меня есть библиотека iOS, предоставляющая функцию C. Эта функция помечена видимостью по умолчанию и используется через теги атрибутов, чтобы компилятор/компоновщик не мог ее удалить
Код: Выделить всё
#ifdef __cplusplus #define DYLIB_EXPORT extern "C" __attribute__((visibility("default"))) __attribute__((used)) #else #define DYLIB_EXPORT __attribute__((visibility("default"))) __attribute__((used)) #endif DYLIB_EXPORT bool say_hello_world();Код: Выделить всё
#import "helper_functions.h" #import bool say_hello_world() { NSLog(@"Hello WORLD 🟢!"); return true; } - Из динамической библиотеки sdk я хочу вызвать эту функцию. В этом примере это библиотека Rust
Код: Выделить всё
unsafe extern "C" { fn say_hello_world() -> bool; } #[unsafe(no_mangle)] extern "C" fn sdk_init() -> i32 { unsafe { say_hello_world(); } return 0; } - Когда приложение скомпилировано и запущено из Xcode (в схемах отладки или выпуска), это работает, следующий фрагмент работает и печатает сообщение hello WORLD:
Код: Выделить всё
#import "Wrapper.h" #import "helper_functions.h" #import "sdk.h" @implementation Wrapper // This function is called on the main view controller mount + (int)initialize { NSBundle *frameworkBundle = [NSBundle bundleWithIdentifier:@"sdk"]; if (![frameworkBundle isLoaded]) { BOOL success = [frameworkBundle load]; if (!success) { return -1; } int status = sdk_init(); return status; } return 0; } @end - Однако при архивировании и загрузке в TestFlight происходит дополнительный этап удаления, который избавляет от функцииsay_hello_world. Затем динамическая библиотека аварийно завершает работу с исключением нулевого указателя:
Код: Выделить всё
Thread 3 name: Thread 3 Crashed: 0 ??? 0x0000000000000000 0x0 + 0 1 sdk 0x0000000105931ec0 0x105820000 + 1121984
Помимо фрагментов, единственный способ воспроизвести пример — с помощью полностью компилируемого приложения iOS можно создать урезанный двоичный файл, который запускается на устройстве. Поэтому я максимально сократил код, чтобы воспроизвести проблему в этом репозитории:
https://github.com/ospfranco/dylib_crash
Затем заархивируйте приложение, а затем экспортируйте его с помощью параметра отладки. Перетащите мышью в окно поиска подключенного iPhone, чтобы установить его напрямую на устройство.
Дополнительные примечания
- На форумах разработчиков Apple было некоторое обсуждение.
- Библиотека Rust была скомпилирована с дополнительными флагами, чтобы предотвратить сбой компоновщика, когда функция отсутствует во время компиляции:
Код: Выделить всё
println!("cargo:rustc-link-arg=-Wl,-U,_say_hello_world"); - Я точно знаю, что это проблема с удалением мертвого кода, потому что, если я отключу удаление мертвого кода в настройках проекта, код вообще не будет удален, что приведет к раздуванию двоичного файла, но сбой больше не произойдет. Однако это происходит только при создании распространяемого .ipa, а не при запуске непосредственно из Xcode
Подробнее здесь: https://stackoverflow.com/questions/798 ... -to-testfl