Static linkage is a common choice for Swift package products in iOS projects. For example, Tuist links package products statically by default.
It is often appropriate for release builds but can introduce friction during development. For LLDB to import Swift modules from statically linked archives during expression evaluation, the relevant module AST paths must be available, for example, through -add_ast_path. Otherwise, evaluating Swift expressions in the debugger may fail - Debug Swift debugging with LLDB
In modular projects with many test targets, the same static dependency may be linked into multiple final binaries. The result is duplicated machine code, larger CI/CD artifacts, and longer link times.
A dynamic library can avoid duplication when shared by multiple final binaries, while also providing a smoother debugging experience. However, a dynamic library is not always an option: a package may depend on a prebuilt static target, or a vendor may distribute a static framework without source code.
DylibForge addresses that case:
It relinks a static archive as a dynamic library without requiring access to its source code. The tool extracts object files, preserves autolink directives, patches Objective-C symbol visibility, skips byte-identical objects, localizes selected duplicate native symbols, and invokes clang -dynamiclib.
For example:
dylib-forge ./AbstractMaps.framework/AbstractMaps
--output ./AbstractMaps.framework/AbstractMaps
--sdk iphoneos
--install-name @rpath/AbstractMaps.framework/AbstractMaps
--linker-arg "-Wl,-undefined,dynamic_lookup"
For more control:
dylib-forge ./AbstractMaps.framework/AbstractMaps
--output ./AbstractMaps.framework/AbstractMaps
--sdk iphoneos
--install-name @rpath/AbstractMaps.framework/AbstractMaps
--linker-arg -framework
--linker-arg Foundation
--linker-arg -lc++
--linker-arg -F"Framework/Search/Path"
--linker-arg -Wl,-U,_some_undefined_symbol
--ignore-autolink PrivateVendorShim
--exclude-object LegacySimulatorOnly
Any feedback, ideas, or suggestions are very welcome.