2026-07-08
Stack Overflow: View Question
Tags: ios, xcode, linker, swift-package-manager, xcframework
Score: -2 | Views: 73
The asker has two XCFrameworks: MySDK which internally uses DependencySDK. When MySDK is built as a dynamic library, the app links only MySDK and runs fine. When they rebuild MySDK as a static library, they get undefined symbols for DependencySDK's functions unless the app also embeds DependencySDK. Why the asymmetry?
This question sits at the heart of a fundamental linker concept that trips up nearly everyone doing framework distribution: symbol resolution happens at different times for static vs. dynamic libraries.
Why it's interesting:
.a) and a Mach-O image with its own load commands (.dylib/.framework).The explanation:
A dynamic MySDK.framework is fully linked at build time against DependencySDK. The resulting Mach-O binary has its own LC_LOAD_DYLIB entries (or in the static-dependency case, the DependencySDK object code is baked directly into MySDK's image). Either way, from the app's perspective, MySDK is a self-contained image with all symbols already resolved. The app linker only needs to satisfy symbols MySDK exports.
A static MySDK.xcframework is essentially a bundle of .o files. There is no linking step until the app links. Every unresolved reference inside MySDK — including every call into DependencySDK — is deferred to the app's final link. The app linker sees those unresolved symbols and demands DependencySDK be provided on the link line. Hence the undefined-symbol errors.
Direction toward a fix:
DependencySDK's object files into MySDK — but this risks duplicate-symbol errors if the app also links DependencySDK elsewhere, and violates the One Definition Rule for singletons/globals inside DependencySDK.MySDK dynamic if it has heavy dependencies, and reserve static for leaf libraries.Gotchas: Objective-C category symbols may need -ObjC and -force_load on the consumer side; Swift static frameworks force clients onto matching Swift compiler versions; and merging archives can silently hide symbol collisions until runtime.
