Can't use framework compiled with Swift 5.2 in Swift 5.1.3 project

We distribute our SDK in a binary framework that's wrapped in a xcframework.
The option BUILD_LIBRARY_FOR_DISTRIBUTION is enabled to get library evolution support.

Our project is compiled in Xcode 11.4 and Swift 5.2. One of our customers is still on Xcode 11.3.1 and Swift 5.1.3, when the customer adds our SDK, he get's compilation errors for the swiftinterface for some annotations (@_inheritsConvenienceInitializers and @_hasMissingDesignatedInitializers) which do not exist in Swift 5.1.3, and thus the project can not be compiled.
I confirmed that compiling with Swift 5.1.3 does not add the annotations.
Is this something that is supposed to happen? Is it odd of me to think that compiling using Swift 5.2 would work on all Swift 5 versions? Is it something we can fix without switching to a different Swift version?

Before, we created our own fat framework (but with the older Xcode and Swift version), it did not include the swiftinterface and it works fine for this customer. We switched on BUILD_LIBRARY_FOR_DISTRIBUTION so we don't have to require our customers to have the same Swift version.

1 Like

Module interfaces aren't forwards-compatible, only backwards-compatible. If they were backwards-compatible, we wouldn't be able to, e.g. add any new attributes in the new compiler.

Your client should continue using the old version of your framework if they're not able to update to the version of Swift that produced your .swiftinterface.

I understand that being forward compatible is important, and that there is the need to be able to add new attributes. But wouldn't you agree that being backwards compatible is equally important, if not more? At least for the versions in the 5.* branch.

Are these attributes something that would make the compilation fail on older Swift versions if they aren't there for those versions? Wouldn't something like this be a solution to use in the swiftinterface (if possible at all): https://github.com/apple/swift-evolution/blob/master/proposals/0224-ifswift-lessthan-operator.md ?

Let's say I compile this version with Swift 5.1, it does not contain the attributes and works fine on Swift 5.1 and 5.2. Why wouldn't the same version also work on 5.1 when compiled with 5.2 if it wouldn't contain the attributes? Or do these attributes also indicate that something is different in the binary itself?

For me, coming from Android, it sounds crazy that a binary framework is tied to a specific version of the compiler (even in the same major version) when implementing the binary framework.

I don't think that requiring my client to upgrade Swift or be stuck with an older version is something that is much appreciated...

There is a difference between ABI-relevant attributes and attributes that aren’t ABI-relevant. You’re right that, for some attributes, it would be harmless for clients to ignore them. We should have some kind of system for marking attributes as ABI-irrelevant or for #if-guarding new declarations that require new compiler versions.

However, @_hasMissingDesignatedInitializers and @_inheritsSuperclassInitializers fixed a bad ABI hole where clients that did not override all the designated initializers from their superclass were still able to inherit convenience initializers, and those convenience initializers would call into the superclass’s designated initializers and lead to partially initialized subclass instances.

It would be really bad if a client ignored these attributes.

But 5.1 does not have this attribute.
What would be the difference between compiling on 5.1 and removing the attributes?

It was broken in 5.1, it caused a serious miscompile that leads to uninitialized data. What would happen is exactly that, your clients could easily miscompile and receive uninitialized class instances when subclassing your classes.

Ok! That's clear, thanks.
Then I will ask the client to upgrade to 5.2 :)

1 Like

Thanks @harlanhaskins. Just confirming this is a typo, you meant Module interfaces aren't backward-compatible, only forward-compatible. In hindsight, it only makes sense like you say, but I think it should be called out a bit more explicitly in the documentation or blog posts, I don't recall noticing that in past.

1 Like

Yep, you're right, I apologize for mixing up the terms.

To be absolutely clear and avoid using potentially ambiguous language:

Module interfaces generated by a given version of the Swift compiler are guaranteed to be able to be imported by any future Swift compiler that supports the -swift-version that it was compiled with.

For example, if Swift 20 removes support for -swift-version 8, then .swiftinterface files compiled in the -swift-version 8 language mode will no longer be supported, but Swift 8 to Swift 19 will be able to import it.

That said, if Swift 9 produces a module interface, even in -swift-version 8 mode there's no guarantee that the Swift 8 compiler will be able to import the module, because the @inlinable code in the .swiftinterface file may be using new syntax that was introduced in Swift 9, but that was included in the -swift-version 8 language mode.

3 Likes
Terms of Service

Privacy Policy

Cookie Policy