Why you need the -ObjC flag
2024.06.04
Tuist provides a method for integrating Swift Packages, previously resolved by SPM, into Xcode projects using XcodeProj primitives such as targets, build settings and phases.
This feature uncovered a need that some packages in the ecosystem have,
and that’s the need for upstream targets to pass -force_load
or -ObjC
through the build setting OTHER_LDFLAGS
.
Why is that needed?
Thanks to David, who put together some troubleshooting guidance and provided some references to discussions, I could better understand what the problem was.
This post is my attempt to write down my understanding of the problem, to help other developers in the future come across the same issue.
In simple words, the problem is that the linker overoptimizes the binary removing symbols that are needed at runtime. The linker’s dead-stripping logic can’t delete dynamically referenced symbols. And this is something that happens not only when referencing Objective-C symbols, but Swift too. For example, when integrating Composable Architecture, when integrating it with Tuist via Xcode targets, developers might need to add explicit references to those symbols or the flags above to the build settings.
What’s the solution? There are a few options:
- The package maintainer can add static references to those symbols to prevent the dead-stripping logic from removing them (e.g., Promises, IGListKit)
-
You set the
-force_load
or-ObjC
flag in theOTHER_LDFLAGS
build setting of the target that links those packages statically. Note that this has some effects, like potentially increasing the binary size. - You turn those dependencies into dynamic targets, which as a caveat might end up increasing the launch time of your app.
This is a bit unfortunate because it requires developers to go a bit deeper in understanding their dependencies , but hopefully this write-up helps you understand the problem and the potential solutions.