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.

2 Likes

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): swift-evolution/0224-ifswift-lessthan-operator.md at master · apple/swift-evolution · GitHub ?

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.

4 Likes

@harlanhaskins Just tried importing a Swift framework generated by Swift Compiler 5.1.3 (Xcode 11.3.1) into Xcode 12, and I am getting the following two errors:

Unable to load standard library for target 'arm64-apple-tvos11.0'

Failed to build module 'FrameworkName' from its module interface; the compiler that produced it, 'Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)', may have used features that aren't supported by this compiler, 'Apple Swift version 5.3 (swiftlang-1200.0.29.2 clang-1200.0.30.1)'

At first glance, it sounds like this breaks the future compatibility contract you described above, but I wonder if there is something else going on that I am missing. It's very curious that this compilation error only happens for the tvOS version of the module, and the iOS version that has identical code does not result into the same error. I'll keep digging for more clues, but please let me know if you have any thoughts.

Just tried importing a Swift framework generated by Swift Compiler 5.1.3 (Xcode 11.3.1) into Xcode 12, and I am getting the following error

If it helps, I should add that the same framework works fine in Xcode 11.3.1-Xcode 11.7 ( haven't tried yet on 11.6-7)

Ok, nevermind, the error message seems to have been a red herring, it was configuration in Xcode project, VALID_ARCHS was specifically set to only arm64 for the tvOS Xcode project, and somehow earlier Xcode versions, would not mind, and still build properly for Sim, but Xcode 12 would not!
UPDATE: Just read this from Xcode 12:

The Build Settings editor no longer includes the Valid Architectures build setting (VALID_ARCHS), and its use is discouraged. Instead, there is a new Excluded Architectures build setting (EXCLUDED_ARCHS). If a project includes VALID_ARCHS, the setting is displayed in the User-Defined section of the Build Settings editor. (15145028)

All resolved.

1 Like