Building with nightly Swift toolchains on macOS
The Swift website provides nightly builds of the Swift compiler (called toolchains) for download. Building with a nightly compiler can be useful if you want to check if a bug has already been fixed on main, or if you want to experiment with upcoming language features such as Embedded Swift, as I’ve been doing lately.
A toolchain is distributed as a .pkg
installer that installs itself into /Library/Developer/Toolchains
(or the equivalent path in your home directory). After installation, you have several options to select the toolchain you want to build with:
In Xcode
In Xcode, select the toolchain from the main menu (Xcode > Toolchains), then build and/or run your code normally.
Not all Xcode features work with a custom toolchain. For example, playgrounds don’t work, and Xcode will always use its built-in copy of the Swift Package Manager, so you won’t be able to use unreleased SwiftPM features in this way. Also, Apple won’t accept apps built with a non-standard toolchain for submission to the App Store.
On the command line
When building on the command line there are multiple options, depending on your preferences and what tool you want to use.
The TOOLCHAINS
environment variable
All of the various Swift build tools respect the TOOLCHAINS
environment variable. This should be set to the desired toolchain’s bundle ID, which you can find in the Info.plist
file in the toolchain’s directory.
Example (I’m using a nightly toolchain from 2024-03-03 here):
# My normal Swift version is 5.10
$ swift --version
swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
# Make sure xcode-select points to Xcode, not to /Library/Developer/CommandLineTools
# The Command Line Tools will ignore the TOOLCHAINS variable.
$ xcode-select --print-path
/Applications/Xcode.app/Contents/Developer
# The nightly toolchain is 6.0-dev
$ export TOOLCHAINS=org.swift.59202403031a
$ swift --version
Apple Swift version 6.0-dev (LLVM 0c7823cab15dec9, Swift 0cc05909334c6f7)
Toolchain name vs. bundle ID
I think the TOOLCHAINS
variable is also supposed to accept the toolchain’s name instead of the bundle ID, but this doesn’t work reliably for me. I tried passing:
- the
DisplayName
fromInfo.plist
(“Swift Development Snapshot 2024-03-03 (a)”), - the
ShortDisplayName
(“Swift Development Snapshot”; not unique if you have more than one toolchain installed!), - the directory name, both with and without the
.xctoolchain
suffix,
but none of them worked reliably, especially if you have multiple toolchains installed.
In my limited testing, it seems that Swift picks the first toolchain that matches the short name prefix (“Swift Development Snapshot”) and ignores the long name components. For example, when I select “Swift Development Snapshot 2024-03-03 (a)”, Swift picks swift-DEVELOPMENT-SNAPSHOT-2024-01-30-a
, presumably because that’s the “first” one (in alphabetical order) I have installed.
My advice: stick to the bundle ID, it works. Here’s a useful command to find the bundle ID of the latest toolchain you have installed (you may have to adjust the path if you install your toolchains in ~/Library
instead of /Library
):
$ plutil -extract CFBundleIdentifier raw /Library/Developer/Toolchains/swift-latest.xctoolchain/Info.plist
org.swift.59202403031
# Set the toolchain to the latest installed:
export TOOLCHAINS=$(plutil -extract CFBundleIdentifier raw /Library/Developer/Toolchains/swift-latest.xctoolchain/Info.plist)
xcrun
and xcodebuild
xcrun
and xcodebuild
respect the TOOLCHAINS
variable too. As an alternative, they also provide an equivalent command line parameter named --toolchain
. The parameter has the same semantics as the environment variable: you pass the toolchain’s bundle ID. Example:
$ xcrun --toolchain org.swift.59202403031a --find swiftc
/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2024-03-03-a.xctoolchain/usr/bin/swiftc
Swift Package Manager
SwiftPM also respects the TOOLCHAINS
variable, and it has a --toolchains
parameter as well, but this one expects the path to the toolchain, not its bundle ID. Example:
$ swift build --toolchain /Library/Developer/Toolchains/swift-latest.xctoolchain
Missing toolchains are (silently) ignored
Another thing to be aware of: if you specify a toolchain that isn’t installed (e.g. because of a typo or because you’re trying to run a script that was developed in a different environment), none of the tools will fail:
-
swift
,xcrun
, andxcodebuild
silently ignore the toolchain setting and use the default Swift toolchain (set viaxcode-select
). - SwiftPM silently ignores a missing toolchain set via
TOOLCHAINS
. If you pass an invalid directory to the--toolchains
parameter, it at least prints a warning before it continues building with the default toolchain.
I don’t like this. I’d much rather get an error if the build tool can’t find the toolchain I told it to use. It’s especially dangerous in scripts.