Building Swift 4.2 For Debian 9 (Stretch)
July 27, 2018

I recently installed a new server, and decided to use Debian 9 (Stretch).

Apple distribute built versions of Swift for Ubuntu 14.04/16.04/16.10, but nothing specifically for Debian.

Since Ubuntu is downstream(-ish) from Debian, there’s a chance that the binaries might have just worked, but I decided that it would be worth the effort to try to build Swift from source on the new server, to see how hard it was.

The answer turned out to be: not very.

The first steps were to fetch the source, and install some dependencies. Apple’s full instructions can be found here, but I’ll summarise them below, along with the tweaks I needed:

Dependencies

Swift needs a few tools. These all installed cleanly on Stretch.

sudo apt-get install git cmake ninja-build clang python uuid-dev libicu-dev icu-devtools libbsd-dev libedit-dev libxml2-dev libsqlite3-dev swig libpython-dev libncurses5-dev pkg-config libblocksruntime-dev libcurl4-openssl-dev systemtap-sdt-dev tzdata rsync

Source

The basic Swift code lives in Github.

mkdir swift-source
cd swift-source
git clone https://github.com/apple/swift.git

Branch

I wanted to build the 4.2 branch, so before proceeding I switched to it:

pushd swift
git checkout swift-4.2-branch
popd

More Source

That done, I could fetch the rest of the source, using a script from the main Swift repo:

./swift/utils/update-checkout --clone

Build All The Things

The instructions I linked to above show you how to build, but ideally what I wanted was to package up everything in the same format as the downloadable distributions.

It turns out there’s a script for that too:

swift/utils/build-toolchain org.swift

(the second argument is a prefix, which I suspect may only be relevant for Mac builds; I wasn’t sure what the correct value to use was, so guessed)

It’s All Going Well… Oh, Damn

This kicked off the build, and things looked like they were going well, but eventually I hit an error.

Afer a bit of rummaging around through the logs, the problem seemed to be that Swift uses swig. By default Stretch has version 3.0.10 of swig installed, and Swift wanted 3.0.12.

As luck would have it, 3.0.12 has made it into testing for Debian, so was theoretically installable with:

sudo apt-get install swig/testing

Things turned out to be a little bit more complicated, since by default, my server setup was not configured to have access to the testing stream.

I didn’t want to upgrade everything to testing, just swig, and it took a little bit of a while to figure out what I needed to do, since I’m no expert with the way of the Debian.

After a bit of Google-fu, I came up with this answer, which pointed me in the right direction.

I didn’t follow their instructions precisely, but I did create the following files in /etc/apt/preferences.d:

security.pref:

Package: *
Pin: release l=Debian-Security
Pin-Priority: 1000

stable.pref:

Package: *
Pin: release a=stable
Pin-Priority: 900

testing.pref:

Package: *
Pin: release a=testing
Pin-Priority: 750

I then edited /etc/apt/sources.list to include the lines:

deb http://mirrors.linode.com/debian testing main
deb-src http://mirrors.linode.com/debian testing main

(I’m using Linode hosting, hence the use of their mirrors - but you could obviously use the official Debian urls there instead, or other mirrors provided by your hosting service)

The theory (according to that linked answer) is that by setting the testing priority lower than the stable one, I wouldn’t be offered the testing version in the normal course of things - but I could access one manually if I wanted.

This seemed to work, and allowed me to run:

sudo apt-get update
sudo apt-get install swig/testing

which got me to where I wanted to be, with swig -version reporting 3.0.12.

Build Take Two

This time, running

swift/utils/build-toolchain org.swift

chugged its way through without falling over, and left me with a tar archive:

swift-LOCAL-2018-07-26-a-osx.tar.gz

\o/

Installing

Expanding this archive leaves you with a usr/ folder containing a fairly normal looking set of sub-folders - bin/, lib/, and so on.

So the simplest “installation” approach is to just get the usr/bin folder into the PATH environment variable.

Exactly where to put the built files is really down to personal preference.

My current strategy is to put them into /usr/local/share/swift/<version>/, symbolically link the version I’m currently using as /usr/local/share/swift/current, and then add /usr/local/share/swift/current/usr/bin to my PATH.

Having the symbolic link in there is just an extra layer of indirection1, allowing me to switch to switch quickly between alternate builds.

Your Mileage May Vary

So far, this seems to have achieved what I wanted. I’ve got Swift up & running, without (hopefully) accidentally upgrading to the complete testing version of Debian.

If this works for you, or doesn’t, or if you’ve got suggestions for a better approach, give me a shout on Micro.blog or Twitter.


  1. well known in computing circles to be the solution to all problems ;)