Linking Swift frameworks to an Unreal Engine project
It’s very rare to find an app without the usage of third-party SDKs. Whether you are working on a casual puzzle or an open-world adventure, there’s a point in the project development cycle when you have to rely on some other peoples’ code doing things for you: collecting and sending crash log data, collecting in-game metrics, helping with monetization, and so on.
Third-party SDKs on iOS are usually distributed in the form of a framework. A framework is either a static or a dynamic library, corresponding headers, module descriptions, and an optional resource bundle.
When integrating iOS framework with an Unreal Engine project, two most common issues happen, and both of them are related to linking the libraries. In this post I will describe the issues and give a solution to them.
Crash on startup “DYLD Library not loaded” or “DYLD Library missing”
If your app crashes on startup with the reason “DYLD Library missing” or “DYLD Library not loaded”, it means that dyld
couldn’t find some libraries in @rpath
. You can tell this kind of issue by the crash log. It will look something like this:
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: DYLD 1 Library missing
Library not loaded: '@rpath/swift_framework_dynamic.framework/swift_framework_dynamic'
Referenced from: '/Volumes/VOLUME/*/MyApp.app/MyApp'
Reason: tried: '' (no such file)
Triggered by Thread: 0
Thread 0 Crashed:
0 dyld 0x11cf4cb14 __abort_with_payload + 8
1 dyld 0x11cf526cc abort_with_payload_wrapper_internal + 104
2 dyld 0x11cf52700 abort_with_payload + 16
3 dyld 0x11cf22a00 dyld4::halt(char const*) + 580
4 dyld 0x11cf1fa20 dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 3560
5 dyld 0x11cf1dd84 start + 488
This crash log says: while executing MyApp
binary from bundle MyApp.app
dyld
couldn’t load swift_framework_dynamic
binary from swift_framework_dynamic.framework
bundle. Dyld
tried to load the library from @rpath/swift_framework_dynamic.framework/swift_framework_dynamic
.
dyld and @rpath
The dynamic linker (dyld
) is the entry point of the app. Before the app is launched, dyld
loads necessary libraries into memory. It knows where to look for libraries from a special attribute of the app binary called @rpath
.
@rpath
stands for Runtime Search Path. Its value is set during build, either using Xcode LD_RUNPATH_SEARCH_PATH
setting or -rpath
parameter of ld
linker command tool. It can be set to several values, one of which usually is @executable_path/Frameworks
, a Frameworks subdirectory in the app bundle.
To get Runpaths of binary, you can use otool -l MyApp.app/MyApp
and look at the LC_RPATH
in the output:
Load command 92
cmd LC_RPATH
cmdsize 40
path @executable_path/Frameworks (offset 12)
You can manipulate Runpaths using install_name_tool
.
Fixing the crash
Update: Unreal Engine 5 solution
Unreal Engine 5 has improved the situation by adding an option to copy frameworks into the app bundle: bCopyFramework
field of the UnrealBuildTool::ModuleRules::Framework
class. Simply set the value of this field to true
when setting up the framework in your plugin Build.cs
file:
PublicAdditionalFrameworks.Add(
new Framework(
"swift_framework_dynamic",
"swift_framework_dynamic.embeddedframework.zip",
null,
true // bCopyFramework
)
);
Unreal Engine 4 solution
To fix the crash, you should put the framework into the Frameworks
directory in the app bundle. Do this by adding copyDir
node to UPL file:
<copyDir src="$S(EngineDir)/Intermediate/UnzippedFrameworks/swift_framework_dynamic/swift_framework_dynamic.embeddedframework/swift_framework_dynamic.framework" dst="$S(BuildDir)/Frameworks/swift_framework_dynamic.framework" />
Linker error “Could not find or use auto-linked library” when using Swift static library
When you add a static framework containing Swift classes to an Unreal Engine project, you have to tell the linker where it should look for Swift libraries. In Xcode this is “Library Search Paths” setting in the Build Settings of a target.
If you get errors similar to these:
ld: warning: Could not find or use auto-linked library 'swiftFoundation'
ld: warning: Could not find or use auto-linked library 'swiftsimd'
ld: warning: Could not find or use auto-linked library 'swiftMetal'
ld: warning: Could not find or use auto-linked library 'swiftDarwin'
ld: warning: Could not find or use auto-linked library 'swiftCoreFoundation'
ld: warning: Could not find or use auto-linked library 'swiftObjectiveC'
ld: warning: Could not find or use auto-linked library 'swiftCore'
ld: warning: Could not find or use auto-linked library 'swiftAVFoundation'
ld: warning: Could not find or use auto-linked library 'swiftCoreMedia'
ld: warning: Could not find or use auto-linked library 'swiftCoreGraphics'
ld: warning: Could not find or use auto-linked library 'swiftCoreImage'
ld: warning: Could not find or use auto-linked library 'swiftCoreAudio'
that’s because the library you added to the project requires Swift libraries to link. By default Unreal Engine does not have paths to Swift libraries added to Library Search paths, so you have to point UBT to it. Swift libraries are located in Xcode toolchain. Add this to your plugin Build.cs
file:
string SDKROOT = Utils.RunLocalProcessAndReturnStdOut("/usr/bin/xcrun", "--sdk iphoneos --show-sdk-path");
PublicSystemLibraryPaths.Add(SDKROOT + "/usr/lib/swift");
PublicSystemLibraryPaths.Add(SDKROOT + "../../../../../../Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos");
PublicSystemLibraryPaths.Add(SDKROOT + "../../../../../../Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-5.0/iphoneos");
PublicSystemLibraryPaths.Add(SDKROOT + "../../../../../../Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-5.5/iphoneos");
and you are ready to go!