If you’ve made the slightly rash but equally rewarding decision to dive into developing the Swift language then make sure you have access to a fast computer with good, fast storage. What you don’t want to do is be running an old Mac mini using an old external hard drive because Apple hasn’t updated the mini line in a few forevers.
If your “About this Mac” panel looks like this, seriously question why you’re trying to do this in the first place. For the sake of uncomplicated narrative, I’m going to assume that just about everyone out there in the real world has a better Mac with better memory and primary disk than I do:
For those interested in the naming from these screen shots: Esopus Spitzenburg., Kiku, and Broxwood Firewhelp. I have others but I think those are the names you might see in screen shots and text examples. Hopefully this will be the first of several posts about the topic, in honor of Paul Cantrell.
Embrace the Wait
Before you can change the compiler, you must get the compiler downloaded, compiled, and working in its most recent form. For me, this is multi-day event. You probably will have slightly fewer roadblocks. Still, keep your day open and focus on other work as your Mac may or may not wind tunnel its way through the process.
Even after you’ve got your toolchain under control and build, you’ll continue to have many many waits in your development process as you’ll want to keep updating your repo to match the current state of Apple’s master and its supporting tools. Each time you do this, you can expect a morning of recompiling before you can start working on anything significant.
During this time, you cannot reasonably explore, test, and build unless you do so on a separate machine or for distinct installs. It’s a big pain in the ass but it’s part and parcel of developing the language.
If you plan to do this casually, and a week has passed between the last pull from upstream/master and now, don’t expect to be productive until the afternoon at the earliest.
Although Swift’s toolset provides a quick iteration tool (called “Ninja”), that adds fast incremental builds, getting up to date and staying up to date means a large time commitment.
Further, don’t be shocked when your compiler or tools simply fail to build. They do that sometimes. It’s utterly frustrating to be stuck with a broken build for whatever reason. Incorporating workarounds into your toolset is a big part of swifting.
If you can’t embrace the wait, you don’t want to be developing swiftlang.
Ensure that your default Xcode is set correctly. Use
xcode-select -p to check which version is selected. If it isn’t your main app, use the utility to establish the right one. I use the production (not beta) version of Xcode:
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
Make sure you have a good package manager installed. I use Homebrew. I know there was some kind of controversy about that a while ago but I can’t remember why and it does the job for me.
Update your package manager to the most recent version:
If you run into any issues, you can do a full remove and re-install. These calls require bash and will misfire in csh/tcsh:
Uninstall Brew (removes all existing packages):
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall)"
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Get cmake and ninja
Grab a copy of cmake and ninja if you do not already have them installed on your system. CMake provides a cross-platform build/test/package solution that generates appropriate Make files, specialized to your environment. Ninja offers a speedy solution for incremental builds. It’s really fast, so once you’ve built out your libraries, you can go in and
ninja swift for a really fast update when you’re doing edit/build/test cycles.
brew install cmake ninja
Go ahead and install
sphinx now too. Sphinx “makes it easy to create intelligent and beautiful documentation” :
brew install sphinx
Because of the long, long nature of setup and update process, consider some tools to help keep you on top of tasks, so you know when they finish and can move on to your next steps.
I use a command-line utility called noti to announce when each stage of downloading and compilation completes. Noti is an open source tools that triggers feedback as a command line process finishes.
You can have the utility speak, create a macOS system notification, and more. It’s helpful for when you’re running long tasks in background windows. Thanks goes to Scott Robbins for his recommendation.
To install noti, follow the directions in the repo’s Readme file. If you elect to
curl a copy to your system, use
csh (or in my case
tcsh), for copy/pasting to your command line. The utility runs fine in
tcsh but its escaping assumes
bash is running.
Once installed, just prefix any command line command with
noti followed by flags. I prefer using
noti -b -s, which gives me both a banner alert and spoken text.
% noti --help Usage: noti [flags] [utility [args...]] Examples: noti tar -cjf music.tar.bz2 Music/ Flags: -t, --title string Set notification title. Default is utility name. -m, --message string Set notification message. Default is "Done!". -b, --banner Trigger a banner notification. This is enabled by default. -s, --speech Trigger a speech notification. -c, --bearychat Trigger a BearyChat notification. -i, --hipchat Trigger a HipChat notification. -p, --pushbullet Trigger a Pushbullet notification. -o, --pushover Trigger a Pushover notification. -u, --pushsafer Trigger a Pushsafer notification. -l, --simplepush Trigger a Simplepush notification. -k, --slack Trigger a Slack notification. -w, --pwatch int Monitor a process by PID and trigger a notification when the pid disappears. (default -1) -f, --file string Path to noti.yaml configuration file. --verbose Enable verbose mode. -v, --version Print noti version and exit. -h, --help Print noti help and exit.
Fork Swift and Clone
Starting on Github, log into your account and then fork Apple’s Swift repo. Navigate to github.com/apple/swift, and click fork:
My fork uses my
erica github account. Adjust the following directions accordingly so they correspond to your fork.
Hop over to a nice fast drive, and create a development directory. Enter the directory (
cd swiftdev, for example) and clone the Swift repo:
git clone https://github.com/erica/swift.git
If you want to get a notification and time how long this took, your command may look like this:
noti -b -s time git clone https://github.com/erica/swift.git
I’ll skip the
time references from here on so they don’t clutter up these instructions. I like how
time-ing gives you a sense of how long each task takes.
Install Supporting Utilities
Grab copies of the supporting utilities using the built-in
update-checkout utility. There’s quite a few supporting folders that need to be built, including
clang, and more. If you’re following these instructions, make sure you’re in the same top level directory as your swift install and not in the swift repo. Otherwise, adjust the path for the
update-checkout to drop the initial
% pwd /Volumes/Kiku/Development % ls swift % ./swift/utils/update-checkout --clone Skipping clone of 'swift', directory already exists Running ``obtain_additional_swift_sources`` with up to 8 processes. Cloning 'compiler-rt' Cloning 'llvm' Cloning 'swift-xcode-playground-support' Cloning 'swift-corelibs-foundation' Cloning 'clang' Cloning 'llbuild' Cloning 'cmark' Cloning 'lldb'
Now wait for everything to clone. There’s another way to clone using
ssh, but I’ve never done it. I just know that it exists and is documented on Apple’s Swift repo Readme file.
You should now be ready to perform a release build. I’m differing here from what’s recommended on Apple’s page because I got help early on from people who didn’t use that method. I’m sticking with my notes because they’re tried and trusted, not because I know what I’m doing.
% cd swift % noti -s time utils/build-script -R
Building Swift (and, this first time, all its supporting utilities) is not…swift. So go do something else for a significantly long time. Unlike your initial Swift build and when you perform updates by pulling from Apple’s upstream master, incremental changes can be relatively quick. Getting things done the first time and after each update is long and tedious.
If you’ve built things properly, you’ll find a newly build
swift compiler waiting for you in the
build folder. This directory is located at the top level of your development folder:
./ lldb/ ../ llvm/ .DS_Store ninja/ Hold/ swift/  Notes.txt swift-corelibs-foundation/ build/  swift-corelibs-libdispatch/ clang/ swift-corelibs-xctest/ cmark/ swift-integration-tests/ compiler-rt/ swift-xcode-playground-support/ llbuild/ swiftpm/
swift repo  sits along the
build folder . Navigate to
bin to find the
swift executable. Check the modification date and run it with the
-version flag to confirm it is the right build:
% ls -l build/Ninja-ReleaseAssert/swift-macosx-x86_64/bin/swift -rwxr-xr-x 1 ericasadun staff 96294356 Apr 30 09:23 build/Ninja-ReleaseAssert/swift-macosx-x86_64/bin/swift* % build/Ninja-ReleaseAssert/swift-macosx-x86_64/bin/swift -version Swift version 4.2-dev (LLVM bb2a4e8df7, Clang 56384a48b9, Swift 5f9bf115b3) Target: x86_64-apple-darwin17.5.0
Go ahead and use it to compile a file. Use the path to this build to ensure you don’t accidentally use the default compiler:
% cd ~/Desktop/ % lns ~/github/apple/swift/build/Ninja-ReleaseAssert/swift-macosx-x86_64/bin/swift swift Created symbolic link at /Users/ericasadun/Desktop/swift % echo 'print("Hello World")' > test.swift % ./swift test.swift Hello World
Getting your initial toolset built and running is the first step on the path to Swift evolution. Next up: ninja builds, creating branches, stashing differences, and managing test builds.
As it happens, my personal development machine is a 2012 quad core i7 Mac Mini with 16GB of RAM and a 1 TB Samsung SSD. It’s more than adequate for Xcode, Swift and my coding/debugging style. Of course, they no longer make a quad core Mac Mini.