-
Notifications
You must be signed in to change notification settings - Fork 4
Swift on Raspberry Pi
Prev: Raspberry Pi Setup
Swift is my favorite programming language of the moment, and it's combination of a high-level syntax while still being compiled to native code, make it an attractive option for working with the Raspberry Pi hardware.
Unfortunately while the Linux port is an actively maintained and supported part of the project, it's intended for Intel processors.
The 32-bit ARM processor in the Raspberry Pi isn't natively supported by Swift, but there is an active community that attempts to make it work.
With a little effort, and with the patches from uraimo's buildSwiftOnARM repository, we can build a working toolchain.
Swift's build dependencies are documented in the README of the main repository.
sudo apt-get install cmake ninja-build clang python uuid-dev libicu-dev icu-devtools libbsd-dev libedit-dev libxml2-dev libsqlite3-dev swig libpython-dev libncurses5-dev pkg-config libblocksruntime-dev libcurl4-openssl-dev autoconf libtool systemtap-sdt-dev
As of stretch, these are almost all of the correct versions.
The one exception is that the swig
package in stretch is, unluckily, one of a couple of minor revisions that are known not to work with the Swift build process.
To work around this, we use the source from Debian unstable to build a version that will work:
wget http://http.debian.net/debian/pool/main/s/swig/swig_3.0.12-1.dsc \
http://http.debian.net/debian/pool/main/s/swig/swig_3.0.12.orig.tar.gz \
http://http.debian.net/debian/pool/main/s/swig/swig_3.0.12-1.debian.tar.xz
dpkg-source -x swig_3.0.12-1.dsc
sudo apt-get install bison debhelper dh-autoreconf default-jdk guile-2.0-dev libchicken-dev libperl-dev libpcre3-dev python-dev ruby ruby-dev tcl-dev tk-dev
(cd swig-3.0.12 && dpkg-buildpackage -uc -us)
sudo dpkg -i swig_3.0.12-1_armhf.deb swig3.0_3.0.12-1_armhf.deb
A source build of Swift consists of more than the main repository for the language, but also the compiler, debugger, standard library, support libraries, and more.
We'll create a working directory to serve as the top-level for the build:
mkdir swift-source
cd swift-source
The master
or HEAD
of the repositories is the latest development version, intended for release alongside the next version of Xcode. We rarely want something that bleeding edge, and thanks to the community nature of the 32-bit ARM support, it rarely works anyway.
To checkout the Swift 4.1.1 release, we use the swift-4.1.1-RELEASE
tag:
git clone -b swift-4.1-RELEASE https://github.com/apple/swift.git
./swift/utils/update-checkout --clone --tag swift-4.1-RELEASE
Swift 4.1.1 needs a few patches in order to build, which we can obtain from the buildSwiftOnARM project. We'll checkout that alongside our sources as well:
git clone https://github.com/uraimo/buildSwiftOnARM.git
We'll then apply those to the appropriate repositories:
for PATCH in buildSwiftOnARM/*.diffs/*.diff; do \
( cd $(echo "$PATCH" \
| sed -e "s,[^/]*/,,;s,.diffs/.*,,") \
&& patch -p1 < ../"$PATCH" ); \
done
Swift comes with a script that manages building all of the different components and dependencies in the correct order (and in some cases, rebuilding them again).
The following arguments are those currently recommended for the Raspberry Pi:
./swift/utils/build-script \
--build-subdir out_linux \
-R \
--lldb \
--llbuild \
--xctest \
--swiftpm \
--foundation \
--libdispatch \
-- \
--install-libdispatch \
--install-foundation \
--install-swift \
--install-lldb \
--install-llbuild \
--install-xctest \
--install-swiftpm \
--install-prefix=/usr \
'--swift-install-components=autolink-driver;compiler;clang-builtin-headers;stdlib;swift-remote-mirror;sdk-overlay;dev' \
--build-swift-static-stdlib \
--build-swift-static-sdk-overlay \
--install-destdir=$(pwd)/install \
--installable-package=$(pwd)/swift-4.1.1.tar.gz \
--verbose-build
This will create a build/
sub-directory containing the intermediate build output, a tree under install/
containing the staged for installation, and a swift-4.1.1.tar.gz
package file of that tree.
Since Swift's support for the Raspberry Pi varies between releases, it's good practice to keep a working toolchain around as long as possible, and always give yourself the chance to rollback to a last known good one.
To achieve this, I like to install the binaries underneath /opt/swift
with a tree for each version, rather than just unpacking it all into /usr
each time.
Symlinks manage the current version:
sudo mkdir -p /opt/swift
sudo tar xzf swift-4.1.1.tar.gz -C /opt/swift
sudo mv /opt/swift/usr /opt/swift/4.1.1
sudo ln -sf /opt/swift/4.1.1/* /opt/swift
Add /opt/swift/bin
to your PATH
for convenience:
echo 'PATH=$PATH:/opt/swift/bin' >> ~/.profile
We can now test it out.
swift --version
Swift version 4.1.1 (swift-4.1.1-RELEASE)
Target: armv7-unknown-linux-gnueabihf
mkdir HelloWorld
cd HelloWorld
swift package init --type executable
Creating executable package: HelloWorld
Creating Package.swift
Creating README.md
Creating .gitignore
Creating Sources/
Creating Sources/HelloWorld/main.swift
Creating Tests/
swift build
Compile Swift Module 'HelloWorld' (1 sources)
Linking ./.build/debug/HelloWorld
swift run HelloWorld
Hello, world!
Next: Integers