Skip to content

Replace bespoke availability system #232

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,34 @@ jobs:
uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@main
with:
linux_os_versions: '["jammy", "focal"]'
enable_macos_checks: false
macos_xcode_versions: '["16.3"]'
enable_macos_checks: true
# FIXME: https://github.com/swiftlang/github-workflows/pull/140
# Xcode 16.0 and 16.1 are not actually available
macos_exclude_xcode_versions: |
[
{"xcode_version": "16.0"},
{"xcode_version": "16.1"},
]
swift_flags: "-Xbuild-tools-swiftc -DSYSTEM_CI"

build-abi-stable:
name: Build ABI Stable
uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@main
with:
enable_linux_checks: false
enable_macos_checks: true
enable_windows_checks: false
# Only build
macos_build_command: "xcrun swift build --build-tests"
# FIXME: https://github.com/swiftlang/github-workflows/pull/140
# Xcode 16.0 and 16.1 are not actually available
macos_exclude_xcode_versions: |
[
{"xcode_version": "16.0"},
{"xcode_version": "16.1"},
]
# Enable availability to match ABI stable verion of system.
swift_flags: "-Xbuild-tools-swiftc -DSYSTEM_CI -Xbuild-tools-swiftc -DSYSTEM_ABI_STABLE"

soundness:
name: Soundness
Expand Down
84 changes: 81 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,71 @@

import PackageDescription

let cSettings: [CSetting] = [
.define("_CRT_SECURE_NO_WARNINGS", .when(platforms: [.windows])),
struct Available {
var name: String
var version: String
var osAvailability: String
var sourceAvailability: String

init(
_ version: String,
_ osAvailability: String
) {
self.name = "System"
self.version = version
self.osAvailability = osAvailability
self.sourceAvailability = "macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, visionOS 1.0"
}

var swiftSetting: SwiftSetting {
#if SYSTEM_ABI_STABLE
// Use availability matching Darwin API.
let availability = self.osAvailability
#else
// Use availability matching SwiftPM default.
let availability = self.sourceAvailability
#endif
return .enableExperimentalFeature(
"AvailabilityMacro=\(self.name) \(version):\(availability)")
}
}

let availability: [Available] = [
Available("0.0.1", "macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0"),

Available("0.0.2", "macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0"),

Available("0.0.3", "macOS 12.3, iOS 15.4, watchOS 8.5, tvOS 15.4"),
Available("1.1.0", "macOS 12.3, iOS 15.4, watchOS 8.5, tvOS 15.4"),

Available("1.1.1", "macOS 14.4, iOS 17.4, watchOS 10.4, tvOS 17.4"),
Available("1.2.0", "macOS 14.4, iOS 17.4, watchOS 10.4, tvOS 17.4"),

Available("1.2.1", "macOS 14.4, iOS 17.4, watchOS 10.4, tvOS 17.4"),
Available("1.3.0", "macOS 14.4, iOS 17.4, watchOS 10.4, tvOS 17.4"),

Available("1.3.1", "macOS 14.4, iOS 17.4, watchOS 10.4, tvOS 17.4, visionOS 1.0"),
Available("1.3.2", "macOS 14.4, iOS 17.4, watchOS 10.4, tvOS 17.4, visionOS 1.0"),
Available("1.4.0", "macOS 14.4, iOS 17.4, watchOS 10.4, tvOS 17.4, visionOS 1.0"),

Available("1.4.1", "macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, visionOS 9999"),
Available("1.4.2", "macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, visionOS 9999"),
Available("1.5.0", "macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, visionOS 9999"),
Available("1.6.0", "macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, visionOS 9999"),
Available("1.6.1", "macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, visionOS 9999"),
]

let swiftSettingsAvailability = availability.map(\.swiftSetting)

#if SYSTEM_CI
let swiftSettingsCI: [SwiftSetting] = [
.unsafeFlags(["-require-explicit-availability=error"]),
]
#else
let swiftSettingsCI: [SwiftSetting] = []
#endif

let swiftSettings: [SwiftSetting] = [
let swiftSettings = swiftSettingsAvailability + swiftSettingsCI + [
.define(
"SYSTEM_PACKAGE_DARWIN",
.when(platforms: [.macOS, .macCatalyst, .iOS, .watchOS, .tvOS, .visionOS])),
Expand All @@ -25,6 +85,22 @@ let swiftSettings: [SwiftSetting] = [
.enableExperimentalFeature("Lifetimes"),
]

let cSettings: [CSetting] = [
.define("_CRT_SECURE_NO_WARNINGS", .when(platforms: [.windows])),
]

#if SYSTEM_ABI_STABLE
let platforms: [SupportedPlatform] = [
.macOS("26"),
.iOS("26"),
.watchOS("26"),
.tvOS("26"),
.visionOS("26"),
]
#else
let platforms: [SupportedPlatform]? = nil
#endif

#if os(Linux)
let filesToExclude = ["CMakeLists.txt"]
#else
Expand All @@ -39,6 +115,7 @@ let testsToExclude = ["IORequestTests.swift", "IORingTests.swift"]

let package = Package(
name: "swift-system",
platforms: platforms,
products: [
.library(name: "SystemPackage", targets: ["SystemPackage"]),
],
Expand All @@ -63,3 +140,4 @@ let package = Package(
cSettings: cSettings,
swiftSettings: swiftSettings),
])

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ To use the `SystemPackage` library in a SwiftPM project,
add the following line to the dependencies in your `Package.swift` file:

```swift
.package(url: "https://github.com/apple/swift-system", from: "1.6.0"),
.package(url: "https://github.com/apple/swift-system", from: "1.6.1"),
```

Finally, include `"SystemPackage"` as a dependency for your executable target:
Expand All @@ -41,7 +41,7 @@ Finally, include `"SystemPackage"` as a dependency for your executable target:
let package = Package(
// name, platforms, products, etc.
dependencies: [
.package(url: "https://github.com/apple/swift-system", from: "1.6.0"),
.package(url: "https://github.com/apple/swift-system", from: "1.6.1"),
// other dependencies
],
targets: [
Expand Down
12 changes: 6 additions & 6 deletions Sources/System/Errno.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
/// An error number used by system calls to communicate what kind of error
/// occurred.
@frozen
@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
public struct Errno: RawRepresentable, Error, Hashable, Codable {
/// The raw C error number.
@_alwaysEmitIntoClient
Expand Down Expand Up @@ -1391,7 +1391,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable {
}

// Constants defined in header but not man page
@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
extension Errno {
/// Operation would block.
///
Expand Down Expand Up @@ -1520,7 +1520,7 @@ extension Errno {
#endif
}

@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
extension Errno {
// TODO: We want to provide safe access to `errno`, but we need a
// release-barrier to do so.
Expand All @@ -1535,14 +1535,14 @@ extension Errno {
}

// Use "hidden" entry points for `NSError` bridging
@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
extension Errno {
public var _code: Int { Int(rawValue) }

public var _domain: String { "NSPOSIXErrorDomain" }
}

@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
extension Errno: CustomStringConvertible, CustomDebugStringConvertible {
/// A textual representation of the most recent error
/// returned by a system call.
Expand All @@ -1562,7 +1562,7 @@ extension Errno: CustomStringConvertible, CustomDebugStringConvertible {
public var debugDescription: String { self.description }
}

@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
extension Errno {
@_alwaysEmitIntoClient
public static func ~=(_ lhs: Errno, _ rhs: Error) -> Bool {
Expand Down
18 changes: 9 additions & 9 deletions Sources/System/FileDescriptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
/// of `FileDescriptor` values,
/// in the same way as you manage a raw C file handle.
@frozen
@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
public struct FileDescriptor: RawRepresentable, Hashable, Codable {
/// The raw C file handle.
@_alwaysEmitIntoClient
Expand All @@ -26,7 +26,7 @@ public struct FileDescriptor: RawRepresentable, Hashable, Codable {
}

// Standard file descriptors.
@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
extension FileDescriptor {
/// The standard input file descriptor, with a numeric value of 0.
@_alwaysEmitIntoClient
Expand All @@ -41,11 +41,11 @@ extension FileDescriptor {
public static var standardError: FileDescriptor { .init(rawValue: 2) }
}

@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
extension FileDescriptor {
/// The desired read and write access for a newly opened file.
@frozen
@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
public struct AccessMode: RawRepresentable, Sendable, Hashable, Codable {
/// The raw C access mode.
@_alwaysEmitIntoClient
Expand Down Expand Up @@ -88,7 +88,7 @@ extension FileDescriptor {

/// Options that specify behavior for a newly-opened file.
@frozen
@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
public struct OpenOptions: OptionSet, Sendable, Hashable, Codable {
/// The raw C options.
@_alwaysEmitIntoClient
Expand Down Expand Up @@ -326,7 +326,7 @@ extension FileDescriptor {

/// Options for specifying what a file descriptor's offset is relative to.
@frozen
@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
public struct SeekOrigin: RawRepresentable, Sendable, Hashable, Codable {
/// The raw C value.
@_alwaysEmitIntoClient
Expand Down Expand Up @@ -402,7 +402,7 @@ extension FileDescriptor {
}
}

@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
extension FileDescriptor.AccessMode
: CustomStringConvertible, CustomDebugStringConvertible
{
Expand All @@ -421,7 +421,7 @@ extension FileDescriptor.AccessMode
public var debugDescription: String { self.description }
}

@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
extension FileDescriptor.SeekOrigin
: CustomStringConvertible, CustomDebugStringConvertible
{
Expand All @@ -444,7 +444,7 @@ extension FileDescriptor.SeekOrigin
public var debugDescription: String { self.description }
}

@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
extension FileDescriptor.OpenOptions
: CustomStringConvertible, CustomDebugStringConvertible
{
Expand Down
2 changes: 1 addition & 1 deletion Sources/System/FileHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
See https://swift.org/LICENSE.txt for license information
*/

@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
extension FileDescriptor {
/// Runs a closure and then closes the file descriptor, even if an error occurs.
///
Expand Down
20 changes: 10 additions & 10 deletions Sources/System/FileOperations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
See https://swift.org/LICENSE.txt for license information
*/

@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
@available(System 0.0.1, *)
extension FileDescriptor {
/// Opens or creates a file for reading or writing.
///
Expand Down Expand Up @@ -368,7 +368,7 @@ extension FileDescriptor {
}

#if !os(WASI)
@available(/*System 0.0.2: macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0*/iOS 8, *)
@available(System 0.0.2, *)
extension FileDescriptor {
/// Duplicates this file descriptor and return the newly created copy.
///
Expand Down Expand Up @@ -398,15 +398,15 @@ extension FileDescriptor {
///
/// The corresponding C functions are `dup` and `dup2`.
@_alwaysEmitIntoClient
@available(/*System 0.0.2: macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0*/iOS 8, *)
@available(System 0.0.2, *)
public func duplicate(
as target: FileDescriptor? = nil,
retryOnInterrupt: Bool = true
) throws -> FileDescriptor {
try _duplicate(as: target, retryOnInterrupt: retryOnInterrupt).get()
}

@available(/*System 0.0.2: macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0*/iOS 8, *)
@available(System 0.0.2, *)
@usableFromInline
internal func _duplicate(
as target: FileDescriptor?,
Expand Down Expand Up @@ -435,20 +435,20 @@ extension FileDescriptor {
#endif

#if !os(WASI)
@available(/*System 1.1.0: macOS 12.3, iOS 15.4, watchOS 8.5, tvOS 15.4*/iOS 8, *)
@available(System 1.1.0, *)
extension FileDescriptor {
/// Creates a unidirectional data channel, which can be used for interprocess communication.
///
/// - Returns: The pair of file descriptors.
///
/// The corresponding C function is `pipe`.
@_alwaysEmitIntoClient
@available(/*System 1.1.0: macOS 12.3, iOS 15.4, watchOS 8.5, tvOS 15.4*/iOS 8, *)
@available(System 1.1.0, *)
public static func pipe() throws -> (readEnd: FileDescriptor, writeEnd: FileDescriptor) {
try _pipe().get()
}

@available(/*System 1.1.0: macOS 12.3, iOS 15.4, watchOS 8.5, tvOS 15.4*/iOS 8, *)
@available(System 1.1.0, *)
@usableFromInline
internal static func _pipe() -> Result<(readEnd: FileDescriptor, writeEnd: FileDescriptor), Errno> {
var fds: (Int32, Int32) = (-1, -1)
Expand All @@ -463,7 +463,7 @@ extension FileDescriptor {
}
#endif

@available(/*System 1.2.0: macOS 9999, iOS 9999, watchOS 9999, tvOS 9999*/iOS 8, *)
@available(System 1.2.0, *)
extension FileDescriptor {
/// Truncates or extends the file referenced by this file descriptor.
///
Expand All @@ -485,7 +485,7 @@ extension FileDescriptor {
/// associated with the file.
///
/// The corresponding C function is `ftruncate`.
@available(/*System 1.2.0: macOS 9999, iOS 9999, watchOS 9999, tvOS 9999*/iOS 8, *)
@available(System 1.2.0, *)
@_alwaysEmitIntoClient
public func resize(
to newSize: Int64,
Expand All @@ -497,7 +497,7 @@ extension FileDescriptor {
).get()
}

@available(/*System 1.2.0: macOS 9999, iOS 9999, watchOS 9999, tvOS 9999*/iOS 8, *)
@available(System 1.2.0, *)
@usableFromInline
internal func _resize(
to newSize: Int64,
Expand Down
Loading