У меня есть библиотека iOS, предоставляющая функцию C. Эта функция помечена видимостью по умолчанию и используется через теги атрибутов, чтобы компилятор/компоновщик не мог ее удалить
Когда приложение скомпилировано и запущено из 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. Затем динамическая библиотека аварийно завершает работу с исключением нулевого указателя:
Минимальный воспроизводимый пример
Помимо фрагментов, единственный способ воспроизвести пример — с помощью полностью компилируемого приложения iOS можно создать урезанный двоичный файл, который запускается на устройстве. Поэтому я максимально сократил код, чтобы воспроизвести проблему в этом репозитории: https://github.com/ospfranco/dylib_crash
Затем заархивируйте приложение, а затем экспортируйте его с помощью параметра отладки. Перетащите мышью в окно поиска подключенного iPhone, чтобы установить его напрямую на устройство.
Дополнительные примечания
На форумах разработчиков Apple было некоторое обсуждение.
Библиотека Rust была скомпилирована с дополнительными флагами, чтобы предотвратить сбой компоновщика, когда функция отсутствует во время компиляции:
Я точно знаю, что это проблема с удалением мертвого кода, потому что, если я отключу удаление мертвого кода в настройках проекта, код вообще не будет удален, что приведет к раздуванию двоичного файла, но сбой больше не произойдет. Однако это происходит только при создании распространяемого .ipa, а не при запуске непосредственно из Xcode
[list] [*]У меня есть библиотека iOS, предоставляющая функцию C. Эта функция помечена видимостью по умолчанию и используется через теги атрибутов, чтобы компилятор/компоновщик не мог ее удалить [code]#ifdef __cplusplus #define DYLIB_EXPORT extern "C" __attribute__((visibility("default"))) __attribute__((used)) #else #define DYLIB_EXPORT __attribute__((visibility("default"))) __attribute__((used)) #endif
bool say_hello_world() { NSLog(@"Hello WORLD 🟢!"); return true; } [/code]
[*]Из динамической библиотеки sdk я хочу вызвать эту функцию. В этом примере это библиотека Rust [code]unsafe extern "C" { fn say_hello_world() -> bool; }
[*]Когда приложение скомпилировано и запущено из Xcode (в схемах отладки или выпуска), это работает, следующий фрагмент работает и печатает сообщение hello WORLD: [code] #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 [/code]
[*]Однако при архивировании и загрузке в TestFlight происходит дополнительный этап удаления, который избавляет от функцииsay_hello_world. Затем динамическая библиотека аварийно завершает работу с исключением нулевого указателя: [code]Thread 3 name: Thread 3 Crashed: 0 ??? 0x0000000000000000 0x0 + 0 1 sdk 0x0000000105931ec0 0x105820000 + 1121984 [/code]
[/list] Минимальный воспроизводимый пример Помимо фрагментов, единственный способ воспроизвести пример — с помощью полностью компилируемого приложения iOS можно создать урезанный двоичный файл, который запускается на устройстве. Поэтому я максимально сократил код, чтобы воспроизвести проблему в этом репозитории: https://github.com/ospfranco/dylib_crash Затем заархивируйте приложение, а затем экспортируйте его с помощью параметра отладки. Перетащите мышью в окно поиска подключенного iPhone, чтобы установить его напрямую на устройство. Дополнительные примечания [list] [*]На форумах разработчиков Apple было некоторое обсуждение. [*]Библиотека Rust была скомпилирована с дополнительными флагами, чтобы предотвратить сбой компоновщика, когда функция отсутствует во время компиляции: [code]println!("cargo:rustc-link-arg=-Wl,-U,_say_hello_world"); [/code]
[*]Я точно знаю, что это проблема с удалением мертвого кода, потому что, если я отключу удаление мертвого кода в настройках проекта, код вообще не будет удален, что приведет к раздуванию двоичного файла, но сбой больше не произойдет. Однако это происходит только при создании распространяемого .ipa, а не при запуске непосредственно из Xcode [/list]