I spent the last few hours leisurely getting a Swift toolchain installed on my Mac to allow me to cross-compile code for a Raspberry Pi 4 I picked up last week. The RPi is not my favorite embedded computer (I prefer the Beaglebone Black), but I wanted to give it a try, and there’s more support out there for the Raspberry Pi than the BBB.
The community has made excellent strides and put in a lot of effort to get the tools up and running, but like so many open-source projects, documentation is lacking. You can’t skip over many of the steps required to build the tools from scratch, even though they provide and recommend you use the pre-built binaries. Hopefully this will explain how to get everything installed.
Note that they recommend using Docker. I barely understand Docker, and have avoided it so far. I think it lets you run an Arm/Linux environment on the Mac to test your builds. I’m sure that will be convenient, but I haven’t tried it.
There are two basic things that need to be done: install the cross-compiler on macOS, and install the runtime on raspbian.
Installing the Cross Compiler
I’m running Buster Lite on a Raspberry Pi 4 B. Altough the RPi 4 is a 64-bit capable computer, Raspbian is still (annoyingly, 32-bit only). You’ll need the
armv6 version of the toolchain, available from https://github.com/CSCIX65G/SwiftCrossCompilers/releases.
I downloaded the Swift-armv7-5.0.pkg package, but make sure there’s not a more recent version there. Note: the resulting tools should be named with
armv6 in the name, but they’re actually
armhf. Hopefully that’s fixed soon.
Double-click the resulting
.pkg file and let macOS install the pieces.
Installing the Runtime
My RPi 4 is running Raspbian Buster Lite from 2019-07-10.
The easiest way to get the runtime installed on the target machine is to grab a prebuilt toolchain from https://github.com/uraimo/buildSwiftOnARM#prebuilt-binaries. I went with the https://github.com/uraimo/buildSwiftOnARM/releases/download/5.0.2/swift-5.0.2-armv7-DebianBuster.tgz build. Again, check to make sure there’s not a more recent version. It’s probably important that the runtime version you install roughly match the compiler you installed on the Mac above (e.g. v5.0.x, v5.1.x, etc). I don’t know how well the recent Swift ABI stability really works.
To install the toolchain, follow these steps:
$ wget https://github.com/uraimo/buildSwiftOnARM/releases/download/5.0.2/swift-5.0.2-armv7-DebianBuster.tgz $ tar -zxf swift-5.0.2-armv7-DebianBuster.tgz
I install the toolchain under
/opt/swift using a directory structure that lets me keep several versions around. There may be more conventional ways to handle this.
$ sudo mkdir -p /opt/swift/versions/swift-5.0.2-armv7-DebianBuster $ sudo mv usr /opt/swift/versions/swift-5.0.2-armv7-DebianBuster $ sudo ln -s /opt/swift/versions/swift-5.0.2-armv7-DebianBuster /opt/swift/current
When that’s done you should have this:
$ ls -l /opt/swift/ total 4 lrwxrwxrwx 1 root root 50 Aug 25 07:25 current -> /opt/swift/versions/swift-5.0.2-armv7-DebianBuster drwxr-xr-x 3 root root 4096 Aug 25 07:25 versions
PATH with (you might want to add this to the end of
.bashrc or similar):
$ export PATH="/opt/swift/current:$PATH"
Helping Raspbian Find the Runtime
Another important step is to make sure the dynamic loader can find the Swift runtime libraries.
$ sudo su # cat > /etc/ld.so.conf.d/swift.conf <<EOF /opt/swift/current/lib/swift/linux /opt/swift/current/lib/swift/clang/lib/linux /opt/swift/current/lib/swift/pm EOF # ldconfig # exit
At this point you should be able to get the Swift compiler version:
$ swift --version Swift version 5.0.2 (swift-5.0.2-RELEASE) Target: armv7-unknown-linux-gnueabihf
Now you can try their Hello World example. On the Mac, create a directory and use the Swift Package Manager to create a skeleton project. Note that these steps differ a bit from what’s written in the readme at the SwiftCrossCompilers repo:
$ mkdir helloworld && cd helloworld $ swift package init --type=executable $ swift build --destination /Library/Developer/Destinations/armhf-5.0-RELEASE.json $ file .build/debug/helloworld .build/debug/helloworld: ELF 32-bit LSB pie executable ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 3.2.0, with debug_info, not stripped
You should be able to copy this executable to your Raspberry Pi:
$ scp .build/debug/helloworld raspberrypi.local: helloworld
Then, on the Raspberry Pi, try running it:
$ ssh raspberrypi.local $ ./helloworld Hello, world!
I hope I got all the necessary steps correct above. It took me some meandering and retracing my steps to get to this point. I’m publishing this article as much to remind me how I did it as to help others. Please let me know in the comments below if you run into any issues.
Thanks for reading!