Open hassila opened 2 years ago
CC: @tshortli
Jordan Rose helpfully pointed out:
yup. I think we should be able to allow custom definitions of environment strings, and piggybacks on the existing availability checker to diagnose violations.
@hassila, currently, Swift's compile-time and runtime availability checking don't support third-party libraries well. While we are still investigating the proper solutions, you could start using -user-module-version
flag to compile your libraries. These versions are compiled into the Swift module and they are currently used in the versioned #canImport()
check. In the future, we could potentially support library version checks at run time, for instance:
if #available(ourProductName, version: 2) {
// perform new behavior because ourProductName has a version greater or equal to 2
} else {
// perform old behavior because ourProductName has a version less than 2
}
Thanks! I'll play with it - but unfortunately that won't cover two of the more important use cases for availability (depreciations and renaming) - we want to be able to evolve API for our customers in a graceful way and those are very nice.
Note for others who wants to try it - -user-module-version
seems to work for checking versions like this, adding it to the library gives a .swiftinterface
containing:
hassila@max ~/G/prototype-library-evolution-client (main)> more .build/arm64-apple-macosx/debug/PrototypeLibraryEvolution.swiftinterface
// swift-interface-format-version: 1.0
// swift-compiler-version: Apple Swift version 5.7 (swiftlang-5.7.0.123.8 clang-1400.0.29.50)
// swift-module-flags: -target arm64-apple-macosx10.13 -enable-objc-interop -enable-library-evolution -swift-version 5 -Onone -module-name PrototypeLibraryEvolution
// swift-module-flags-ignorable: -user-module-version 1.0
...
and the check is done thusly (with currently underscored version - there's also an _underlyingVersion
for
module overlays, but must admit I have no idea when/why that would be used, as far as I could see it is for
getting at the underlying version when exposing e.g. ObjC API?):
#if canImport(PrototypeLibraryEvolution, _version: 1.0)
import PrototypeLibraryEvolution
#endif
Thanks for the instruction, @hassila ! the version number for ObjC library is pulled from .tbd
file, which contains a field indicating user-specified version keyed by current-version
.
I was mulling over potentially using user module version for @available
attribute, e.g. something like @available(moduleVersion 2, *)
. The challenge of supporting this is that, unlike OS versions, the user module version is local and cannot penetrate through module boundaries. This may be doable if the library owners can provide information about how the user module versions of different modules are aligned with each other.
I was mulling over potentially using user module version for
@available
attribute, e.g. something like@available(moduleVersion 2, *)
.
That'd be great if possible I think.
The challenge of supporting this is that, unlike OS versions, the user module version is local and cannot penetrate through module boundaries. This may be doable if the library owners can provide information about how the user module versions of different modules are aligned with each other.
Sorry, I don't quite understand the problem here, is it about using modules that are implicitly re-exported by a dependency (how Swift currently 'leaks' imports), or something else that causes problems?
How would information about how 'user module versions of different modules are aligned with each other' be used?
Ok, I couldn't help noticing the definition: https://github.com/apple/swift-foundation/blob/cd3d29426fee11d02d58363ad16683eb44a38985/Package.swift#L13
And usage: https://github.com/search?q=repo%3Aapple%2Fswift-foundation+available%28FoundationPreview&type=code
Looking forward to the pitch and we will happily test this out when you feel it's ready.
The "availability macros" feature used in swift-foundation doesn't really represent progress towards this feature request as far as I understand it. Availability macros have existed for quite a while and were originally designed to aid the authors of the standard library in managing @available
annotations (see availability-macros.def). These macros are just conveniences that get expanded to traditional, platform based availability. For example, a SwiftStdlib 5.9
annotation in the standard library expands to macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0
.
The feature requested here requires introducing a notion of availability that is fully separate from platform based availability.
Ah, thanks for the link, I didn't realize the mapping to platform versions when looking at the usage site (which was my focus) - you are absolutely right it doesn't address this issue then, sorry for the noise.
Hello! Are there any updates?
It would be nice to have a similar option as in the Doc generator: https://forums.swift.org/t/setting-a-documentation-article-s-platform-availability/61144/8
Right now, we can describe the version in which certain features became available using:
@Metadata {
@Available("Swift DocC", introduced: "1.0")
}
And it would be great to describe symbol availability in a similar way:
@available("Swift DocC", introduced: "1.0")
public something: Some
UPDATE: It looks related:
Is your feature request related to a problem? Please describe.
We’ve ended up realizing we’d like to use the library evolution features for resilient api surfaces for our product (yes, needed for an enterprise solution where clients of libraries must be able to be replaced independently and don’t have source access. Both macOS and Linux. Aware of tool chain impedance matching on Linux required - that’s ok).
The question is how we can evolve our api with availability annotations?
Current annotations for availability is tied to platform or swift version only, but we'd want to tie it to our products version numbers instead.
Not sure the best way to express it, but if a typical swift macro would be:
@available(swift 5.1)
we'd want something like:
@available(ourProductName 2.0)
which we could use with e.g.
or e.g.
@available(ourProductName , deprecated: 3, renamed: "newNameForThis")
Describe the solution you'd like Add support for third-party availability annotations to allow tying availability to our product releases instead of platform/swift versions.
Describe alternatives you've considered As a stop-gap we considered to tie it to Swift releases instead, which is not really a good workaround, but AFAWU it's fundamentally the only option we have (for it to work on both Linux and macOS) - and not very good conceptually.
Additional context Some background discussion here: https://forums.swift.org/t/availability-when-using-library-evolution-resilience-for-third-party-libraries/59341