Reputation: 11112
I'm building a dynamic framework from source for iOS with bitcode enabled (using cmake
and xcodebuild
). I use lipo
and install_name_tool
to make a fat binary and update LC_ID_DYLIB
, for binary to be loaded correctly. When I archive the application, the framework is correctly signed and packaged with the application. This is the output of file
:
MyFramework: Mach-O universal binary with 3 architectures: [arm_v7: Mach-O dynamically linked shared library arm_v7] [arm_v7s] [arm64]
MyFramework (for architecture armv7): Mach-O dynamically linked shared library arm_v7
MyFramework (for architecture armv7s): Mach-O dynamically linked shared library arm_v7s
MyFramework (for architecture arm64): Mach-O 64-bit dynamically linked shared library arm64
Looking at otool -l
output for LC_ID_DYLIB
shows this:
Load command 4
cmd LC_ID_DYLIB
cmdsize 64
name @rpath/MyFramework.framework/MyFramework (offset 24)
time stamp 1 Thu Jan 1 01:00:01 1970
current version 1.0.0
compatibility version 1.0.0
It all seems correct. If I upload this archive to App Store, it gets uploaded and processed correctly. After running it from App Store, it crashes right after start, due to loading dynamic frameworks. It is known that apps get recompiled from Bitcode on App Store, so I simulated that by exporting as Ad-Hoc and leaving "Rebuild from Bitcode" option enabled as suggested in Technical Note TN2432. Inspecting the .ipa (which also crashed after start) and the framework in question, this is the output of otool -l
:
Load command 3
cmd LC_ID_DYLIB
cmdsize 128
name /Users/legoless/Downloads/ios/build/build-iphoneos/lib/Release/MyFramework_ios.framework/MyFramework_ios (offset 24)
time stamp 1 Thu Jan 1 01:00:01 1970
current version 1.0.0
compatibility version 1.0.0
So obviously the LC_ID_DYLIB
of this library is incorrect and this the absolute path to the location where the framework was originally built, before making a fat binary. This is replaced at the Rebuild from Bitcode step, but I have no idea why or even where this path is stored in the existing Mach-O file. I used both otool
and objdump
tools to try to find the reference in the Mach-O binary, with no luck.
In practice, another framework depends on this one and this is the load command for the target framework:
Load command 14
cmd LC_LOAD_DYLIB
cmdsize 64
name @rpath/MyFramework.framework/MyFramework (offset 24)
time stamp 2 Thu Jan 1 01:00:02 1970
current version 1.0.0
compatibility version 1.0.0
Again after Rebuild with Bitcode, the reference gets changed here as well:
Load command 13
cmd LC_LOAD_DYLIB
cmdsize 128
name /Users/legoless/Downloads/ios/build/build-iphoneos/lib/Release/MyFramework_ios.framework/MyFramework_ios (offset 24)
time stamp 2 Thu Jan 1 01:00:02 1970
current version 1.0.0
compatibility version 1.0.0
This only happens for the framework in question, but not for other frameworks, where @rpath
is left as it was.
My question still remains:
Where is this absolute path reference stored? And how to remove it, so Rebuild from Bitcode does not affect it anymore?
Thank you!
Upvotes: 5
Views: 1059
Reputation: 172
I was experiencing exactly the same issue. The accepted answer got me close, but setting the INSTALL_NAME_DIR
parameter by itself didn't fix it as it doesn't allow you to set the complete value passed to the linker as install_name (only the directory, as you might expect).
Instead I set XCODE_ATTRIBUTE_LD_DYLIB_INSTALL_NAME
which overwrites the complete value in one go. Obviously this only works on the XCode generator in CMake, but this was fine for what I wanted. To summarise, my CMake file for this framework now contains:
set_target_properties(${LIBRARY_NAME} PROPERTIES XCODE_ATTRIBUTE_LD_DYLIB_INSTALL_NAME "@rpath/${LIBRARY_NAME}.framework/${LIBRARY_NAME}")
set_target_properties(${LIBRARY_NAME} PROPERTIES BUILD_WITH_INSTALL_RPATH 1)
Upvotes: 1
Reputation: 11112
Doing detailed investigation into this issue, showed that the .xar archive that contains bitcode inside Mach-O file stores quite a bit of information, including linker flags. This information is stored in Table of Contents of the archive and is used to recompile/relink the libraries on bitcode recompilation.
In my case, I was building the framework with cmake, which added this information into linker flags. Configuring INSTALL_NAME_DIR
and BUILD_WITH_INSTALL_RPATH
and using @rpath effectively fixed the issue, and install_name_tool
was not required anymore.
Upvotes: 3