From 67f4563befa40fde650ddc9c34b064d5ed341697 Mon Sep 17 00:00:00 2001 From: Lawrence Forooghian Date: Wed, 18 Sep 2024 15:45:50 -0300 Subject: [PATCH] Require Xcode 16 or later MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This means: - using it for development (which will allow us to use Swift Testing, which we’ll do in #55) - requiring users of the library to use it (so that we can use Swift 6 features, which we’ll do in #56) — we’ve decided we’re happy to do this since from April 2025 Apple will force users wishing to upload to the App Store to use it anyway Whilst implementing this, I decided to revisit my comment from 646c220: > I haven’t committed the `.swiftpm/configuration/Package.resolved` file > created by Xcode 16. We already have two Package.resolved files (see the > `comparePackageLockfiles` lint task) and so let’s wait for Xcode 16 to > be released to see whether this file is going to stick around (perhaps > it will become part of the .gitignore created by the SPM that ships with > Xcode 16). With the release version of Xcode 16, I am no longer able to get Xcode to generate this file, so either they changed something or it’s going to reappear at some point when we poke Xcode in some very specific way (at which point we can decide what to do with it). Resolves #21. --- .github/workflows/check.yaml | 11 +++++ .swift-version | 2 +- CONTRIBUTING.md | 17 -------- Package.swift | 21 +--------- Package@swift-6.swift | 68 ------------------------------- README.md | 2 +- Sources/BuildTool/BuildTool.swift | 2 +- 7 files changed, 15 insertions(+), 108 deletions(-) delete mode 100644 Package@swift-6.swift diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index 932625e..ca4698b 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -18,6 +18,11 @@ jobs: steps: - uses: actions/checkout@v4 + # This step can be removed once the runners’ default version of Xcode is 16 or above + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: 16 + # We use caching for Mint because at the time of writing SwiftLint took about 5 minutes to build in CI, which is unacceptably slow. # https://github.com/actions/cache/blob/40c3b67b2955d93d83b27ed164edd0756bc24049/examples.md#swift---mint - uses: actions/cache@v4 @@ -39,6 +44,12 @@ jobs: matrix: ${{ steps.generation-step.outputs.matrix }} steps: - uses: actions/checkout@v4 + + # This step can be removed once the runners’ default version of Xcode is 16 or above + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: 16 + - id: generation-step run: swift run BuildTool generate-matrices >> $GITHUB_OUTPUT diff --git a/.swift-version b/.swift-version index f9ce5a9..e0ea36f 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -5.10 +6.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1501f9c..1771ced 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,20 +28,3 @@ To check formatting and code quality, run `swift run BuildTool lint`. Run with ` - We should aim to make it easy for consumers of the SDK to be able to mock out the SDK in the tests for their own code. A couple of things that will aid with this: - Describe the SDK’s functionality via protocols (when doing so would still be sufficiently idiomatic to Swift). - When defining a `struct` that is emitted by the public API of the library, make sure to define a public memberwise initializer so that users can create one to be emitted by their mocks. (There is no way to make Swift’s autogenerated memberwise initializer public, so you will need to write one yourself. In Xcode, you can do this by clicking at the start of the type declaration and doing Editor → Refactor → Generate Memberwise Initializer.) - -## Building for Swift 6 - -At the time of writing (August 2024), the latest version of Swift to ship with a release version of Xcode is Swift 5.10. However, in the next few months Apple will launch Swift 6, which refines the strict concurrency checking introduced in Swift 5.10. Specifically, my understanding is that it introduces features that make Swift 5.10’s strict concurrency checking more developer-friendly. I think that some of these features can be switched on in Swift 5.10, but I’m not sure if all of them can. So, Swift 6 releases we might decide that we want to switch to using Swift 6 for our SDK. So, in CI, in addition to Swift 5 language mode, we also try building the SDK in Swift 6 language mode using the latest Xcode 16 beta. - -And, actually more importantly, we want to be sure that the SDK can be integrated into a user’s application that uses Swift 6. So, in CI, in addition to Swift 5 language mode, we also try building the example app in Swift 6 language mode using the aforementioned Xcode beta. - -(If any of the above turns out to cause a lot of problems due to the quality of the beta software, we can reconsider this.) - -### Multiple `Package.swift` files - -We have a separate manifest file, `Package@swift-6.swift`, which a Swift compiler supporting Swift 6 will use instead of `Package.swift` (see [documentation of this SPM feature](https://github.com/swiftlang/swift-package-manager/blob/74f06f8a7fd6b4c729e474dee34db66319d90759/Documentation/Usage.md#version-specific-manifest-selection)). This file exists for two reasons: - -1. To tell the compiler “use the Swift 6 language mode to compile this package if the compiler supports Swift 6, else use the Swift 5 language mode” (I previously tried passing `-Xswiftc -swift-version -Xswiftc 6` to `swift build` but this seems to then use Swift 6 language mode for compiling not just our own package, but all of our dependencies, which is likely to fail.) -2. If you try to use `.enableUpcomingFeature` for a feature that is enabled by default in Swift 6, you’ll get an error `error: upcoming feature 'BareSlashRegexLiterals' is already enabled as of Swift version 6`. (I don’t know if there’s a better way of handling this.) - -So, we need to make sure we keep `Package.swift` and `Package@swift-6.swift` in sync manually. diff --git a/Package.swift b/Package.swift index b4d5955..fc233cd 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.10 +// swift-tools-version: 6.0 import PackageDescription @@ -39,20 +39,6 @@ let package = Package( name: "Ably", package: "ably-cocoa" ), - ], - swiftSettings: [ - // We build with strict concurrency checking enabled, because: - // - // 1. in theory it’s a useful language feature that reduces - // bugs - // 2. it will be unavoidable if we migrate to Swift 6, so let’s - // future-proof ourselves - // - // This is the first time that I’ll have used strict - // concurrency checking, so I don’t know what kind of impact it - // might have; I’ve seen anecdotes that it can make developers’ - // lives tricky. - .enableExperimentalFeature("StrictConcurrency"), ] ), .testTarget( @@ -76,11 +62,6 @@ let package = Package( name: "AsyncAlgorithms", package: "swift-async-algorithms" ), - ], - swiftSettings: [ - // See justification above. - .enableExperimentalFeature("StrictConcurrency"), - .enableUpcomingFeature("BareSlashRegexLiterals"), ] ), ] diff --git a/Package@swift-6.swift b/Package@swift-6.swift deleted file mode 100644 index fc233cd..0000000 --- a/Package@swift-6.swift +++ /dev/null @@ -1,68 +0,0 @@ -// swift-tools-version: 6.0 - -import PackageDescription - -let package = Package( - name: "AblyChat", - platforms: [ - .macOS(.v11), - .iOS(.v14), - .tvOS(.v14), - ], - products: [ - .library( - name: "AblyChat", - targets: [ - "AblyChat", - ] - ), - ], - dependencies: [ - .package( - url: "https://github.com/ably/ably-cocoa", - from: "1.2.0" - ), - .package( - url: "https://github.com/apple/swift-argument-parser", - from: "1.5.0" - ), - .package( - url: "https://github.com/apple/swift-async-algorithms", - from: "1.0.1" - ), - ], - targets: [ - .target( - name: "AblyChat", - dependencies: [ - .product( - name: "Ably", - package: "ably-cocoa" - ), - ] - ), - .testTarget( - name: "AblyChatTests", - dependencies: [ - "AblyChat", - .product( - name: "AsyncAlgorithms", - package: "swift-async-algorithms" - ), - ] - ), - .executableTarget( - name: "BuildTool", - dependencies: [ - .product( - name: "ArgumentParser", - package: "swift-argument-parser" - ), - .product( - name: "AsyncAlgorithms", - package: "swift-async-algorithms" - ), - ] - ), - ] -) diff --git a/README.md b/README.md index 091a8b0..67570d9 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ This is the repository for the Swift version of the Ably Chat SDK. We aim to bui ## Requirements -Xcode 15.3 (i.e. a compiler that supports Swift 5.10) or later. +Xcode 16 (i.e. a compiler that supports Swift 6) or later. ## Installation diff --git a/Sources/BuildTool/BuildTool.swift b/Sources/BuildTool/BuildTool.swift index bd5a0a6..5d3cca5 100644 --- a/Sources/BuildTool/BuildTool.swift +++ b/Sources/BuildTool/BuildTool.swift @@ -70,7 +70,7 @@ struct GenerateMatrices: ParsableCommand { mutating func run() throws { let tooling = [ [ - "xcodeVersion": "15.3", + "xcodeVersion": "16", "swiftVersion": 5, ], [