9/24/2016 Update: See our latest post on building Swift 3.0 on ARMv7 systems such as the Pi 3.
Editor’s Note: This post was updated on 9/4/2016 to reflect the recent updates for Swift 3.0 (in particular it now includes the build of swift-corelibs-libdispatch
).
A number of folks have expressed interest in building Swift 3.0 on their own Raspberry Pi 3. These instructions are for those brave souls who want to do so!
To get started you’re going to need:
- a Raspberry Pi 3
- a UHS-I/class 10 microSD card with a capacity of 16GB or greater (I like the Patriot EP Series for the price combined with relatively high write speeds)
- Ubuntu Xenial 16.04
- Patience
Note that this can be done; we’ve done it, and there are group of folks dedicated to working with Swift on ARM-based devices. Don’t give up. If you do decide to give up we aren’t ones to judge, just head over and download our prebuilt Swift 3.0 package for the Raspberry Pi 2 and 3.
Install Xenial
We will not be using Raspbian here, but rather Ubuntu Xenial. Obtain Xenial with curl
or wget
and then write the filesystem out to your microSD card with dd
.
Note: You’ve read this warning before I’m sure, but it is critical that you put in the right device name where we reference YOUR_DEVICE
below. Failure to do so could destroy your data (they don’t call dd
disk destroyer for nothing).
Using Linux
# wget http://www.finnie.org/software/raspberrypi/ubuntu-rpi3/ubuntu-16.04-preinstalled-server-armhf+raspi3.img.xz # xzcat ubuntu-16.04-preinstalled-server-armhf+raspi3.img.xz | sudo dd of=/dev/YOUR_DEVICE bs=8M
To find your YOUR_DEVICE
insert the microSD into your Linux machine and run dmesg|tail
to see something like
[1255451.544316] usb-storage 4-2:1.0: USB Mass Storage device detected [1255451.544466] scsi host25: usb-storage 4-2:1.0 [1255452.545332] scsi 25:0:0:0: Direct-Access Generic STORAGE DEVICE 0817 PQ: 0 ANSI: 6 [1255452.545670] sd 25:0:0:0: Attached scsi generic sg8 type 0 [1255452.828405] sd 25:0:0:0: [sdh] 15523840 512-byte logical blocks: (7.94 GB/7.40 GiB) [1255452.829402] sd 25:0:0:0: [sdh] Write Protect is off [1255452.829409] sd 25:0:0:0: [sdh] Mode Sense: 23 00 00 00 [1255452.830400] sd 25:0:0:0: [sdh] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA [1255452.835967] sdh: sdh1 [1255452.840401] sd 25:0:0:0: [sdh] Attached SCSI removable disk
In this example your device is /dev/sdh
.
Using OS X (macOS)
I personally prefer to use a separate Linux server for these types of operations, but you can use a Mac as well with homebrew:
# brew install wget xz # wget http://www.finnie.org/software/raspberrypi/ubuntu-rpi3/ubuntu-16.04-preinstalled-server-armhf+raspi3.img.xz # xzcat ubuntu-16.04-preinstalled-server-armhf+raspi3.img.xz|sudo dd of=/dev/rdisk3 bs=8m
Note when using dd
on the Mac its advisable to use /dev/rYOUR_DEVICE
. Using /dev/YOUR_DEVICE
can be painfully slow, as explained here.
To find YOUR_DEVICE
on a Mac, insert the microSD and run diskutil list
in a terminal. Look for the disk that that matches your SD card size (if you have other attached drives of the same size look also at its other attributes to ensure you are using the right one).
# diskutil list ... /dev/disk5 (external, physical): #: TYPE NAME SIZE IDENTIFIER 0: FDisk_partition_scheme *16.0 GB disk5 1: Windows_FAT_32 system-boot 134.2 MB disk5s1 2: Linux 15.9 GB disk5s2
If you are nervous about the steps with diskutil
and dd
, read this walkthrough to gain some confidence. As an aside, if you’re going to make a habit out of working with the Raspberry Pi the wget
, xzcat
, and dd
commands are a critical part of your toolbox. Get comfortable with them.
Update Xenial
Now that you have Xenial written to the microSD card, insert it into the Raspberry Pi 3 and power up! And yes, we’re assuming you have an Ethernet cable attached or you have network connectivity through the miniUSB. You can try to ssh
into the Pi with ssh ubuntu@ubuntu.local
first, but if that fails use your router LAN page to determine the IP address. The default password is ubuntu
.
# ssh ubuntu@192.168.1.115 The authenticity of host '192.168.1.115 (192.168.1.115)' can't be established. ECDSA key fingerprint is 62:e9:f9:09:d0:30:3c:c9:0e:47:a3:42:f5:2c:e2:ae. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.1.115' (ECDSA) to the list of known hosts. ubuntu@192.168.1.115's password: You are required to change your password immediately (root enforced) Welcome to Ubuntu 16.04 LTS (GNU/Linux 4.4.0-1009-raspi2 armv7l) ... WARNING: Your password has expired. You must change your password now and login again! Changing password for ubuntu. (current) UNIX password:
Once you’ve changed your password log back in with the ubuntu
user (and your new password) and update the system with sudo apt-get update
.
Warning: Previous versions of this post suggested running sudo apt-get upgrade -y
as well. See the comments below for the workarounds if you cannot login via Ethernet afterwards.
Install Build Prerequisites
Compiling Swift requires a number of prerequisites. Get them in one fell swoop with:
# sudo apt-get install -y git cmake ninja-build clang uuid-dev libicu-dev icu-devtools libbsd-dev libedit-dev libxml2-dev libsqlite3-dev swig libpython-dev libncurses5-dev pkg-config autoconf libtool systemtap-sdt-dev libcurl4-openssl-dev
Fortunately we didn’t have to discover the prerequisites iteratively (you know, when you download a repository and try to build it and discover what the prerequisites are, one at a time) because they are outlined in the Open Source Swift README.
I also like to include htop
(sudo apt-get install -y htop
) so I can see the Pi compile it’s little heart out:
Add Some Swap
While the Pi 3 does come with an impressive 1GB of RAM, that is still not enough to build Swift from beginning to end (it’s the linking steps that usually get us into trouble). Let’s add some swap to double that amount:
# cd /var/cache # sudo mkdir swap # cd swap # sudo fallocate -l 1G 1G.swap # sudo mkswap 1G.swap Setting up swapspace version 1, size = 1024 MiB (1073737728 bytes) no label, UUID=184d002a-2f15-4b23-8360-8e792badc6a2 # sudo chmod 600 1G.swap # sudo swapon 1G.swap
Here’s an example of what happens when you don’t have swap enabled:
cd /root/workspace/Swift-3.0-Pi3-ARM-Incremental/build/buildbot_linux/swift-linux-armv7/bin && /usr/bin/cmake -E create_symlink swift swiftc && cd /root/workspace/Swift-3.0-Pi3-ARM-Incremental/build/buildbot_linux/swift-linux-armv7/bin && /usr/bin/cmake -E create_symlink swift swift-autolink-extract clang: error: unable to execute command: Killed clang: error: linker command failed due to signal (use -v to see invocation) ninja: build stopped: subcommand failed. ./swift/utils/build-script: fatal error: command terminated with a non-zero exit status 1, aborting
Doubling the amount of your Pi’s RAM with swap space that’s on a microSD card is not something you would typically do. Once we do hit the build phases that require us to dip into swap things will slow down, but the alternative is to crash with an out-of-memory error.
Use package-swift
package-swift
is our Github repository that has several helper scripts to make life a little easier building Swift.
# git clone https://github.com/iachievedit/package-swift # cd package-swift
By default package-swift
will check out to the swift-3.0
branch. This branch contains important patches needed to properly build Swift for ARM (to see them take a look in patches/armv7
, they are organized by the various repos they patch).
The scripts are pretty simple:
get.sh
– Downloads all of the required repositories for building Swiftupdate.sh
– Updates all of your local repositories with the latest on Github.patch.sh
– Applies any patches that the Swift on ARM team has put forward; from time to time we have to apply patches to get things working. Once a patch is no longer necessary we remove it, so before performing the actual build you will want togit pull
to get the latest patchsetpackage.sh
– Runs the Swiftbuild-script
with a preset namedbuildbot_linux_armv7
.
I suggest you look at each shell script and walk through the logic before executing. They are straightforward but it’s worth the time understanding what they are doing. Pay particular attention to the get.sh
and update.sh
scripts in that they detect we are building on a ARMv7 processor and thus need William Dillon’s swift-llvm
fork.
Let’s Do This
Remember to make sure you have:
- installed all of the prerequisite packages
- enabled 1GB of swap space
- cloned
package-swift
from Github
Now, clone all of the required repositories:
# cd package-swift # ./get.sh
On my SD card this step took about 15 minutes to download and write everything.
Next, apply patches. It is important to do the step to pick up patches that the Swift on ARM team has developed and tested. From time to time these patches change so make sure and pick up the latest.
# ./patch.sh
Now, compile. The Swift on ARM team uses Jenkins to run this in a headless build job, but if you use nohup
to ensure your compile continues even if the terminal detaches you should be fine:
# nohup ./package.sh > swiftbuild.log&
To watch the output of the build use tail -F swiftbuild.log
.
Now, be prepared to wait! A clean build of Swift on a Raspberry Pi 3 can take upwards of 6 hours. The reward is well worth it, however, and that is a swift.tar.gz
bundle that can be installed on either a Raspberry Pi 2 or Pi 3 running Ubuntu Xenial (do not try to install this on a Raspbian machine, you will be sorry). I like to install Swift in /opt/swift/
like so:
# cd /opt # mkdir -p swift/swift-3.0 # cd swift/swift-3.0 # tar -xzvf /path/to/swift.tar.gz
You can then set your PATH
with export PATH=/opt/swift/swift-3.0/usr/bin:$PATH
. To properly use swiftc
and swift build
you will also need to run the following commands:
sudo apt-get install -y libicu-dev sudo apt-get install -y clang-3.6 sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-3.6 100 sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-3.6 100
Getting Help
There is a high likelihood that your build will fail the first time. In fact, it is possible that builds for ARM devices such as the Raspberry Pi 2 and 3 will be failing for days until someone is available to fix them. If you are having trouble compiling please feel free to send an e-mail to admin@iachieved.it
to get invited to the Swift for ARM Slack community.
Acknowledgements
I should probably put up a separate page just for this; a number of folks have been instrumental in getting Swift going on ARM devices. Folks like PJ have blazed the trail building Swift for the Raspberry Pi 1, and no article on Swift on the Pi is complete without mentioning William Dillon’s work.
For some reason
sudo apt-get upgrade
lead to the system no longer working properly, that is, I couldn’t login via SSH after reboot.I followed this other guide and just downloaded the binary and this worked fine:
http://dev.iachieved.it/iachievedit/swift-3-0-on-raspberry-pi-2-and-3/
Thanks to everybody who’s working on bringing Swift to these devices!
When I hit this, the helpful folks in the swift-arm channel pointed out that this is a known bug in Xenial https://bugs.launchpad.net/ubuntu/+source/systemd/+bug/1579969 and gave a workaround: Look at the list of interfaces with
ifconfig -a
. One of these (for me at least) was named with a long string starting with ‘en’. Edit /etc/network/interfaces.d/50-cloud-init.cfg and replace the two occurrences of eth0 with the name of the ethernet device, reboot, and ethernet connections should be possible again.Thanks for the workaround Tim!
This guide is valid for armv6 too? (raspberry pi zero)