An Update on Swift 3.1.1 For Raspberry Pi Zero/1/2/3
Posted on May 1, 2017
Update 6th Sept: Swift 3.1.1 with SPM now compiles correctly on the latest Raspbian, check out the post here.
Update 12th May: Added section on cross compilation.
I think it’s time for another update on the status of Swift on Raspberry Pi and other ARM boards.
If you are using a Raspberry Pi 2 or 3 with Ubuntu Mate 16.04, that has been for some time the distribution I recommend, you can just download release 3.1.1 from here(install the dependecies with: sudo apt install clang-3.8 libicu-dev libcurl4-nss-dev) or use the updated buildSwiftOnARM scripts to build your own binaries.
Just decompress the tgz archive and both swiftc
and swift
will be available under ./usr/bin
. Use the former to compile Swift files directly or the swift binary to access additional tools like SPM (as usual the REPL will not be available).
Thanks to Florian Friedrich most of the patches required to compile on ARM have been integrated into the Swift master and 3.1 branches.
If you have an ARMv6 board like the original Raspberry Pis or the new Zero boards or you are just running Raspbian, at the moment it’s not possible to compile successfully releases of Swift newer than 3.0.2.
That release could be enough for what you want to do and if it is, you can find it here (and yes, there is still no SPM on Raspbian/Debian, but read the section on cross compilation).
The community built around the swift-arm Slack channel have been working on trying to get Swift to compile on Raspbian (or other Debians) since the 3.1 release and some progress has been made.
There are already some patches (that are needed on some Ubuntus too) and a couple of issues have been opened to track the current blocking issues: SR-4613, SR-4147.
As usual, 3.1.1 have been tested with SwiftyGPIO and everything appears to work.
Building on Docker and Cross-Compilation
Another recent development is the new dockSwiftOnARM project by Helge Heß that allows to run or even build Swift in an ARM docker container running on Linux or macOS, quite convinient and well documented.
A few weeks ago the Swift Package Manager finally gained support for cross compilation.
Thanks to Johannes Weiß for the great work he’s done on cross-compilation and toolchains generation.
This means that now you can finally cross-compile ARM binaries from a Mac (or from Ubuntu), follow these detailed instructions from Helge Heß to build your own SPM-capable cross-compiling toolchain that produces Swift 3.1.1 ARM binaries for Ubuntu 16.04 on macOS.
Cross-compiling Toolchain for Swift 3.0.2 on Raspbian
The instructions above can be slightly modified to produce a toolchain that builds binaries that work with Swift 3.0.2 on Raspbian, but more important, has a working SPM!
A few things need to be changed from what is described in the original guide.
Download the Swift 3.0.2 packages instead of the 3.1.1 ones:
curl -o /tmp/swift-3.0.2-RPi1Zero-RaspbianNov16.tgz https://www.dropbox.com/s/dkrkt9ht1c3hog2/swift-3.0.2-RPi1Zero-RaspbianNov16.tgz
curl -o /tmp/swift-3.0.2-RELEASE-osx.pkg https://swift.org/builds/swift-3.0.2-release/xcode/swift-3.0.2-RELEASE/swift-3.0.2-RELEASE-osx.pkg
Launch the script with these parameters:
./build_rpi_ubuntu_cross_compilation_toolchain \
/tmp/ \
/tmp/swift-3.0.2-RELEASE-osx.pkg \
/tmp/swift-3.0.2-RPi23-RaspbianNov16.tgz
The toolchain will be built correctly but SPM will not work because the swiftc from Swift 3.0.2 does not support the new -swift-version
option that the package manager appends when calling the compiler.
Let’s build a version of the package manager without this option.
Clone SPM:
cd /tmp/
git clone https://github.com/apple/swift-package-manager.git
Save this patch in a file and apply it (patch -p1 < file.diff
):
diff --git a/Sources/Build/BuildPlan.swift b/Sources/Build/BuildPlan.swift
index 5c48fb57..af50f539 100644
--- a/Sources/Build/BuildPlan.swift
+++ b/Sources/Build/BuildPlan.swift
@@ -260,7 +260,7 @@ public final class SwiftTargetDescription {
/// The arguments needed to compile this target.
public func compileArguments() -> [String] {
var args = [String]()
- args += ["-swift-version", String(swiftVersion)]
+ //args += ["-swift-version", String(swiftVersion)]
args += buildParameters.toolchain.extraSwiftCFlags
args += buildParameters.swiftCompilerFlags
args += optimizationArguments
diff --git a/Sources/PackageLoading/ManifestLoader.swift b/Sources/PackageLoading/ManifestLoader.swift
index 9f8f3cbd..02cde4be 100644
--- a/Sources/PackageLoading/ManifestLoader.swift
+++ b/Sources/PackageLoading/ManifestLoader.swift
@@ -306,7 +306,7 @@ public final class ManifestLoader: ManifestLoaderProtocol {
) -> [String] {
var cmd = [String]()
let runtimePath = self.runtimePath(for: manifestVersion)
- cmd += ["-swift-version", String(manifestVersion.rawValue)]
+ //cmd += ["-swift-version", String(manifestVersion.rawValue)]
cmd += ["-I", runtimePath.asString]
#if os(macOS)
cmd += ["-target", "x86_64-apple-macosx10.10"]
Compile SPM:
swift build
Temporarily move the swift-build
binary you are using right now and copy this one (your path could be different, once done with cross-compiling restore the original binary):
cd /Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2017-05-09-a.xctoolchain/usr/bin/
sudo mv swift-build swift-build.old
sudo cp /tmp/swift-package-manager/.build/debug/swift-build /Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2017-05-09-a.xctoolchain/usr/bin/
You can use the toolchain now, move to the root of your project and compile it using the new SPM’s option:
swift build --destination /tmp/cross-toolchain/rpi-ubuntu-xenial-destination.json
The resulting binary will work on your Raspberry Pi with Swift 3.0.2 (remember to update the LD_LIBRARY_PATH
as shown in the guide).
And again, as you have noticed, the procedure is a bit more convoluted with Raspbian.
Did you like this article? Let me know on Twitter!