This guide was written for FireAlarm, but it will work for other Swift projects as well.
Note: Many of these steps will take a long time (up to several hours). To run a command in the background (so it won't die with your SSH session), I often run the command with time (<command here>) > filename.log 2>&1 &
.
Because some packages are not available in the latest stable release, Raspbian must be updated to Stretch, the testing release. Unfortunately, the Wi-Fi firmware in Stretch is broken. To prevent it from being updated, run sudo apt-mark hold firmware-brcm80211
. If you update to Stretch without doing this (which I did), you can downgrade by running sudo apt-get install firmware-brcm80211=0.43+rpi5
(while connected over Ethernet, of course).
Edit /etc/apt/sources.list
and replace jessie
with stretch
in the first line. The first line should now look like this:
deb http://mirrordirector.raspbian.org/raspbian/ stretch main contrib non-free rpi
Now run sudo apt-get update && sudo apt-get -y dist-upgrade -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold"
to upgrade all installed packages, including the kernel and firmware. On my system, this took several hours. The dpkg
options force the default behavior when replacing configuration files, so it doesn't pause for a prompt.
Install Swift dependencies with:
sudo apt-get install -y git 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
I used these shell scripts to make it easier to download and build Swift:
download.sh
:
#!/bin/bash
FORCE=0
while getopts "f" option; do
case $option in
f)
FORCE=1
;;
?)
echo "Usage: download.sh [-f]"
;;
esac
done
mkdir -p build
cd build
REPOS=('swift' 'swift-llvm'
'swift-clang' 'swift-lldb'
'swift-cmark' 'swift-corelibs-xctest'
'swift-corelibs-foundation' 'swift-corelibs-libdispatch')
DIRS=( 'swift' 'llvm'
'clang' 'lldb'
'cmark' 'swift-corelibs-xctest'
'swift-corelibs-foundation' 'swift-corelibs-libdispatch')
for ((i=0;i< ${#REPOS[@]};i++)) do
REPO=${REPOS[$i]}
DIR=${DIRS[$i]}
BRANCH=${BRANCHES[$i]}
if [ ! -d "$DIR" ] || [ $FORCE = 1 ]; then
[ -d "$DIR" ] && rm -rf "$DIR"
git clone "git://github.com/apple/${REPO}.git" "$DIR" -b swift-3.1-branch
else
echo "$REPO already exists; not overwriting without -f"
fi
done
pushd swift-corelibs-libdispatch
git submodule init && git submodule update
popd
build.sh
:
#!/bin/bash
BUILD_DIR=$(pwd)/build
cd "$BUILD_DIR" || (echo "Directory '$BUILD_DIR' doesn't exist."; exit 1)
DATE=$(date +%F)
swift/utils/build-script --no-assertions --no-swift-stdlib-assertions \
--release --libdispatch --lldb --foundation --install-xctest \
--install-foundation --install-libdispatch --install-lldb \
--swift-enable-ast-verifier=0 --install-swift --install-foundation --install-prefix=/usr \
'--swift-install-components=compiler;clang-builtin-headers;stdlib;sdk-overlay;dev' --build-swift-static-stdlib=1 --skip-test-lldb=1 \
--install-destdir="$BUILD_DIR/dest" \
--installable-package="$BUILD_DIR/swift-$DATE.tar.gz" --release
After running download.sh
, we need to make a few patches for it to build.
The swift_build_support
import path in SwiftBuildSupport.py
needs to have priority. Change this line (line 23 when I built):
sys.path.append(os.path.join(os.path.dirname(__file__), 'swift_build_support'))
to:
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'swift_build_support'))
Go to the declaration of COMMON_C_FLAGS
in swift/utils/build-script-impl
. On my system, this was line 1525. It should contain:
COMMON_C_FLAGS=""
Edit it to:
COMMON_C_FLAGS="-mfpu=vfpv4"
This disables NEON instructions, which were having an alignment issue. I'll try to come up with a real fix, but this works for now.
If you want LLDB to work, change the definition of LLDB_EDITLINE_USE_WCHAR
on line 50 of lldb/include/lldb/Host/Editline.h
to 1
.
LLVM's swift-3.1-branch
Unicode functions are not in the llvm
namespace, where Swift expects to find them. cd
to llvm
and run git cherry-pick 449cdb5ad51c7720c9f5eecdcb1d142044f16721
to cherry pick a commit which fixes this.
Unfortunately, Clang's swift-3.1-branch
does not expect to find the files in the LLVM namespace. Cherry-pick a commit to fix this by cd
ing to clang
and running git cherry-pick dd052623fdb8f7292a60486e46c498a4294ad581
.
There are some bugfixes in Foundation's swift-3.1-branch
which are not in master
, and vice versa. To fix it, cd
to swift-corelibs-foundation
and run git merge --strategy-option theirs master
.
CoreFoundation makes an assumption about structure size which is not true on Raspberry Pi (because of alignment). Go to swift-corelibs-foundation/CoreFoundation/NumberDate.subproj/CFNumber.c
and change this line (line 1203 when I built):
CFIndex size = 8 + ((!__CFNumberTypeTable[type].floatBit && __CFNumberTypeTable[type].storageBit) ? 8 : 0);
to:
CFIndex size = sizeof(struct __CFNumber) - sizeof(CFRuntimeBase);
if (!__CFNumberTypeTable[type].floatBit && __CFNumberTypeTable[type].storageBit) size += 8;
In order for the Swift JIT interpreter to work (which is necessary for the Swift Package Manager), cd
to llvm
and cherry-pick a commit from https://github.com/swift-arm/swift-llvm:
git remote add swift-arm https://github.com/swift-arm/swift-llvm
git fetch swift-arm
git cherry-pick 95581a28b69cc7ea811055891b499576fdfc8ed7
You may get a few more compiler errors. Here's how to fix the ones I ran into:
Add an #include "llvm/Support/ErrorHandling.h"
to the file.
This is because the version of linux-libc-dev
in Raspbian is ancient and is missing membarrier.h
. To work around it, replace the #include
on line 93 of swift-corelibs-libdispatch/src/shims/lock.h
with the code that is supposed to be in that (thankfully tiny) header and the syscall number definition for membarrier
:
enum membarrier_cmd {
MEMBARRIER_CMD_QUERY = 0,
MEMBARRIER_CMD_SHARED = (1 << 0),
};
#define __NR_membarrier (__NR_SYSCALL_BASE+389)
This is because something's messed up with header files. Replace the line with the error with an abort();
(and maybe a printf for debugging). If you get a linker error mentioning DISPATCH_INTERNAL_CRASH
, clean libdispatch (by removing build/build/Ninja-Relase/libdispatch-linux-armv7
) and try again.
Once the build completes successfully, it's time to install Swift. The build script will generate a .tar.gz
file contaiing the Swift binaries, which you can install in /usr/bin
, /usr/lib
, etc. by running sudo tar -C / -xzf filename.tar.gz
. You can omit the -C /
flag to install it in the current directory, which makes it far easier to uninstall Swift (but be sure to add the created usr/bin
directory to your PATH).
For whatever reason, the installable package was missing swift-autolink-extract
. This caused swiftc
to fail silently, compiling the code successfully but not generating an executable. I fixed this by copying build/build/Ninja-Release/swift-linux-armv7/bin/swift-autolink-extract
into /usr/bin
.
Additionally, the Dispatch module is installed into the wrong directory. Copy Dispatch.swiftdoc
and Dispatch.swiftmodule
from /usr/lib/swift/linux/armv7l
into /usr/lib/swift/linux/armv7
.