Cross-compilation Swift SDKs for Android

There are now Swift 5.4 cross-compilation SDKs for AArch64, armv7, and x86_64 available, which you can use with a prebuilt Swift toolchain to cross-compile packages like swift-crypto or swift-system for Android with the Swift package manager.

Instructions on building and testing those packages on an Android device or emulator are in the README. Building with these SDKs is primarily tested on linux, but using them on Mac or Windows should be possible too.

I have set up a daily CI on github Actions that builds latest trunk of five Swift packages for all three architectures, then runs their tests for Android x86_64 in an emulator.

I plan to set up the same for the 5.5 branch snapshots and trunk, which will build the latest Swift SDK from source before testing it. I will also add some Swift scripts to automate the configuration of the SDK and building it.

Any suggestions of Swift packages to add to this Android CI are welcome, and you could use the CI script as an example to build or test packages yourself. Right now, the largest package tested on the CI is Swift NIO, which is about 60k lines of Swift code, about half tests.

I have also put out a Swift 5.4 toolchain that runs on Android in the Termux app, which can be used on Chromebooks that support running Android apps too.

22 Likes

With the release of Android NDK 23 a couple weeks ago, I've put together Swift 5.4.2 cross-compilation SDKs that can be used with this latest NDK.

The daily CI now builds the latest trunk commit of 11 Swift packages against all three Swift toolchains, ie 5.4.2 and the 5.5 and trunk snapshots, for the three Android architectures to make sure everything is still working. A few tests and packages are currently disabled from that matrix, for example, Swift NIO is only built by 5.4 because its tests currently can't be built by the 5.5 and trunk toolchains because of compiler regressions, which is reproducible on linux.

Building an Android SDK yourself is now easy because I added a Swift script to automate most of the setup. I will add a couple more Swift executables next, to similarly automate getting the Android SDK configured in your local environment.

Please report any problems by opening an issue on that github repo.

11 Likes

You might already have considered and rejected this, but it sounds like maybe the Source Compatibility Suite could be useful here?

That would be a good place to get ideas for Swift packages to add, but I doubt I will add server-oriented packages like Vapor. Some of the client-side packages make sense, but I may not need or be familar with them myself, pulls welcome.

As you can see with this pull adding two Swift packages, it is pretty easy. I need to switch the Android emulator to run on macOS soon, as it runs without hardware acceleration on linux in the github-provided CI VMs so the 11 testsuites take 90-120 mins. on there, as opposed to several mins. on my Android AArch64 phone.

3 Likes

I've added cross-compilation SDKs for Swift 5.5, which work with the latest Android NDK 23.

There is also a Swift 5.5 toolchain that runs natively on Android in the Termux app, which now includes a sourcekit-lsp package for the first time. Simply install that app on an Android phone or tablet, run pkg install swift sourcekit-lsp, and you can use sourcekit-lsp from the LSP-compatible editor of your choice.

I haven't tested it extensively, but simple things like jumping to the definition of a symbol in the same Swift file appear to work. Thanks to @blangmuir and everyone else who contributed to sourcekit-lsp.

You can also use this Swift toolchain on most Chromebooks, as most of them support installing Android apps these days, so you can install Termux and Swift on there too.

9 Likes

Android cross-compilation SDKs for Swift 5.6 are now available. The AArch64 SDK will not work with a fraction of devices running Android 11 or newer, because Android AArch64 is currently rolling out memory tagging. As I note in this SDK doc, I have submitted a fix and will update the AArch64 SDK once that is in the prebuilt Swift compiler.

Native builds of the Swift 5.6 toolchain that run on Android in the Termux app should work for 64-bit platforms, but cannot be built for 32-bit armv7 right now, because of some compilation issue that crept in last year. I'm guessing this is true when building the Swift compiler for all 32-bit platforms, as I doubt this is specific to Android armv7. I'll investigate further and update the Swift toolchain for Termux soon.

10 Likes

Awesome work Buttaface, just wanted to say thank you for posting this. I haven't had a chance to try this out yet but looking forward to trying the concurrency features on Android.

1 Like

I just put out Android SDKs for cross-compilation with the latest Android NDK 25b and the Swift 5.6.3 toolchain, the first release to include the fix for the Android memory tagging issue I mentioned six months ago. Thanks to the Swift devs who reviewed that pull and got it merged.

I've also updated the native Swift 5.6 toolchain that runs in the Termux app for Android, which is how I build and use Swift (my desk looks something like this, with an Android device driving a 2560X1600 monitor). I recently built one of the latest 5.7 source snapshots for Android, and while the AArch64 build works well, the 32-bit armv7 compiler still consistently crashes. I'm thinking about dropping support for running the Swift compiler on armv7 devices with 5.7, as I appear to be the only person still building the Swift toolchain for 32-bit devices.

7 Likes

Android cross-compilation SDKs for Swift 5.7 are now available.

Native builds of the Swift 5.7 toolchain that run on Android in the Termux app are also up. While the 32-bit ARM builds have been crashing for many months, I noticed that turning bootstrapping off, ie disabling the portions of the compiler written in Swift, got it to work again.

8 Likes

An Android multi-architecture cross-compilation SDK for Swift 5.8 is now available. The Swift compiler currently does not support multi-architecture library setups other than on Mac and Windows, so I had to add a line to the Android destination config to tell it where I placed the Swift libraries.

Native builds of the Swift 5.8 toolchain that run on Android in the Termux app are also online. Since I build that native compiler and control where the libraries are installed, I put the Swift libraries in <sysroot>/usr/lib/ for the first time (based on a comment by @etcwilde), spun off Swift runtime library and SDK packages that can be used from any Android device, and patched the Swift compiler to look in the right places.

That means cross-compiling Swift in Termux is now as simple as

> pkg install swift swift-sdk-arm
> swiftc -target armv7-linux-android hello.swift

I had to turn bootstrapping the compiler off on 64-bit too, ie disabling the portions of the compiler written in Swift, because of an issue with C++ interoperability between libc++ and the LLVM headers, so bare regex literals currently don't work with this native Swift compiler.

7 Likes

A multi-architecture cross-compilation SDK for Swift 5.9 to Android is now up. This release only supports the last LTS NDK 25c, because the latest LTS NDK 26 added nullability annotations everywhere, which broke some code in the Swift stdlib and corelibs. I'm looking at fixes that can hopefully be backward-compatible with the previous Bionic headers, which I'll upstream when ready. I also plan to have an experimental SDK bundle supporting NDK 26 up later this month.

Native builds of the Swift 5.9 toolchain that run on Android devices, similar to Swift Playgrounds on iPadOS, are now available in the Termux app for Android. You can use it to build Swift code on most Android devices and Chromebooks, through the ChromeOS support for Android apps.

I'm happy to report that bare regex literals work again with this native Swift toolchain and so do the new macros, because of upstream pulls by @Douglas_Gregor, @bnbarham, and @rintaro that I backported to 5.9 and used on Android. Thanks to those authors for their work.

10 Likes

Great!

How fun. More nullability annotations is a good thing overall, despite the churn it will cause.

... and @compnerd !

Doug

4 Likes

A multi-architecture cross-compilation SDK for Swift 5.10 to Android is now up. This release supports the latest LTS NDK 26c, while my daily Android CI still produces 5.10 SDK builds supporting the previous LTS NDK 25c. I never got the experimental SDK bundle packaged for 5.9, hope to have one up for 5.10 eventually.

Native builds of the Swift 5.10 toolchain that run on Android or most ChromeOS devices are now available in the Termux app for Android. While I was able to remove many of the upstream patches that I had to apply to 5.9, I backported @Erik_Eckstein's massive "pure bridging" patch for C++ interop to 5.10 to get the mixed Swift and C++ in the Swift compiler itself to keep building for Android. Hopefully, @Alex_L's work to split out and properly modularize Bionic for Swift will get C++ interop working fully on Android.

Some other news since the last release: now that Swift works fairly well on Android, I have submitted it as an officially supported platform to the Core Team, and an outline for a prospective Android blog post to the SWWG. After discussing it with some members of the Core Team, I'm looking into adding Android to the official CI, and expanding testing beyond running the compiler validation suite, which is done on the current Android community CI.

I have been open-sourcing and upstreaming all my patches for Swift on Android, as I intend to develop an Android app written in Swift. If your company is using Swift on Android, email me if you would like to sponsor my ongoing work on the Android port, which would allow me to spend more time on expanding the official CI, writing up docs, and other remaining work.

11 Likes

An Android SDK bundle for Swift 6 has been up for the last month. The new bundle simplifies cross-compiling Swift packages to Android and now supports cross-compiling from a macOS host too, which has been tested on my daily Android CI for the last couple months, thanks to @Marc_Prud_hommeaux who added that macOS support (check out his Skip toolchain, which is starting to provide Android cross-compilation from macOS in beta).

Native builds of the Swift 6 toolchain that run directly on Android and ChromeOS devices are now available in the Termux app.

Both the new Swift 6 SDK bundle and toolchain use Alex's work on the new Android overlay and the Foundation rewrite for the first time. There is currently a Swift 6 regression where some Foundation and stdlib code cannot be used on Android APIs 24-28: I will update the SDK bundle and native toolchain once I find a fix for that.

After that, the next step is getting Android into the official Swift CI. Thanks to everyone who contributed to getting Swift on Android this far.

8 Likes

Thanks to @Finagolfin for his tireless and heroic efforts over the years to keep the Android flame burning! This SDK bundle is going to be an integral part of Skip's native toolchain integration for creating dual-platform iOS/Android apps from a single codebase.

On this topic, I've donated a server for running Android builds for the Swift Community CI, which I've submitted and am just awaiting finalization. Once it gets hooked into the Jenkins build system, we can start getting immediate feedback when breakage occurs, rather than requiring @Finagolfin to scramble to figure out what broke in the daily trunk builds (which is a weekly occurrence).

2 Likes

I've used your Swift 5 toolchain to build shared library files suitable for use with Android NDK, to finally produce an APK that runs as a GUI app. Now trying out this Swift 6 one.

For Swift 5, the command was swift build --destination ~/.../swiftpm-android-armv7.json and so on. This used dynamic linking and required copying a bunch of shared libraries like libandroid-spawn.so, libBlocksRuntime.so etc for each architecture into the APK.

For Swift 6, the command swift build --swift-sdk armv7-unknown-linux-androideabi24 (and similar for the other 2 architectures), produced shared libraries. These .so files are < 100 KB in size, similar to the Swift 5 output, so I assume they are also using dynamic linking.

Is is possible to do static linking? I tried swift build --static-swift-stdlib ... and got this:

Building for debugging...
error: link command failed with exit code 1 (use -v to see invocation)
ld.lld: error: unable to find library -l_FoundationCShims
ld.lld: error: unable to find library -l_FoundationCollections
ld.lld: error: unable to find library -l_FoundationCShims
ld.lld: error: unable to find library -l_FoundationCollections
ld.lld: error: unable to find library -lDispatchStubs
ld.lld: error: unable to find library -lCoreFoundation
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I didn't really support it with Swift 5, but am starting to now with Swift 6. @Geordie_J reported a similar issue a couple days ago, going to look into it and may ask for more info, so follow that issue or post more there.

1 Like