Search code examples
iosiphonexcodecmakexcframework

How do I correctly sign an xcframework that contains `.dylib` files?


I am developing a cross platform library in C++, with a C-compatible interface. While trying to compile the library for multiple Apple platforms, I have been running into issues related to signing.
The issues only appear when loading the library on a physical device, while they don't appear when working on macOS or the iOS Simulator.

The release format of this library is supposed to be an xcframework. Currently, I use CMake to build and sign each individual binary, and then I create the xcframework using this command:

xcodebuild -create-xcframework -library builds/catalyst/Release/mylib.1.1.0.dylib -headers include -library builds/macos/Release/mylib.1.1.0.dylib -headers include -library builds/ios/Release/mylib.1.1.0.dylib -headers include -library builds/ios-sim/Release/mylib.1.1.0.dylib -headers include -output Mylib.xcframework

Which results in these errors when loading the lib on device:

dyld[8339]: Library not loaded: @rpath/mylib.1.1.0.dylib
  Referenced from: <3D40ED9F-BDDA-3878-80B7-52E4C1D79471> /private/var/containers/Bundle/Application/212147E0-C36B-413C-95F0-9819D78D0F9B/BasicExample.app/Frameworks/BasedClient.framework/BasedClient
  Reason: tried: '/usr/lib/system/introspection/mylib.1.1.0.dylib' (errno=2, not in dyld cache),
 '/private/var/containers/Bundle/Application/212147E0-C36B-413C-95F0-9819D78D0F9B/BasicExample.app/Frameworks/mylib.1.1.0.dylib' (code signature invalid in <0E938CE1-2726-3C26-A057-49DAD2351627> '/private/var/containers/Bundle/Application/212147E0-C36B-413C-95F0-9819D78D0F9B/BasicExample.app/Frameworks/mylib.1.1.0.dylib' (errno=1) sliceOffset=0x00000000, codeBlobOffset=0x004F2FF0, codeBlobSize=0x0000E810),
 '/private/var/containers/Bundle/Application/212147E0-C36B-413C-95F0-9819D78D0F9B/BasicExample.app/Frameworks/mylib.1.1.0.dylib' (code signature invalid in <0E938CE1-2726-3C26-A057-49DAD2351627> '/private/var/containers/Bundle/Application/212147E0-C36B-413C-95F0-9819D78D0F9B/BasicExample.app/Frameworks/mylib.1.1.0.dylib' (errno=1) sliceOffset=0x00000000, codeBlobOffset=0x004F2FF0, codeBlobSize=0x0000E810),
 '/private/preboot/Cryptexes/OS@rpath/mylib.1.1.0.dylib' (errno=2),
 '/private/var/containers/Bundle/Application/212147E0-C36B-413C-95F0-9819D78D0F9B/BasicExample.app/Frameworks/mylib.1.1.0.dylib' (code signature invalid in <0E938CE1-2726-3C26-A057-49DAD2351627> '/private/var/containers/Bundle/Application/212147E0-C36B-413C-95F0-9819D78D0F9B/BasicExample.app/Frameworks/mylib.1.1.0.dylib' (errno=1) sliceOffset=0x00000000, codeBlobOffset=0x004F2FF0, codeBlobSize=0x0000E810),
 '/private/var/containers/Bundle/Application/212147E0-C36B-413C-95F0-9819D78D0F9B/BasicExample.app/Frameworks/mylib.1.1.0.dylib' (code signature invalid in <0E938CE1-2726-3C26-A057-49DAD2351627> '/private/var/containers/Bundle/Application/212147E0-C36B-413C-95F0-9819D78D0F9B/BasicExample.app/Frameworks/mylib.1.1.0.dylib' (errno=1) sliceOffset=0x00000000, codeBlobOffset=0x004F2FF0, codeBlobSize=0x0000E810),
 '/usr/local/lib/mylib.1.1.0.dylib' (errno=2),
 '/usr/lib/mylib.1.1.0.dylib' (errno=2, not in dyld cache)

If I inspect the individual .dylib files, they are all signed correctly.

While exploring options, I have tried following this guide, but running xcodebuild archive -project Mylib.xcodeproj -scheme Mylib -destination "generic/platform=iOS" -archivePath "archives/Mylib" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES for some reason outputs a file tree that looks like

.
└── Mylib_iOS_Simulator.xcarchive
    ├── Info.plist
    ├── Products
    │   └── @rpath
    │       └── mylib.1.1.0.dylib
    └── dSYMs

where that @rpath folder is very suspicious.


Solution

  • I'm not sure if you are creating your XCFramework in the right way. XCFramework bundle is a container of several Frameworks, and not individual libraries.

    What you want to do is to tell CMake to make a Framework for you, see here, and then glue those into a XCFramework. If you use CMake to create your Frameworks, you don't have to deal with header files, etc manually either.