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.

Setup

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.

Software Updates

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

Other Setup

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
    • Change CONF_SWAPSIZE to 2048 and reboot
  • Install screen in 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: screen -ls
  • Install htop for monitoring cpu/memory during build
    • sudo apt-get install htop

Relax

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: ./swift/utils/build-script

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 git@github.com:apple/swift.git swift
  • git clone git@github.com:hpux735/swift-llvm.git llvm
  • git clone git@github.com:apple/swift-clang.git clang
  • git clone git@github.com:apple/swift-lldb.git lldb
  • git clone git@github.com:apple/swift-cmark.git cmark
  • git clone git@github.com:apple/swift-llbuild.git llbuild
  • git clone git@github.com:apple/swift-package-manager.git swiftpm
  • git clone git@github.com:apple/swift-corelibs-xctest.git
  • git clone git@github.com:apple/swift-corelibs-foundation.git
  • git clone git@github.com:apple/swift-corelibs-libdispatch.git
  • git clone git@github.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 swiftc not 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.

Gotchas

SR-623

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

Foundation

@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

SR-1412

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

The Result

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