Evolve Swift: Part 1 – Building your Tools


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.

Selecting Xcode

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

Package Managers

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:

brew update

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 bash, not 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
  noti [flags] [utility [args...]]

noti tar -cjf music.tar.bz2 Music/

  -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 noti and 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 llvm, 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 swift:

% pwd
% ls
% ./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:

% ls

./                       lldb/
../                      llvm/
.DS_Store                ninja/
Hold/                    swift/ [1]
Notes.txt                swift-corelibs-foundation/
build/ [2]               swift-corelibs-libdispatch/
clang/                   swift-corelibs-xctest/
cmark/                   swift-integration-tests/
compiler-rt/             swift-xcode-playground-support/
llbuild/                 swiftpm/

Your cloned swift repo [1] sits along the build folder [2]. Navigate to build > Ninja-ReleaseAssert > swift-macosx-x86_64 > 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.

One Comment

  • 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.