the compiler that produced it, 'Apple Swift version 5.5 (swiftlang-1300.0.31.1 clang-1300.0.29.1)’, 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)

My framework was built with Library Evolution enabled.

Replies

You should take time and make effort to explain better the context.

Which version of Xcode are you using ? 12.5 ?

If so, that means that the framework was built with a more recent version of XCode (and Swift compiler).

Library Evolution enabled does not play here: it is for upward compatibility (a framework compiled in a version will work with a more recent version), not downward compatibility: a framework built with a version may not work with a more ancient version.

Framework was built with Xcode 13 RC and built in swift version of 5.5 The app which is integrating the framework is using Xcode 12 RC with 5.3 swift version. Yes this looks like downward copability issue. Any clues?

  • I do not see other solution than recompiling framework with 12.5 or using 13 for compiling the app.

Add a Comment

@Claude31 has the right answer, so I'm reiterating it — binaries built with newer tools cannot be used with older tools. Binary stability only allows a binary to work with tools that didn't exist at the time the binary was complied. Either you need to use Xcode 12 to support your clients using Xcode 12+, or you need to move the requirements for your clients to use your library to Xcode 13+.

  • I was directed to this answer by Developer Technical Support (DTS) in response to a question I asked about an issue we're seeing with our binary framework when we compile it with Xcode 12.5 but then it is linked by our clients against Xcode <12.5 which results in a crash on launch:

    dyld: Symbol not found: __ZN5swift34swift50override_conformsToProtocolEPKNS_14TargetMetadataINS_9InProcessEEEPKNS_24TargetProtocolDescriptorIS1_EEPFPKNS_18TargetWitnessTableIS1_EES4_S8_E

    In this case, we actually don't get this warning, everything compiles fine until the app crashes on launch with the above (rather unilluminating!) error. We also found this issue only seems to impact Xcode 12.5, so it seems to be an Xcode 12.5 vs Xcode <12.5 issue, rather than Xcode 12 vs Xcode 13.

    There appear to be a number of other frameworks affected by this issue in Xcode 12.5. I also have a question on StackOverflow about this.

    @edford can you elaborate a little on the expected behaviours around module/binary stability and what's going on here under-the-hood? This took us (and our customers) a little by surprise as we had expected that our framework would continue to be both forwards and backwards compatible as it has been until now.

Add a Comment

@jon-iproov

we had expected that our framework would continue to be both forwards and backwards compatible as it has been until now.

Unfortunately, that was a wrong expectation. Where did you get it ? It happened to work "by chance", because nothing was changed that could cause problem. But the last release had more changed.

  • The most thorough official explanation of module stability which I can find is at https://swift.org/blog/abi-stability-and-more/ which talks about the ability to "mix versions". There is no mention of any restriction around backwards or forwards compatibility. Indeed, it specifically states that with module stability "clients can use a module without having to care what compiler it was built with" - this would seem to not be the case.

    Having had a further dig into this I can see a more nuanced discussion about backwards-compatibility at https://forums.swift.org/t/plan-for-module-stability/14551 but this is not explained anywhere in any of the official sources. We don't seem to be the only ones taken by surprise on this... (Especially as there is no compiler errors or warnings, just an obscure dyld crash).

Add a Comment

@jon-iproov, I reviewed your DTS request and had your support request routed here. I'll try to provide a little more information to help fill in your questions.

 This took us (and our customers) a little by surprise as we had expected that our framework would continue to be both forwards and backwards compatible as it has been until now. 

I'm sorry to hear you were surprised by this. We did mention the forward-compatibility detail in a few places. First, we presented binary Swift frameworks at WWDC 2019 with this information:

And since [textual module interfaces] behave like source code, then future versions of the Swift Compiler will be able to import module interfaces created with older versions.

You also cite a blog article on Swift.org, which contains this mention:

Swift 5 provides binary compatibility for apps: a guarantee that going forward, an app built with one version of the Swift compiler will be able to talk to a library built with another version.

can you elaborate a little on the expected behaviours around module/binary stability and what's going on here under-the-hood?

When you compile a module with a specific complier version, you're implicitly choosing a set of conditions for the layout and structure of the complied binary which will always correspond to the Swift version of the complier. Note the top of your module interface file and the lines that denote the textual interface version, complier version, and specific complier flags, for an example of where this is defined in the complied output.

The concept of a stable ABI is a lower-level concept and not everyone has familiarity with it, so let's make a rough analogy with how APIs work, as more people are familiar with the API level. Pick you favorite Apple framework, and imagine this framework added a new method in the iOS 15 SDK that fundamentally alters how you use the framework, and you'd like to adopt the new approach. However, you have to use an older Xcode with the iOS 14 SDK. How do you call this new API? Since the method didn't exist at the time the older Xcode and iOS 14 SDK were produced, you can't work with this new method. An ABI is conceptually similar — the contents of the compiled binary might have fundamental structural elements in it that didn't exist in an older version of the Swift complier, so that older complier is thus fundamentally incompatible with that binary.

Part of what might have confused you is the specific language used to discuss these issues. The language is important, because the concept of backwards- and forwards-compatibility are relative terms, and the direction of that relativity between compiler and library matters. The following are equivalent statements with the directionality flipped, and accurately represent what will work:

  • A new complier is backwards-compatible with the textual interface of a binary complied by an older complier.
  • An older binary's textual interface is forward-compatible with newer Swift compliers.

That is not the same as these statements, both of which are incorrect and will not work:

  • An older complier is forwards-compatible with the textual interface of a binary complied by an newer complier.
  • The textual interface for a binary from a newer complier is backward-compatible with older Swift compliers.

Swift's module stability is not the only complier technology where the binary module is only forward-compatible with a newer complier — bitcode is another example. An older complier cannot read the bitcode created by a newer complier. As such, a library author really needs to define two sets of requirements for clients:

  • What is the minimum OS version the library supports?
  • What is the minimum Xcode version the library supports?

That second point is often overlooked when defining library requirements. Ideally, a library could track this in line with the required Xcode versions for app development. For example, apps submitted to the App Store were required to use Xcode 12 as of April 2021. In April 2022, the requirement moves forward to requiring Xcode 13. There's no harm in having requirements that are more stringent and require a newer Xcode version than these baseline versions if it suits the needs of your library because you need the newer language features, so long as you are intentional about making this requirement and the impact on your clients in service of making a better library. Similarly, there's no reason for the library to support less than those Xcode versions and delay adopting language features beyond that point, as clients of your library will already be updating their Xcode versions according to that schedule.

  • Hello all, I just wanted to chime in here. I've been working on updating my project to library evolution support for about 2 weeks now. It's been grueling. I've been building iPhone apps for 14 years, quite knowledgeable with Xcode, and this has been one of the most painful processes I've encountered. It may be because I had sub-libraries that are static libraries inside my framework, but nevertheless I am ending up with frozen compilers, when interpreting .swiftinterface and related files. Compiler just hangs. Reason I am leaving this message is to give my opinion as well that forwards and backwards compatibility is what is being implied around the marketing of this. As a developer, that is what I assumed as well from watching the Apple WWDC video. Namely, because there are no directions anywhere on how and why someone should switch to an older version of Xcode or xcodebuild tools in order to correctly build something that supports multiple swift versions (as in, only forwards compatibility). There are no indications or even hints that one should do this. So I think it's a very confused subject, probably inside and outside of Apple. I'm currently filing another ticket because in my case compiler hangs forever when trying to build on a different version of swift than XCFramework was created in, even with build libraries for distribution, and there is no way to debug it even with xcodebuild as there are no details around, it just never returns from the '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-frontend -frontend' command. I am not even sure if it supports static libraries inside the framework at all at this point because I've done everything I can think of. Perhaps, just as they are hiding the fact that it's only forward compatible they are also hiding the fact that it does not support embedded static libraries? In any case, no way to tell as a developer, the parsing code for the swiftinterface files is done behind the scenes and there is no way for us to correct the problems.

Add a Comment