I have a binary Swift xcframework which references two other open-source Swift frameworks (built from source).
My framework along with its dependencies are built with the BUILD_LIBRARY_FOR_DISTRIBUTION
option enabled (in order to support module stability).
This setup has worked fine for many years, but now when building my framework in Xcode 12.5 or above, I’m getting the following dyld error when an app using the framework is compiled in Xcode <12.5:
dyld: Symbol not found: __ZN5swift34swift50override_conformsToProtocolEPKNS_14TargetMetadataINS_9InProcessEEEPKNS_24TargetProtocolDescriptorIS1_EEPFPKNS_18TargetWitnessTableIS1_EES4_S8_E
I do not seem to be the only one experiencing this problem. A look on Github provides a number of other frameworks experiencing the same issue in Xcode 12.5.
It is suggested here that this issue is being caused by the following warning apparently now causing this fatal error:
Using ‘class’ keyword for protocol inheritance is deprecated; use ‘AnyObject’ instead
I note that the affected dependency involved in my case (Starscream) has not yet changed the class keyword to AnyObject, however I have not (yet) verified this is definitely the cause.
Unfortunately there is very little documentation out there about this issue, but it seems like it could potentially be quite widespread and increasing in prevalence as people upgrade to Xcode 12.5+, and more binary frameworks are built against this new version.
Does anyone have any ideas about how this can be resolved/mitigated, other than downgrading to Xcode 12.4?
2
Answers
We ran into this issue as well when updating to
Xcode 12.5
. According to Apple, "module stability" only ensures that frameworks built in older versions of Xcode will work in newer versions of Xcode. Up until12.5
, it has conveniently worked the other way around as well, but it seems like they decided to make some breaking changes.The workaround that we’ve been doing is using the
xcodebuild
system of 12.4 to compile our frameworks dependencies, while still using the12.5
GUI for daily development. Switching to the older build is done by downloading the Xcode from the Developer Downloads and renaming itXcode_12_4
.export DEVELOPER_DIR=/Applications/Xcode_12_4.app/Contents/Developer
Although, because of this definition of module stability, I would strongly advise building with the minimum version of Xcode that your framework officially supports. (which must be at least
12.0
to submit to the App Store) This would ensure that there would be no possible issues with anyone using your framework in an older Xcode version.I know that’s a pretty disappointing non-answer, but it can be a fairly sustainable process. Framework development on iOS seems to be moving in the direction of requiring the developers to use the minimum version of
xcodebuild
that they expect their implementers to be using.Another work-around that is sometimes available:
This issue can be avoided by building your dependencies from source (assuming their license permits it). We built
Starscream
from source and it works quite well. (i.e. looking at the dependency GitHub if they post their source code, then copying it into a directory in your framework)We hit
with our framework which we distribute as binary. We were still using an old version of PromiseKit (6.10) which contains
Updating to a newer version which is changed to
Thenable: AnyObject
resolved the issue.