I'm working on a Payment SDK integrating Storekit2 for Unity games. The workflow is as follows:
- build the swift project that exposes objective c interface to static libraries, then archive them into xcframework
- embed the xcframework into native unity plugin where we call objective-c functions from C#
- export the unity project to Xcode project
- build the game Xcode project
When deployment target of swift project is set to iOS15
No matter what iOS version target is set in the game Xcode project, I got build error:
Undefined symbol: __swift_FORCE_LOAD_$_swiftCompatibility56
When deployment target of swift project is set to iOS16
And set the deployment target of game project to iOS15 (I need to let the payment sdk to work on iOS15 as Storekit2 and swift concurrency shipped with iOS15).
I can build the game Xcode project, and it works on iOS16+ device. But when I run on iOS15 device, I got runtime error:
2024-08-26 18:17:29.289078+0900 ***[1404:95780] Error loading /var/containers/Bundle/Application/123/***/Frameworks/UnityFramework.framework/UnityFramework: dlopen(/var/containers/Bundle/Application/123/***/Frameworks/UnityFramework.framework/UnityFramework, 0x0109): Symbol not found: (_objc_claimAutoreleasedReturnValue)
Referenced from: '/private/var/containers/Bundle/Application/123/***/Frameworks/UnityFramework.framework/UnityFramework'
Expected in: '/usr/lib/libobjc.A.dylib'
2024-08-26 18:17:29.418604+0900 ***[1404:95780] Error loading /var/containers/Bundle/Application/123/***/Frameworks/UnityFramework.framework/UnityFramework: dlopen(/var/containers/Bundle/Application/123/***/Frameworks/UnityFramework.framework/UnityFramework, 0x0109): Symbol not found: (_objc_claimAutoreleasedReturnValue)
Referenced from: '/private/var/containers/Bundle/Application/123/***/Frameworks/UnityFramework.framework/UnityFramework'
Expected in: '/usr/lib/libobjc.A.dylib'
If I chose not to build framework into static libraries but dynamic ones, I can avoid this problem but Unity cannot handle dynamic libraries well when exporting to Xcode project so I have no choice here but to stick to static ones.
minimum reproduction
I made a minimum reproduction project to exclude the process of unity.
- a fresh new empty objective-c app project
- embed the xcframework built with target iOS15
- call a function in the framework in applicationDidFinishLaunch
- set the deployment target of main target of the app project to iOS15.
- build the project
I still get
Undefined symbol: __swift_FORCE_LOAD_$_swiftCompatibility56
versions
- Xcode version 15.4
- Test iOS device version 15.8
Here is the GitHub repo
Ta!
With that I was able to reproduce the problem easily.
I’ll note that the error you mentioned isn’t the only error in play. If you look at the full build transcript — something I talk about more in Command [something] failed with a nonzero exit code — there are actually two warnings and an error:
ld: warning: Could not find or use auto-linked library 'swiftCompatibility56': library 'swiftCompatibility56' not found
ld: warning: Could not find or use auto-linked library 'swiftCompatibilityPacks': library 'swiftCompatibilityPacks' not found
Undefined symbols for architecture arm64:
"__swift_FORCE_LOAD_$_swiftCompatibility56", referenced from:
__swift_FORCE_LOAD_$_swiftCompatibility56_$_MinimumFramework in libMinimumFramework.a[3](Util.o)
Those warnings are interesting. They suggest that:
-
The static library is trying to autolink some compatibility stuff.
-
The linker is unable to find that, probably due to a search path issue.
The easiest way to resolve this is to add a Swift file to the app target. The Swift file can be empty, but its presence tells Xcode that Swift might be in play, and thus to adjust the way it invokes the linker.
Comparing the linker build step in the working and non-working cases I see this:
% diff -c ng.txt ok.txt
*** ng.txt Tue Sep 10 13:09:08 2024
--- ok.txt Tue Sep 10 13:09:02 2024
***************
*** 30,35 ****
--- 30,41 ----
-no_deduplicate
-fobjc-arc
-fobjc-link-runtime
+ -L/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos
+ -L/usr/lib/swift
+ -Xlinker
+ -add_ast_path
+ -Xlinker
+ /Users/quinn/Library/Developer/Xcode/DerivedData/MinimumApp-ckfwmiiefkdgcdbqanvnclfzdcoo/Build/Intermediates.noindex/MinimumApp.build/Debug-iphoneos/MinimumApp.build/Objects-normal/arm64/MinimumApp.swiftmodule
-Xlinker
-alias
-Xlinker
The key thing seems to be that linker include path of /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos
. That’s where those libraries should be found:
% ls -lh /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos
…
-rwxr-xr-x 1 quinn staff 84K 9 Aug 16:47 libswiftCompatibility56.a
…
I guess you could fix this by manually adding that link path, but it might just be easier to include a dummy Swift file in the final target.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"