Replace platforms: block with per-API @available annotations#11
Conversation
The `platforms:` block in `Package.swift` sets an OS 26 deployment-target
floor for the package and transitively for any downstream package.
Requiring this of every adopter is an onerous constraint, especially for
libraries that want to offer QUIC / HTTP/3 as one transport option among
several. We should avoid it where possible.
This change drops the `platforms: [.macOS("26.0"), ...]` block from
`Package.swift` and annotates availability per-declaration instead.
The annotation changes broadly fall into these categories:
* Mark with `@available(Network 0.1.0, *)` (= macOS 26 / iOS 26 / tvOS 26
/ watchOS 26 / visionOS 26) every top-level declaration in `Sources/`,
`Tests/`, the benchmark target, and the executable tools whose body uses
an OS-26+ feature (Span / RawSpan / MutableRawSpan / OutputRawSpan,
InlineArray, ~Escapable types, @_lifetime, the package's own
`SwiftTLSQUICInstance` etc.) or another `@available(Network 0.1.0, *)` /
`@available(SwiftTLS 0.1.0, *)` symbol.
* Use `@available(macOS 11, iOS 14, tvOS 14, watchOS 7, *)` on
`os.Logger(subsystem:category:)` initializers in Darwin branches and on
the `Logger`-using `UInt64+VLE` helpers, where the actual binding
constraint is `os.Logger`.
* Use `@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)` on
extensions of `SymmetricKey` / `AES.GCM` / `ChaChaPoly` / `HMAC` in
`CryptoWrappers.swift`, where the binding constraint is the underlying
CryptoKit type.
* Split `Logging.swift`'s `extension Logger` into Darwin and non-Darwin
halves so only the os.Logger-using half carries the macOS 11 floor.
* Wrap each tool's `main.swift` runtime body in `if
#available(macOS 26, iOS 26, tvOS 26, watchOS 26, visionOS 26, *) { ... }
else { fatalError(...) }`. Tool helper types and free functions live at
module scope with `@available(Network 0.1.0, *)`; in `SocketTransfer`,
`NSEC_PER_MSEC` becomes a `static let` on the class because script-mode
top-level `let`s cannot carry `@available`.
* Wire `availabilityMacros` into the benchmark, test, and executable tool
targets' `swiftSettings` so the `Network 0.1.0` macro is defined when
building those targets.
Replace every `@available(Network 0.1.0, *)` annotation across `Sources/`, `Tests/`, the benchmark target, and the executable tools with the equivalent `@available(anyAppleOS 26, *)`. `anyAppleOS` is a meta-platform covering the Apple platforms with unified versioning starting at 26.0, which expands to the same `macOS 26 / iOS 26 / tvOS 26 / watchOS 26 / visionOS 26` tuple the custom macro produced. Drop the package-level macro plumbing this enables: the `AvailabilityMacro=Network 0.1.0:macOS 26, ...` `enableExperimentalFeature` setting, the `_OSAvailability` / `_Availability` helpers, and the per-target `availabilityMacros + ` prefix on `swiftSettings`. Adopters no longer need to know the macro name to read the source. Future-gated declarations can use `@available(anyAppleOS 10000, *)` directly if this pattern is ever needed.
agnosticdev
left a comment
There was a problem hiding this comment.
On piece of feedback. Also just confirming that the plan is to synchronize on anyAppleOS across SwiftTLS and SwiftNetwork, correct?
| #endif | ||
|
|
||
| #if !(os(Linux) || (NETWORK_EMBEDDED && !NETWORK_DRIVERKIT)) | ||
| #if canImport(os) || NETWORK_DRIVERKIT |
There was a problem hiding this comment.
Does the second branch of this statement make sense? (NETWORK_EMBEDDED && !NETWORK_DRIVERKIT) when we check for #if canImport(os) || NETWORK_DRIVERKIT on the next line?
Should we consolidate on #if canImport(os) || NETWORK_DRIVERKIT or do Linux still pickup the os module?
There was a problem hiding this comment.
You're right, it doesn't
That is definitely my plan, I intend to open a follow-up PR to SwiftTLS |
…ity macro" This reverts commit f247640.
I have since opened and backed out that PR. Upon further reflection it might not give us all the flexibility we would like. I'll back that change out here. |
| /// | ||
| /// See `NetworkPOSIXError` and `HTTP2Error` as two examples of `NetworkDomainSpecificError`. | ||
| @_spi(ProtocolProvider) | ||
| @available(Network 0.1.0, *) |
There was a problem hiding this comment.
Removing all availability here seems wrong. Why was this changed?
| @preconcurrency internal import Crypto | ||
| #endif | ||
|
|
||
| @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) |
There was a problem hiding this comment.
Is there any reason these can't also just be@available(Network 0.1.0, *)?
There was a problem hiding this comment.
No reason, I was just trying to express the minimum requirement wherever relevant. This is what’s required because of upstream requirements. You can always put more stringent requirements on. I personally think the granularity and matching the code we’re using makes it easier to reason about and it’ll match the numbers in things like build errors.
There was a problem hiding this comment.
Fair. It just seems a bit odd to have bits of code that we define that are unused and unusable on those older platforms, but still marked available. I don't care strongly though.
| } else { | ||
| print("Error running all (\(iterations)) transfers, something failed") | ||
| } | ||
| fatalError("This tool requires macOS 26 or newer") |
There was a problem hiding this comment.
Is there any way to make the entire test tool products have a minimum platform?
The
platforms:block inPackage.swiftsets an OS 26 deployment-target floor for the package and transitively for any downstream package. Requiring this of every adopter is an onerous constraint, especially for libraries that want to offer QUIC / HTTP/3 as one transport option among several. We should avoid it where possible.This PR drops the
platforms: [.macOS("26.0"), ...]block fromPackage.swiftand annotates availability per-declaration instead.The first commit applies per-declaration
@availableannotations across the source tree, in tiers chosen as the lowest that suffices:@available(Network 0.1.0, *)(= macOS 26 / iOS 26 / tvOS 26 / watchOS 26 / visionOS 26) every top-level declaration inSources/,Tests/, the benchmark target, and the executable tools whose body uses an OS-26+ feature (Span / RawSpan / MutableRawSpan / OutputRawSpan, InlineArray, ~Escapable types, @_lifetime, the package's ownSwiftTLSQUICInstanceetc.) or another@available(Network 0.1.0, *)/@available(SwiftTLS 0.1.0, *)symbol.@available(macOS 11, iOS 14, tvOS 14, watchOS 7, *)onos.Logger(subsystem:category:)initializers in Darwin branches and on theLogger-usingUInt64+VLEhelpers, where the actual binding constraint isos.Logger.@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)on extensions ofSymmetricKey/AES.GCM/ChaChaPoly/HMACinCryptoWrappers.swift, where the binding constraint is the underlying CryptoKit type.Logging.swift'sextension Loggerinto Darwin and non-Darwin halves so only the os.Logger-using half carries the macOS 11 floor.main.swiftruntime body inif #available(macOS 26, iOS 26, tvOS 26, watchOS 26, visionOS 26, *) { ... } else { fatalError(...) }. Tool helper types and free functions live at module scope with@available(Network 0.1.0, *); inSocketTransfer,NSEC_PER_MSECbecomes astatic leton the class because script-mode top-levellets cannot carry@available.availabilityMacrosinto the benchmark, test, and executable tool targets'swiftSettingsso theNetwork 0.1.0macro is defined when building those targets.The second commit replaces every
@available(Network 0.1.0, *)with the equivalent@available(anyAppleOS 26, *).anyAppleOSis a meta-platform covering the Apple platforms with unified versioning starting at 26.0, which expands to the samemacOS 26 / iOS 26 / tvOS 26 / watchOS 26 / visionOS 26tuple the custom macro produced.This lets us drop the package-level macro plumbing: the
AvailabilityMacro=Network 0.1.0:macOS 26, ...enableExperimentalFeaturesetting, the_OSAvailability/_Availabilityhelpers, and the per-targetavailabilityMacros +prefix onswiftSettings. Adopters no longer need to know the macro name to read the source.Future-gated declarations can use
@available(anyAppleOS 10000, *)directly if this pattern is ever needed.The two commits are kept separate so the
anyAppleOSchange can be reverted independently if reviewers prefer to keep the named macro.