Building Swift For ARMv6
Building Swift For ARMv6
Back in March I wrote about using Swift on my Raspberry Pi Model B (an ARMv6 device). I was using the swift 3.0 binary that @uraimo built and shared from here.
Since then, a group of people came together via a Slack chat to help the ‘Swift for ARM’ processor effort, details here. I joined and didn’t know how to start contributing so, I figured a good way to learn was to build Swift myself. I only have an ARMv6 Pi, so I started there. @uraimo mentions in his blog post, ‘100s of hours of compiling…’, but I knew I could just leave it compiling on my desk, and go about my normal business. This way we can get newer binaries for ARMv6 (Pi1 or PiZero), while we wait for cross-compiling to get finished. Also, by documenting the steps I took, maybe I’ll make it easier for someone else to get started in the Swift for ARM world.
I started by installing Raspbian Lite using a brand new 32gb SD card. This way I could keep my daily Raspbian image, while having a special ‘dev’ card for Swift builds. Details for getting Raspbian and imaging (from OSX) are here and here.
I run everything headless, so after getting a bootable image on the card, I connected via ethernet to setup wifi. Easiest way to find the IP:
arp -na | grep -i b8:27:eb Once on the Pi, I move my public SSH key to the
authorized_keys file on the Pi, so I can SSH in easily. Details here on that.
Also don’t forget to expand the file system using
sudo raspi-config, so you get full use of the 32gb card.
Then I setup wifi, here is a good link on that.
With the Pi setup, its time to get the proper tools. First update packages:
sudo apt-get update
Install general dependencies needed for building Swift:
sudo apt-get install git cmake ninja-build clang python uuid-dev libicu-dev icu-devtools libedit-dev libxml2-dev libsqlite3-dev swig libpython-dev libncurses5-dev pkg-config
I like using SSH with Github (others are fine with https), so if you like SSH, its probably best to make a new SSH key so you can reject it from your account (should something go wrong). Details for making and installing a new SSH key are here.
One of the best posts about building Swift for Pi’s comes from MoriMori, be sure to see the updated post here. Some tips I picked up from that blog post:
- Make a big swap file
sudo vi /etc/dphys-swapfile
CONF_SWAPSIZEto 2048 and reboot
screenin case your connection stalls:
sudo apt-get install screen
- Start a new screen:
screen -S buildswift
- Reattach to screen:
screen -r buildswift
- List current screens:
htopfor monitoring cpu/memory during build
sudo apt-get install htop
Ok, now the system is setup, next we need to dig into the code. The Swift build process was extremely overwhelming to me at first. The important piece to understand is in the main Swift repo, the
build_script file. This file is the center of building Swift. There are various tools for helping to clone code & updating code, but I think these lines in
build_script are key to understand:
'build-script' expects the sources to be laid out in the following way: $SWIFT_SOURCE_ROOT/llvm /clang /swift /lldb (optional) /llbuild (optional) /swiftpm (optional, requires llbuild) /compiler-rt (optional) /swift-corelibs-xctest (optional) /swift-corelibs-foundation (optional) /swift-corelibs-libdispatch (optional)
This comment shows you:
- how to lay out the various repos
- that basically everything (barring llvm, clang & swift) are OPTIONAL
Once you realize that, it simplifies things a bit. While
build_script has a ton of switches and is very complex, you can get a build going by doing a simple:
I urge anyone interested to spend some time reading the comments in
build_script, it really de-mystifies the whole process.
The Clone Army
To actually get the code, you can clone the repos yourself or you can use a script. As we saw above, it is important to lay out the directories as
build_script wants them. I initially cloned the repos myself, so I would understand everything:
git clone email@example.com:apple/swift.git swift
git clone firstname.lastname@example.org:hpux735/swift-llvm.git llvm
git clone email@example.com:apple/swift-clang.git clang
git clone firstname.lastname@example.org:apple/swift-lldb.git lldb
git clone email@example.com:apple/swift-cmark.git cmark
git clone firstname.lastname@example.org:apple/swift-llbuild.git llbuild
git clone email@example.com:apple/swift-package-manager.git swiftpm
git clone firstname.lastname@example.org:apple/swift-corelibs-xctest.git
git clone email@example.com:apple/swift-corelibs-foundation.git
git clone firstname.lastname@example.org:apple/swift-corelibs-libdispatch.git
git clone email@example.com:apple/swift-compiler-rt.git
Note that the LLVM is from @hpux735. He did a bunch of work to support ARM processors, and for ARM work its best to build on that.
However, I quickly tired of manually cloning and updating the repos, so I started using a set of scripts from @iachievedit for building & packaging Swift, the repo is here. To use this, simply clone it and run
./get.sh. This will clone the proper repos for you. Also included are scripts for updating and cleaning.
One interesting note: I initially screwed up and used the master branch of LLVM, not @hpux735’s. After days of compiling, it actually worked, but only
swift, details on the difference of those (symlinked) tools are here
Start The Build
With a fresh clone, as updated as possible, its time to kick off the build. Here is the exact command I used:
swift/utils/build-script -R -- \ --install-swift \ --install-foundation \ --install-prefix=/usr \ --foundation \ --install-destdir="/tmp/swift" \ '--swift-install-components=autolink-driver;compiler;clang-builtin-headers;stdlib;sdk-overlay;license' \ --reconfigure
These switches look scary, but most of them are just about the install/packaging step. This build will attempt to build
Foundation, and install Swift and Foundation in
/tmp/swift, which makes it easy to compress the results for sharing!
So kick that off, and relax, because on an ARMv6 it will probably take ~3 days.
The first issue I ran into when using
swiftc was this bug. It might be due to not using @hpux735’s LLVM though (currently building with that right now). Either way, it was solvable by adding
-target armv6-unknown-linux-gnueabihf to the build like this:
./bin/swiftc -target armv6-unknown-linux-gnueabihf helloworld.swift
@hpux735 also did a bunch of work to get Foundation working on ARMv7, so I submitted a pull request to extend that work to include ARMv6, here
I ran into heavy problems with
va_list discussed in this bug. A workaround patch is listed, which involves adding a switch to the Foundation build:
-Xcc -D_VA_LIST This allows the build to finish, but I found I had to also add that switch to any
swiftc compiles also, so now the line looks like:
./bin/swiftc -target armv6-unknown-linux-gnueabihf -Xcc -D_VA_LIST helloworld.swift
Since it takes a loooong time, I recommend backups…I foolishly screwed up one SD card by trying to install clang 3.6 for a different architecture. Here is a good link for making a complete image of the card.
And if you just want the goods, here is a tar of my most recent build for ARMv6 (with the above caveats).