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!