Swift on Raspberry Pi

The Raspberry Pi 4 (Pi image courtesy of Michael Henzler via Wikimedia Commons)

After the horrible experience just acquiring, installing, & configuring a basic Raspberry Pi, I was anticipating much effort – likely ending in failure – to get Swift working.

I was pleasantly surprised.

There are multiple ways to do it, apparently. One would think that there’d be the correct & working packages already available through apt, but just as with Docker, one would be wrong. In the case of Swift, there is the Swift-ARM site & group that does provide a package repo with pre-built binaries (and various tutorials on using them), but oddly they don’t provide the current version of Swift.

An alternative is the buildSwiftOnARM Github repo. They merely provide tarballs, which is slightly suboptimal, but very straightforward and they have tarballs for essentially every version – major and minor – of Swift to date. The git history also indicates that they’re very prompt about building tarballs as new versions are released.

Better yet, they provide a couple of shell scripts to build Swift from scratch from source. Only a couple of dependencies (e.g. clang) need be pre-installed, which can be done quickly & painlessly via apt.

Installing from source is presumably the least reliable approach, but since I had already resigned myself to a miserable experience, I figured I might as well go all in.

However, it works. Perfectly. Sure, it takes some time to pull down the huge source base for Swift and all its core dependencies, and some time to build it (though not that long – hours, not days, contrary to what I read online). But the end result was a working toolchain.

It remains to be seen exactly how good or bad Swift development on Linux is, given the absence of the numerous Apple system libraries which are what actually distinguish macOS development above other platforms, but at least getting Swift itself installed is painless.

Sidenote: SATA to USB

The only real speedbump in the whole process, for me, had nothing actually to do with installing Swift itself, but rather the external storage situation on the Raspberry Pi.

The Raspberry Pi doesn’t offer SATA directly, unfortunately (let-alone any form of pluggable PCIe). MicroSD is a low-performance, low-reliability, and high-cost option. So to attach any significant storage you’re basically going either through Ethernet (e.g. NAS) or USB.

USB to SATA adaptors are a shitshow. I’ve tried at least half a dozen different vendors’ offerings over the years, and every single one has been super buggy. The one I newly acquired for my Raspberry Pi use proved to be no exception.

Long story short on that, the symptoms were I/Os taking incredibly long times to complete (many seconds each, serialised), and generally unusable performance. /var/log/messages contained countless pages of:

Oct 13 11:13:45 applepi kernel: [  234.087294] sd 0:0:0:0: [sda] tag#2 uas_eh_abort_handler 0 uas-tag 1 inflight: CMD IN
Oct 13 11:13:45 applepi kernel: [  234.087306] sd 0:0:0:0: [sda] tag#2 CDB: opcode=0x28 28 00 77 3b ce 00 00 00 d0 00
Oct 13 11:13:45 applepi kernel: [  234.126541] scsi host0: uas_eh_device_reset_handler start
Oct 13 11:13:45 applepi kernel: [  234.277450] usb 2-2: reset SuperSpeed Gen 1 USB device number 2 using xhci_hcd
Oct 13 11:13:45 applepi kernel: [  234.312541] scsi host0: uas_eh_device_reset_handler success
Oct 13 11:14:15 applepi kernel: [  264.805760] sd 0:0:0:0: [sda] tag#7 uas_eh_abort_handler 0 uas-tag 2 inflight: CMD IN
Oct 13 11:14:15 applepi kernel: [  264.805778] sd 0:0:0:0: [sda] tag#7 CDB: opcode=0x28 28 00 77 3b d1 b8 00 00 48 00

Turns out this is an incredibly common problem with USB to SATA adaptor chipsets, that’s documented as such all over the web. Finding how to solve it was less trivial, because a lot of the advice given is either outright wrong or at least doesn’t work on Raspbian. The solution I found, via this random thread, was to simply add:

usb-storage.quirks=152d:1561:u

…to /boot/cmdline.txt (where 152d:1561 is the vendor & device IDs for the particular chipset used in my case). All other variations on this, involving adding similar magic incantations to files in /etc/modprobe.d etc, simply do not do anything on Raspbian.

‘Fake error’ about immutable values when using popFirst() on Array

It’s been a while since I wrote any meaningful Swift.  How I didn’t miss the Swift compiler’s bullshit error messages.

var someArray = ["Foo", "Bar"]

if let foo = someArray.popFirst() {
    print("Who cares, we never get here anyway.")
}

That yields, on the popFirst() method:  “Cannot use mutating member on immutable value: ‘someArray’ is immutable”.

No it’s not.  It’s simply not.

For whatever reason, if you instead call popFirst() on ArraySlice – ostensibly indistinguishable from a real Array – it works just fine.

var someArray = ["Foo", "Bar"][0...]

if let foo = someArray.popFirst() {
    print("Yet this works correctly.")
}

Sigh.

I presume it’s trying to tell me something stupidly obscure about Swift’s byzantine type system.  Good luck finding out what.  Good luck even finding the definition of the popFirst() method, since Xcode claims it doesn’t exist if you Command-Control-click on it.  But Xcode can’t find most things, so that in itself says very little.

Undocumented Swift conditional compilation macros

swift/lib/Basic/LangOptions.cpp has most of the conditional compilation macros (called “Language Options” in the compiler internally).  Notably the swift() version macro is absent, and doesn’t seem to be defined anywhere…

At time of writing the two undocumented additions, to the os(), arch(), and swift() set, are _endian() and _runtime().

I have no idea if they’re useful or not – does anyone have to care about CPU endianness these days, really? – but there they are.