Skip to content

Commit

Permalink
Update doc, config, and download script to 5.7
Browse files Browse the repository at this point in the history
  • Loading branch information
finagolfin committed Sep 20, 2022
1 parent 043df19 commit 8902d57
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 67 deletions.
7 changes: 3 additions & 4 deletions .github/workflows/sdks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ jobs:
uses: actions/cache@v2
with:
path: ~/swift-${{ matrix.version }}-android-${{ matrix.arch }}-*-sdk.tar.xz
key: ${{ matrix.version }}-${{ steps.version.outputs.latest }}-${{ matrix.arch }}-syntax-sdk
key: ${{ matrix.version }}-${{ steps.version.outputs.latest }}-${{ matrix.arch }}-release-sdk
- name: Clone
uses: actions/checkout@v2
with:
Expand All @@ -101,8 +101,7 @@ jobs:
run: |
cd sdk-config
sudo apt install ninja-build
export BUILD_SWIFT_PM=1
swift get-packages-and-swift-source.swift
BUILD_SWIFT_PM=1 swift get-packages-and-swift-source.swift
SDK_NAME=$(ls | grep swift-${{ matrix.version }}-android-${{ matrix.arch }})
SDK=`pwd`/$SDK_NAME
Expand All @@ -117,7 +116,7 @@ jobs:
cd ..
fi
./swift/utils/build-script -RA --skip-build-cmark --build-llvm=0 --android --android-ndk $ANDROID_NDK --android-arch ${{ matrix.arch }} --android-api-level $ANDROID_API_LEVEL --build-swift-tools=0 --native-swift-tools-path=`pwd`/$SWIFT_TAG-ubuntu20.04/usr/bin --native-clang-tools-path=`pwd`/$SWIFT_TAG-ubuntu20.04/usr/bin --cross-compile-hosts=android-${{ matrix.arch }} --cross-compile-deps-path=$SDK --skip-local-build --xctest --skip-early-swift-driver --install-swift --install-libdispatch --install-foundation --install-xctest --install-destdir=$SDK --swift-install-components='clang-resource-dir-symlink;license;stdlib;sdk-overlay' --cross-compile-append-host-target-to-destdir=False -b -p --install-llbuild --sourcekit-lsp
./swift/utils/build-script -RA --skip-build-cmark --build-llvm=0 --android --android-ndk $ANDROID_NDK --android-arch ${{ matrix.arch }} --android-api-level $ANDROID_API_LEVEL --build-swift-tools=0 --native-swift-tools-path=`pwd`/$SWIFT_TAG-ubuntu20.04/usr/bin --native-clang-tools-path=`pwd`/$SWIFT_TAG-ubuntu20.04/usr/bin --cross-compile-hosts=android-${{ matrix.arch }} --cross-compile-deps-path=$SDK --skip-local-build --build-swift-static-stdlib --xctest --skip-early-swift-driver --install-swift --install-libdispatch --install-foundation --install-xctest --install-destdir=$SDK --swift-install-components='clang-resource-dir-symlink;license;stdlib;sdk-overlay' --cross-compile-append-host-target-to-destdir=False -b -p --install-llbuild --sourcekit-lsp
patchelf --set-rpath \$ORIGIN $SDK/usr/lib/swift/android/libdispatch.so
patchelf --set-rpath \$ORIGIN/../..:\$ORIGIN $SDK/usr/lib/swift/android/lib[FXs]*.so
Expand Down
97 changes: 43 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
# Swift cross-compilation SDKs for Android

All patches used to build these SDKs are open source and listed below. I
maintain [a daily CI](https://github.com/buttaface/swift-android-sdk/actions?query=event%3Aschedule)
on [github Actions that cross-compiles the SDK from the three main source branches
of the Swift toolchain for AArch64, armv7, and x86_64, builds several Swift packages
against those SDKs, and then runs their tests in the Android x86_64
maintain [a daily CI on github Actions](https://github.com/buttaface/swift-android-sdk/actions?query=event%3Aschedule)
that [cross-compiles the SDK from the three main source branches of the Swift
toolchain for AArch64, armv7, and x86_64, builds several Swift packages against
those SDKs, and then runs their tests in the Android x86_64
emulator](https://github.com/buttaface/swift-android-sdk/blob/main/.github/workflows/sdks.yml).

To build with a Swift 5.6.3 SDK, first download [the latest Android LTS NDK
25b](https://developer.android.com/ndk/downloads) and [Swift 5.6.3
To build with a Swift 5.7 SDK, first download [the latest Android LTS NDK
25b](https://developer.android.com/ndk/downloads) and [Swift 5.7
compiler](https://swift.org/download/#releases) (make sure to install the Swift
compiler's dependencies listed there). Unpack these archives and the SDK.

I will write up a Swift script to do this SDK configuration, but you will need
to do it manually for now. [You can see how I do it on the CI for a concrete
example](https://github.com/buttaface/swift-android-sdk/blob/5.6/.github/workflows/sdks.yml#L145).
I will write up a Swift script to do this SDK configuration one day, but you
will need to do it manually for now (I'll show aarch64 below, the same will
need to be done separately for the armv7 or x86_64 SDKs).

The SDK will need to be modified with the path to some clang headers bundled
with the Swift compiler (I'll show aarch64 below, the same will need to be done
for the armv7 or x86_64 SDKs).

Change the symbolic link at `swift-5.6.3-android-aarch64-24-sdk/usr/lib/swift/clang`
Change the symbolic link at `swift-5.7-android-aarch64-24-sdk/usr/lib/swift/clang`
to point to the clang headers that come with your swift compiler, eg

```
ln -sf /home/yourname/swift-5.6.3-RELEASE-ubuntu20.04/usr/lib/clang/13.0.0
swift-5.6.3-android-aarch64-24-sdk/usr/lib/swift/clang
ln -sf /home/yourname/swift-5.7-RELEASE-ubuntu20.04/usr/lib/clang/13.0.0
swift-5.7-android-aarch64-24-sdk/usr/lib/swift/clang
```

Next, modify the cross-compilation JSON file `android-aarch64.json` in this repo
Expand All @@ -34,11 +30,11 @@ similarly:
1. All paths to the NDK should change from `/home/butta/android-ndk-r25b`
to the path to your NDK, `/home/yourname/android-ndk-r25b`.

2. The path to the compiler should change from `/home/butta/swift-5.6.3-RELEASE-ubuntu20.04`
to the path to your Swift compiler, `/home/yourname/swift-5.6.3-RELEASE-centos8`.
2. The path to the compiler should change from `/home/butta/swift-5.7-RELEASE-ubuntu20.04`
to the path to your Swift compiler, `/home/yourname/swift-5.7-RELEASE-centos8`.

3. The path to the Android SDK should change from `/home/butta/swift-5.6.3-android-aarch64-24-sdk`
to the path where you unpacked the Android SDK, `/home/yourname/swift-5.6.3-android-aarch64-24-sdk`.
3. The path to the Android SDK should change from `/home/butta/swift-5.7-android-aarch64-24-sdk`
to the path where you unpacked the Android SDK, `/home/yourname/swift-5.7-android-aarch64-24-sdk`.

Now you're ready to cross-compile a Swift package with the cross-compilation
configuration JSON file, `android-aarch64.json`, and run its tests on Android.
Expand All @@ -48,9 +44,9 @@ git clone --depth 1 https://github.com/apple/swift-argument-parser.git
cd swift-argument-parser/
/home/yourname/swift-5.6.3-RELEASE-ubuntu20.04/usr/bin/swift build --build-tests
/home/yourname/swift-5.7-RELEASE-ubuntu20.04/usr/bin/swift build --build-tests
--enable-test-discovery --destination ~/swift-android-sdk/android-aarch64.json
-Xlinker -rpath -Xlinker \$ORIGIN/swift-5.6.3-android-aarch64-24-sdk/usr/lib/swift/android
-Xlinker -rpath -Xlinker \$ORIGIN/swift-5.7-android-aarch64-24-sdk/usr/lib/swift/android
```
This will cross-compile the package for Android aarch64 and produce a test
runner executable with the `.xctest` extension, in this case at
Expand All @@ -59,22 +55,22 @@ It adds a rpath for where it expects the SDK libraries to be relative to the
test runner when run on Android.

Sometimes the test runner will depend on additional files or executables: this
one depends on the example executables `math`, `repeat`, and `roll` in the
same build directory. Other packages use `#file` to point at test data in the
repo: I've had success moving this data with the test runner, after modifying
the test source so it has the path to this test data in the Android test
environment. See the example of [swift-crypto on the
CI](https://github.com/buttaface/swift-android-sdk/blob/5.6/.github/workflows/sdks.yml#L291).
one depends on the example executables `generate-manual`, `math`, `repeat`, and
`roll` in the same build directory. Other packages use `#file` to point at test
data in the repo: I've had success moving this data with the test runner, after
modifying the test source so it has the path to this test data in the Android
test environment. See the example of [swift-crypto on the
CI](https://github.com/buttaface/swift-android-sdk/blob/5.7/.github/workflows/sdks.yml#L282).

You can copy these executables and the SDK to [an emulator or a USB
debugging-enabled device with adb](https://github.com/apple/swift/blob/release/5.6/docs/Android.md#3-deploying-the-build-products-to-the-device),
or put them on an Android device with [a terminal emulator app like Termux](https://termux.com).
debugging-enabled device with adb](https://github.com/apple/swift/blob/release/5.7/docs/Android.md#3-deploying-the-build-products-to-the-device),
or put them on an Android device with [a terminal emulator app like Termux](https://termux.dev/en/).
I test aarch64 with Termux so I'll show how to run the test runner there, but
the process is similar with adb, [as can be seen on the CI](https://github.com/buttaface/swift-android-sdk/blob/5.6/.github/workflows/sdks.yml#L325).
the process is similar with adb, [as can be seen on the CI](https://github.com/buttaface/swift-android-sdk/blob/5.7/.github/workflows/sdks.yml#L316).

Copy the test executables to the same directory as the SDK:
```
cp .build/aarch64-unknown-linux-android24/debug/{swift-argument-parserPackageTests.xctest,math,repeat,roll} ..
cp .build/aarch64-unknown-linux-android24/debug/{swift-argument-parserPackageTests.xctest,generate-manual,math,repeat,roll} ..
```
You can copy the SDK and test executables to Termux using scp from OpenSSH, run
these commands in Termux on the Android device:
Expand All @@ -83,14 +79,14 @@ uname -m # check if you're running on the right architecture, should say `aarch6
cd # move to the Termux app's home directory
pkg install openssh
scp [email protected]:{swift-5.6.3-android-aarch64-24-sdk.tar.xz,
swift-argument-parserPackageTests.xctest,math,repeat,roll} .
scp [email protected]:{swift-5.7-android-aarch64-24-sdk.tar.xz,
swift-argument-parserPackageTests.xctest,generate-manual,math,repeat,roll} .
tar xf swift-5.6.3-android-aarch64-24-sdk.tar.xz
tar xf swift-5.7-android-aarch64-24-sdk.tar.xz
./swift-argument-parserPackageTests.xctest
```
I tried a handful of Swift packages, including some mostly written in C or C++,
I've tried several Swift packages, including some mostly written in C or C++,
and all the cross-compiled tests passed.

You can even run armv7 tests on an aarch64 device, though Termux may require
Expand All @@ -101,37 +97,30 @@ mode.

# Building the Android SDKs

Download the Swift 5.6.3 compiler and Android NDK 25b as above. Check out this
Download the Swift 5.7 compiler and Android NDK 25b as above. Check out this
repo and run
`SWIFT_TAG=swift-5.6.3-RELEASE ANDROID_ARCH=aarch64 swift get-packages-and-swift-source.swift`
`SWIFT_TAG=swift-5.7-RELEASE ANDROID_ARCH=aarch64 swift get-packages-and-swift-source.swift`
to get some prebuilt Android libraries and the Swift source to build the SDK. If
you pass in a different tag like `swift-DEVELOPMENT-SNAPSHOT-2022-08-30-a`
you pass in a different tag like `swift-DEVELOPMENT-SNAPSHOT-2022-09-12-a`
for the latest Swift trunk snapshot and pass in the path to the corresponding
official prebuilt Swift toolchain to `build-script` below, you can build a Swift
trunk SDK too, as seen on the CI.

Next, apply some patches to the Swift source, `swift-android.patch` from
Next, apply a patch to the Swift source, `swift-android.patch` from
this repo, which adds a dependency for the Foundation core library in this
Android SDK and extracts the clang resource directory from the NDK, and two
patches that have been merged into trunk upstream:
Android SDK and extracts the clang resource directory from the NDK:
```
git apply swift-android.patch
cd swift
wget -q https://patch-diff.githubusercontent.com/raw/apple/swift/pull/40976.diff
wget -q https://patch-diff.githubusercontent.com/raw/apple/swift/pull/41510.diff
patch -p1 < 40976.diff
patch -p1 < 41510.diff
cd ..
```

After making sure [needed build tools like python 3, CMake, and ninja](https://github.com/apple/swift/blob/release/5.6/docs/HowToGuides/GettingStarted.md#linux)
After making sure [needed build tools like python 3, CMake, and ninja](https://github.com/apple/swift/blob/release/5.7/docs/HowToGuides/GettingStarted.md#linux)
are installed, run the following `build-script` command with your local paths
substituted instead:
```
./swift/utils/build-script -RA --skip-build-cmark --build-llvm=0 --android
--android-ndk /home/butta/android-ndk-r25b/ --android-arch aarch64 --android-api-level 24
--build-swift-tools=0 --native-swift-tools-path=/home/butta/swift-5.6.3-RELEASE-ubuntu20.04/usr/bin/
--native-clang-tools-path=/home/butta/swift-5.6.3-RELEASE-ubuntu20.04/usr/bin/
--build-swift-tools=0 --native-swift-tools-path=/home/butta/swift-5.7-RELEASE-ubuntu20.04/usr/bin/
--native-clang-tools-path=/home/butta/swift-5.7-RELEASE-ubuntu20.04/usr/bin/
--host-cc=/usr/bin/clang-13 --host-cxx=/usr/bin/clang++-13
--cross-compile-hosts=android-aarch64 --cross-compile-deps-path=/home/butta/swift-release-android-aarch64-24-sdk
--skip-local-build --xctest --swift-install-components='clang-resource-dir-symlink;license;stdlib;sdk-overlay'
Expand Down Expand Up @@ -160,7 +149,7 @@ stdlib and corelibs require some libraries like libicu, that are pulled from the
prebuilt library packages used by the Termux app which are built against Android
API 24. Specifically, it downloads the libicu, libicu-static, libandroid-spawn,
libcurl, and libxml2 packages from the [Termux package
repository](https://packages.termux.org/apt/termux-main/pool/main/).
repository](https://packages.termux.dev/apt/termux-main/pool/main/).

Each one is unpacked with `ar x libicu_71.1-1_aarch64.deb; tar xf data.tar.xz` and
the resulting files moved to a newly-created Swift release SDK directory:
Expand All @@ -187,7 +176,7 @@ patchelf --set-soname libicuuc.so libicuuc.so
patchelf --replace-needed libicudata.so.71 libicudata.so libicuuc.so
```
The libcurl and libxml2 packages are [only needed for the FoundationNetworking
and FoundationXML libraries respectively](https://github.com/apple/swift-corelibs-foundation/blob/release/5.6/Docs/ReleaseNotes_Swift5.md),
and FoundationXML libraries respectively](https://github.com/apple/swift-corelibs-foundation/blob/release/5.7/Docs/ReleaseNotes_Swift5.md),
so you don't have to deploy them on the Android device if you don't use those
extra Foundation libraries.

Expand All @@ -204,7 +193,7 @@ instead, so this Swift SDK for Android could be built without using
any prebuilt Termux packages, if you're willing to put in the effort to
cross-compile them yourself, for example, against a different Android API.

Finally, it gets [the 5.6.3 source](https://github.com/apple/swift/releases/tag/swift-5.6.3-RELEASE)
Finally, it gets [the 5.7 source](https://github.com/apple/swift/releases/tag/swift-5.7-RELEASE)
tarballs for five Swift repos and renames them to `llvm-project/`, `swift/`,
`swift-corelibs-libdispatch`, `swift-corelibs-foundation`, and
`swift-corelibs-xctest`, as required by the Swift `build-script`, and creates
Expand Down
4 changes: 2 additions & 2 deletions android-aarch64.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"version": 1,
"target": "aarch64-unknown-linux-android24",
"toolchain-bin-dir": "/home/butta/swift-5.6.3-RELEASE-ubuntu20.04/usr/bin",
"toolchain-bin-dir": "/home/butta/swift-5.7-RELEASE-ubuntu20.04/usr/bin",
"sdk": "/home/butta/android-ndk-r25b/toolchains/llvm/prebuilt/linux-x86_64/sysroot",
"extra-cc-flags": [
"-fPIC"
],
"extra-swiftc-flags": [
"-resource-dir", "/home/butta/swift-5.6.3-android-aarch64-24-sdk/usr/lib/swift",
"-resource-dir", "/home/butta/swift-5.7-android-aarch64-24-sdk/usr/lib/swift",
"-tools-directory", "/home/butta/android-ndk-r25b/toolchains/llvm/prebuilt/linux-x86_64/bin",
],
"extra-cpp-flags": [
Expand Down
4 changes: 2 additions & 2 deletions android-armv7.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"version": 1,
"target": "armv7-unknown-linux-androideabi24",
"toolchain-bin-dir": "/home/butta/swift-5.6.3-RELEASE-ubuntu20.04/usr/bin",
"toolchain-bin-dir": "/home/butta/swift-5.7-RELEASE-ubuntu20.04/usr/bin",
"sdk": "/home/butta/android-ndk-r25b/toolchains/llvm/prebuilt/linux-x86_64/sysroot",
"extra-cc-flags": [
"-fPIC"
],
"extra-swiftc-flags": [
"-resource-dir", "/home/butta/swift-5.6.3-android-armv7-24-sdk/usr/lib/swift",
"-resource-dir", "/home/butta/swift-5.7-android-armv7-24-sdk/usr/lib/swift",
"-tools-directory", "/home/butta/android-ndk-r25b/toolchains/llvm/prebuilt/linux-x86_64/bin",
],
"extra-cpp-flags": [
Expand Down
4 changes: 2 additions & 2 deletions android-x86_64.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"version": 1,
"target": "x86_64-unknown-linux-android24",
"toolchain-bin-dir": "/home/butta/swift-5.6.3-RELEASE-ubuntu20.04/usr/bin",
"toolchain-bin-dir": "/home/butta/swift-5.7-RELEASE-ubuntu20.04/usr/bin",
"sdk": "/home/butta/android-ndk-r25b/toolchains/llvm/prebuilt/linux-x86_64/sysroot",
"extra-cc-flags": [
"-fPIC"
],
"extra-swiftc-flags": [
"-resource-dir", "/home/butta/swift-5.6.3-android-x86_64-24-sdk/usr/lib/swift",
"-resource-dir", "/home/butta/swift-5.7-android-x86_64-24-sdk/usr/lib/swift",
"-tools-directory", "/home/butta/android-ndk-r25b/toolchains/llvm/prebuilt/linux-x86_64/bin",
],
"extra-cpp-flags": [
Expand Down
13 changes: 10 additions & 3 deletions get-packages-and-swift-source.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Foundation
// The Termux packages to download and unpack
var termuxPackages = ["libicu", "libicu-static", "libandroid-spawn", "libcurl", "libxml2"]

let swiftRepos = ["llvm-project", "swift", "swift-corelibs-libdispatch",
var swiftRepos = ["llvm-project", "swift", "swift-corelibs-libdispatch",
"swift-corelibs-foundation", "swift-corelibs-xctest", "swift-syntax"]

let extraSwiftRepos = ["swift-llbuild", "swift-package-manager", "swift-driver",
Expand Down Expand Up @@ -33,15 +33,22 @@ let tagExtract = try NSRegularExpression(pattern: "swift-([0-9]+\\.[0-9])?\\.?[0

if tagExtract.numberOfMatches(in: SWIFT_TAG, range: tagRange) == 1 {
let match = tagExtract.firstMatch(in: SWIFT_TAG, range: tagRange)
swiftVersion = SWIFT_TAG.substring(with: match!.range(at: 1))
if match!.range(at: 1).location != NSNotFound {
swiftVersion = SWIFT_TAG.substring(with: match!.range(at: 1))
}

swiftBranch = SWIFT_TAG.substring(with: match!.range(at: 2))
swiftSnapshotDate = SWIFT_TAG.substring(with: match!.range(at: 3))

if match!.range(at: 3).location != NSNotFound {
swiftSnapshotDate = SWIFT_TAG.substring(with: match!.range(at: 3))
}
} else {
fatalError("Something went wrong with extracting data from the SWIFT_TAG environment variable: \(SWIFT_TAG)")
}

if swiftBranch == "RELEASE" {
sdkDir = "swift-release-android-\(ANDROID_ARCH)-24-sdk"
swiftRepos += ["swift-experimental-string-processing"]
} else {
sdkDir = "swift-\(swiftVersion == "" ? "trunk" : "devel")-android-\(ANDROID_ARCH)-\(swiftSnapshotDate)-24-sdk"
}
Expand Down

0 comments on commit 8902d57

Please sign in to comment.