diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 1ed0a799..ed578bc6 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -21,3 +21,141 @@ jobs: name: docker-logs path: | *.log + + static-linux-build: + name: Build Static Linux image + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Build Docker images + working-directory: swift-ci/sdks/static-linux + run: ./build + + android-build: + name: Build Android ${{ matrix.arch }} SDK + strategy: + fail-fast: false + matrix: + # blank arch builds all (aarch64,x86_64,armv7) + #arch: [''] + # builds only x86_64 to speed up the validation + #arch: ['x86_64'] + # build both the quick (x86_64) and complete (aarch64,x86_64,armv7) SDKs + arch: ['x86_64', ''] + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Install Dependencies + run: | + sudo apt install -q ninja-build patchelf + - name: Build Android SDK + working-directory: swift-ci/sdks/android + run: | + TARGET_ARCHS=${{ matrix.arch }} ./build + - name: Get artifact info + id: info + shell: bash + run: | + set -ex + SWIFT_ROOT=$(dirname ${{ runner.temp }}/swift-android-sdk/host-toolchain/*/usr) + echo "swift-root=${SWIFT_ROOT}" >> $GITHUB_OUTPUT + echo "swift-path=${SWIFT_ROOT}/usr/bin/swift" >> $GITHUB_OUTPUT + + ARTIFACT_BUILD=$(realpath ${{ runner.temp }}/swift-android-sdk/build/*.artifactbundle) + ARTIFACT_PATH=$(realpath ${{ runner.temp }}/swift-android-sdk/products/*.artifactbundle.tar.gz) + echo "artifact-path=${ARTIFACT_PATH}" >> $GITHUB_OUTPUT + echo "sdk-id=x86_64-unknown-linux-android28" >> $GITHUB_OUTPUT + + ARTIFACT_EXT=".artifactbundle.tar.gz" + ARTIFACT_NAME="$(basename ${ARTIFACT_PATH} ${ARTIFACT_EXT})" + # artifacts need a unique name so we suffix with the matrix arch(s) + if [[ ! -z "${{ matrix.arch }}" ]]; then + ARTIFACT_NAME="${ARTIFACT_NAME}-$(echo ${{ matrix.arch }} | tr ',' '-')" + fi + ARTIFACT_NAME="${ARTIFACT_NAME}${ARTIFACT_EXT}" + + # There is no way to prevent even a single-file artifact from being zipped: + # https://github.com/actions/upload-artifact?tab=readme-ov-file#zip-archives + # so the actual artifact download will look like: + # swift-6.1-RELEASE_android-0.1-x86_64.artifactbundle.tar.gz.zip + echo "artifact-name=${ARTIFACT_NAME}" >> $GITHUB_OUTPUT + + # validate some required paths in the artifactbundle + pushd ${ARTIFACT_BUILD}/*/*/usr + ls lib/swift/android + ls lib/swift/android/* + ls lib/swift/android/*/swiftrt.o + ls lib/*-linux-android/*/crtbegin_dynamic.o + + ls lib/swift_static-* + ls lib/swift_static-*/android + ls lib/swift_static-*/android/libFoundationEssentials.a + + ls lib/*-linux-android/libFoundationEssentials.so + ls lib/*-linux-android/libFoundationNetworking.so + ls lib/*-linux-android/libFoundationInternationalization.so + ls lib/*-linux-android/lib_FoundationICU.so + ls lib/*-linux-android/libFoundationXML.so + ls lib/*-linux-android/libTesting.so + + ls lib/swift/clang/lib + ls lib/swift/clang/lib/linux + ls lib/swift/clang/lib/linux/*/libunwind.a + popd + - name: Upload SDK artifactbundle + uses: actions/upload-artifact@v4 + with: + compression-level: 0 + name: ${{ steps.info.outputs.artifact-name }} + path: ${{ steps.info.outputs.artifact-path }} + - name: Cleanup + run: | + # need to free up some space or else when installing we get: No space left on device + rm -rf ${{ runner.temp }}/swift-android-sdk/{build,src} + - name: Install artifactbundle + shell: bash + run: | + set -ex + ${{ steps.info.outputs.swift-path }} sdk install ${{ steps.info.outputs.artifact-path }} + ${{ steps.info.outputs.swift-path }} sdk configure --show-configuration $(${{ steps.info.outputs.swift-path }} sdk list | head -n 1) ${{ steps.info.outputs.sdk-id }} + # recent releases require that ANDROID_NDK_ROOT *not* be set + # see https://github.com/finagolfin/swift-android-sdk/issues/207 + echo "ANDROID_NDK_ROOT=" >> $GITHUB_ENV + + - name: Create Demo Project + run: | + cd ${{ runner.temp }} + mkdir DemoProject + cd DemoProject + ${{ steps.info.outputs.swift-path }} --version + ${{ steps.info.outputs.swift-path }} package init + echo 'import Foundation' >> Sources/DemoProject/DemoProject.swift + echo 'import FoundationEssentials' >> Sources/DemoProject/DemoProject.swift + echo 'import FoundationXML' >> Sources/DemoProject/DemoProject.swift + echo 'import FoundationNetworking' >> Sources/DemoProject/DemoProject.swift + echo 'import Dispatch' >> Sources/DemoProject/DemoProject.swift + echo 'import Android' >> Sources/DemoProject/DemoProject.swift + - name: Test Demo Project on Android + uses: skiptools/swift-android-action@v2 + with: + # only test for the complete arch SDK build to speed up CI + run-tests: ${{ matrix.arch == '' }} + package-path: ${{ runner.temp }}/DemoProject + installed-sdk: ${{ steps.info.outputs.sdk-id }} + installed-swift: ${{ steps.info.outputs.swift-root }} + + - name: Checkout swift-algorithms + uses: actions/checkout@v4 + with: + repository: apple/swift-algorithms + path: swift-algorithms + - name: Test swift-algorithms + uses: skiptools/swift-android-action@v2 + with: + run-tests: ${{ matrix.arch == '' }} + package-path: swift-algorithms + installed-sdk: ${{ steps.info.outputs.sdk-id }} + installed-swift: ${{ steps.info.outputs.swift-root }} + diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..98bcc3db --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.*.swp +static-swift-linux-sources diff --git a/swift-ci/sdks/android/README.md b/swift-ci/sdks/android/README.md new file mode 100644 index 00000000..531aa88a --- /dev/null +++ b/swift-ci/sdks/android/README.md @@ -0,0 +1,43 @@ +# Build scripts for Swift Android SDK + +This folder contains scripts to build a Swift Android SDK +in the form of an artifactbundle. + +## Running + +The top-level `./build` script installs a host toolchain and the +Android NDK, and then invokes `scripts/fetch-source.sh` which will +fetch tagged sources for libxml2, curl, boringssl, and swift. + +It then applies some patches and invokes `scripts/build.sh`, +which will build the sources for each of the specified +architectures. Finally, it combines the NDK and the newly built +SDKs into a single artifactbundle. + +## Specifying Architectures + +By default all the supported Android architectures +(`aarch64`, `x86_64`, `aarmv7`) +will be built, but this can be reduced in order to speed +up the build. This can be useful, e.g., as part of a CI that +validates a pull request, as building a single architecture +takes around 30 minutes on a standard ubuntu-24.04 GitHub runner, +whereas building for all the architectures takes over an hour. + +To build an artifactbundle for just the `x86_64` architecture, run: + +``` +TARGET_ARCHS=x86_64 ./build +``` + +## Installing and validating the SDK + +The `.github/workflows/pull_request.yml` workflow +will create and upload an installable SDK named something like: +`swift-6.1-RELEASE_android-0.1.artifactbundle.tar.gz` + +The workflow will also install the SDK locally and use +[swift-android-action](https://github.com/marketplace/actions/swift-android-action) +to build and test various Swift packages in an Android emulator. + + diff --git a/swift-ci/sdks/android/build b/swift-ci/sdks/android/build new file mode 100755 index 00000000..e35bd431 --- /dev/null +++ b/swift-ci/sdks/android/build @@ -0,0 +1,91 @@ +#!/bin/bash -e +# Swift Android SDK: Top-level Build Script + +# default architectures to build for +TARGET_ARCHS=${TARGET_ARCHS:-aarch64,x86_64,armv7} + +ANDROID_NDK_VERSION=android-ndk-r27c +ANDROID_API=28 + +SDKROOT=${RUNNER_TEMP:-${TMPDIR:-'/tmp'}}/swift-android-sdk +mkdir -p ${SDKROOT} + +# Install a Swift host toolchain if it isn't already present +SWIFT_ROOT=${SDKROOT}/host-toolchain +HOST_OS=ubuntu$(lsb_release -sr) +SWIFT_VERSION=6.1 +SWIFT_TAG="swift-${SWIFT_VERSION}-RELEASE" +SWIFT_BRANCH="swift-$(echo $SWIFT_TAG | cut -d- -f2)-release" +SWIFT_BASE=$SWIFT_TAG-$HOST_OS + +if [[ ! -d $SWIFT_ROOT ]]; then + mkdir -p $SWIFT_ROOT + pushd $SWIFT_ROOT + + SWIFT_URL="https://download.swift.org/$SWIFT_BRANCH/$(echo $HOST_OS | tr -d '.')/$SWIFT_TAG/$SWIFT_BASE.tar.gz" + wget -q $SWIFT_URL + tar xzf $SWIFT_BASE.tar.gz + + popd +fi + +#HOST_TOOLCHAIN=${HOST_TOOLCHAIN:-$(dirname $(dirname $(which swiftc)))} +HOST_TOOLCHAIN=$SWIFT_ROOT/$SWIFT_BASE/usr +$HOST_TOOLCHAIN/bin/swift --version + +# ensure the correct Swift is first in the PATH +export PATH=$HOST_TOOLCHAIN/bin:$PATH + +export ANDROID_NDK_HOME=${SDKROOT}/ndk/${ANDROID_NDK_VERSION} +export ANDROID_NDK=${ANDROID_NDK_HOME} + +if [[ ! -d ${ANDROID_NDK_HOME} ]]; then + mkdir -p $(dirname ${ANDROID_NDK_HOME}) + pushd $(dirname ${ANDROID_NDK_HOME}) + NDKFILE=$(basename $ANDROID_NDK_HOME)-linux.zip + wget -q https://dl.google.com/android/repository/${NDKFILE} + unzip -q ${NDKFILE} + popd +fi + +mkdir -p ${SDKROOT}/products + +# Check-out the sources +if [[ ! -d ${SDKROOT}/src ]]; then + scripts/fetch-source.sh --source-dir ${SDKROOT}/src --swift-tag ${SWIFT_TAG} +fi + +# fetch and apply the patches +PATCHDIR=${SDKROOT}/patches +if [[ ! -d ${PATCHDIR} ]]; then + git clone https://github.com/finagolfin/swift-android-sdk.git ${PATCHDIR} + + # TODO: need to selectively apply patches based on release or not release + pushd ${SDKROOT}/src/swift-project + echo "Applying patches" + + # patch the patch, which seems to only be needed for an API less than 28 + # https://github.com/finagolfin/swift-android-sdk/blob/main/swift-android.patch#L110 + perl -pi -e 's/#if os\(Windows\)/#if os\(Android\)/g' $PATCHDIR/swift-android.patch + + # remove the need to link in android-execinfo + perl -pi -e 's/dispatch android-execinfo/dispatch/g' $PATCHDIR/swift-android.patch + + git apply -v $PATCHDIR/swift-android.patch + # swift-android-ci.patch is not needed, since it is only used for llbuild, etc. + #git apply -C1 $PATCHDIR/swift-android-ci.patch + #git apply -v $PATCHDIR/swift-android-ci-release.patch + git apply -v $PATCHDIR/swift-android-testing-release.patch + + perl -pi -e 's%String\(cString: getpass%\"fake\" //%' swiftpm/Sources/PackageRegistryCommand/PackageRegistryCommand+Auth.swift + # disable backtrace() for Android (needs either API33+ or libandroid-execinfo, or to manually add in backtrace backport) + perl -pi -e 's/os\(Android\)/os\(AndroidDISABLED\)/g' swift-testing/Sources/Testing/SourceAttribution/Backtrace.swift + + # need to un-apply libandroid-spawn since we don't need it for API28+ + perl -pi -e 's/MATCHES "Android"/MATCHES "AndroidDISABLED"/g' llbuild/lib/llvm/Support/CMakeLists.txt + perl -pi -e 's/ STREQUAL Android\)/ STREQUAL AndroidDISABLED\)/g' swift-corelibs-foundation/Sources/Foundation/CMakeLists.txt + popd +fi + +./scripts/build.sh --products-dir ${SDKROOT}/products --source-dir ${SDKROOT}/src --build-dir ${SDKROOT}/build --ndk-home ${ANDROID_NDK_HOME} --android-api ${ANDROID_API} --host-toolchain ${HOST_TOOLCHAIN} --archs ${TARGET_ARCHS} + diff --git a/swift-ci/sdks/android/scripts/build.sh b/swift-ci/sdks/android/scripts/build.sh new file mode 100755 index 00000000..843ff2db --- /dev/null +++ b/swift-ci/sdks/android/scripts/build.sh @@ -0,0 +1,536 @@ +#!/bin/bash +# Swift SDK for Android: Build Script +set -e + +# Docker sets TERM to xterm if using a pty; we probably want +# xterm-256color, otherwise we only get eight colors +if [ -t 1 ]; then + if [[ "$TERM" == "xterm" ]]; then + export TERM=xterm-256color + fi +fi + +if [[ -n "$TERM" ]]; then + bold="" + white="" + grey="" + reset="" +else + bold=$(tput bold) + white=$(tput setaf 15) + grey=$(tput setaf 8) + reset=$(tput sgr0) +fi + +function cleanup { + echo "${reset}" +} +trap cleanup EXIT + +function header { + local text="$1" + echo "" + echo "${white}${bold}*** ${text} ***${reset}${grey}" + echo "" +} + +function groupstart { + local text="$1" + if [[ ! -z "$CI" ]]; then + echo "::group::${text}" + fi + header $text +} + +function groupend { + if [[ ! -z "$CI" ]]; then + echo "::endgroup::" + fi +} + +function usage { + cat < --products-dir --ndk-home --host-toolchain + [--name ] [--version ] [--build-dir ] + [--archs [, ...]] + +Build the Swift Android SDK. + +Options: + + --name Specify the name of the SDK bundle. + --version Specify the version of the Android SDK. + --source-dir Specify the path in which the sources can be found. + --ndk-home Specify the path to the Android NDK + --host-toolchain Specify the path to the host Swift toolchain + --products-dir Specify the path in which the products should be written. + --build-dir Specify the path in which intermediates should be stored. + --android-api Specify the Android API level + (Default is ${android_api}). + --archs [, ...] + Specify the architectures for which we should build + the SDK. + (Default is ${archs}). + --build Specify the CMake build type to use (Release, Debug, + RelWithDebInfo). + (Default is ${build_type}). + -j + --jobs Specify the number of parallel jobs to run at a time. + (Default is ${parallel_jobs}.) +EOF +} + +# Declare all the packages we depend on +declare -a packages + +function declare_package +{ + local name=$1 + local userVisibleName=$2 + local license=$3 + local url=$4 + + local snake=$(echo ${name} | tr '_' '-') + + declare -g ${name}_snake="$snake" + declare -g ${name}_name="$userVisibleName" + declare -g ${name}_license="$license" + declare -g ${name}_url="$url" + + packages+=(${name}) +} + +declare_package android_sdk \ + "Swift SDK for Android" \ + "Apache-2.0" "https://swift.org/install" +declare_package swift "swift" "Apache-2.0" "https://swift.org" +declare_package libxml2 "libxml2" "MIT" \ + "https://github.com/GNOME/libxml2" +declare_package curl "curl" "MIT" "https://curl.se" +declare_package boringssl "boringssl" "OpenSSL AND ISC AND MIT" \ + "https://boringssl.googlesource.com/boringssl/" +declare_package zlib "zlib" "Zlib" "https://zlib.net" + +# Parse command line arguments +android_sdk_version=0.1 +sdk_name= +archs=aarch64,armv7,x86_64 +android_api=28 +build_type=Release +parallel_jobs=$(($(nproc --all) + 2)) +source_dir= +ndk_home=${ANDROID_NDK} +build_dir=$(pwd)/build +products_dir= + +while [ "$#" -gt 0 ]; do + case "$1" in + --source-dir) + source_dir="$2"; shift ;; + --ndk-home) + ndk_home="$2"; shift ;; + --host-toolchain) + host_toolchain="$2"; shift ;; + --build-dir) + build_dir="$2"; shift ;; + --android-api) + android_api="$2"; shift ;; + --products-dir) + products_dir="$2"; shift ;; + --name) + sdk_name="$2"; shift ;; + --archs) + archs="$2"; shift ;; + --version) + android_sdk_version="$2"; shift ;; + -j|--jobs) + parallel_jobs=$2; shift ;; + *) + echo "Unknown argument '$1'"; usage; exit 0 ;; + esac + shift +done + +# Change the commas for spaces +archs="${archs//,/ }" + +if [[ -z "$source_dir" || -z "$products_dir" || -z "$ndk_home" || -z "$host_toolchain" ]]; then + usage + exit 1 +fi + +if ! swiftc=$(which swiftc); then + echo "build.sh: Unable to find Swift compiler. You must have a Swift toolchain installed to build the Android SDK." + exit 1 +fi + +script_dir=$(dirname -- "${BASH_SOURCE[0]}") +resource_dir="${script_dir}/../resources" + +# Find the version numbers of the various dependencies +function describe { + pushd $1 >/dev/null 2>&1 + git describe --tags + popd >/dev/null 2>&1 +} +function versionFromTag { + desc=$(describe $1) + if [[ $desc == v* ]]; then + echo "${desc#v}" + else + echo "${desc}" + fi +} + +swift_version=$(describe ${source_dir}/swift-project/swift) +if [[ $swift_version == swift-* ]]; then + swift_version=${swift_version#swift-} +fi + +if [[ -z "$sdk_name" ]]; then + sdk_name=swift-${swift_version}_android-${android_sdk_version} +fi + +libxml2_version=$(versionFromTag ${source_dir}/libxml2) + +curl_desc=$(describe ${source_dir}/curl | tr '_' '.') +curl_version=${curl_desc#curl-} + +boringssl_version=$(describe ${source_dir}/boringssl) + +zlib_version=$(versionFromTag ${source_dir}/zlib) + +function quiet_pushd { + pushd "$1" >/dev/null 2>&1 +} +function quiet_popd { + popd >/dev/null 2>&1 +} + +header "Swift Android SDK build script" + +swift_dir=$(realpath $(dirname "$swiftc")/..) +HOST=linux-x86_64 +#HOST=$(uname -s -m | tr '[:upper:]' '[:lower:]' | tr ' ' '-') +ndk_toolchain=$ndk_home/toolchains/llvm/prebuilt/$HOST + + +echo "Swift found at ${swift_dir}" +echo "Host toolchain found at ${host_toolchain}" +${host_toolchain}/bin/swift --version +echo "Android NDK found at ${ndk_home}" +${ndk_toolchain}/bin/clang --version +echo "Building for ${archs}" +echo "Sources are in ${source_dir}" +echo "Build will happen in ${build_dir}" +echo "Products will be placed in ${products_dir}" +echo +echo "Building from:" +echo " - Swift ${swift_version}" +echo " - libxml2 ${libxml2_version}" +echo " - curl ${curl_version}" +echo " - BoringSSL ${boringssl_version}" +echo " - zlib ${zlib_version}" + +function run() { + echo "$@" + "$@" +} + +for arch in $archs; do + # enable short-circuiting the individual builds + if [[ ! -z "$SWIFT_ANDROID_ARCHIVEONLY" ]]; then + continue + fi + + case $arch in + armv7) target_host="arm-linux-androideabi"; compiler_target_host="armv7a-linux-androideabi$android_api"; android_abi="armeabi-v7a" ;; + aarch64) target_host="aarch64-linux-android"; compiler_target_host="$target_host$android_api"; android_abi="arm64-v8a" ;; + x86_64) target_host="x86_64-linux-android"; compiler_target_host="$target_host$android_api"; android_abi="x86_64" ;; + x86) target_host="x86-linux-android"; compiler_target_host="$target_host$android_api"; android_abi="x86" ;; + *) echo "Unknown architecture '$1'"; usage; exit 0 ;; + esac + + sdk_root=${build_dir}/sdk_root/${arch} + mkdir -p "$sdk_root" + + groupstart "Building libxml2 for $arch" + quiet_pushd ${source_dir}/libxml2 + run cmake \ + -G Ninja \ + -S ${source_dir}/libxml2 \ + -B ${build_dir}/$arch/libxml2 \ + -DANDROID_ABI=$android_abi \ + -DANDROID_PLATFORM=android-$android_api \ + -DCMAKE_TOOLCHAIN_FILE=$ndk_home/build/cmake/android.toolchain.cmake \ + -DCMAKE_BUILD_TYPE=$build_type \ + -DCMAKE_EXTRA_LINK_FLAGS="-rtlib=compiler-rt -unwindlib=libunwind -stdlib=libc++ -fuse-ld=lld -lc++ -lc++abi" \ + -DCMAKE_BUILD_TYPE=$build_type \ + -DCMAKE_INSTALL_PREFIX=$sdk_root/usr \ + -DLIBXML2_WITH_PYTHON=NO \ + -DLIBXML2_WITH_ICU=NO \ + -DLIBXML2_WITH_ICONV=NO \ + -DLIBXML2_WITH_LZMA=NO \ + -DBUILD_SHARED_LIBS=OFF \ + -DBUILD_STATIC_LIBS=ON + + quiet_pushd ${build_dir}/$arch/libxml2 + run ninja -j$parallel_jobs + quiet_popd + + header "Installing libxml2 for $arch" + quiet_pushd ${build_dir}/$arch/libxml2 + run ninja -j$parallel_jobs install + quiet_popd + quiet_popd + groupend + + groupstart "Building boringssl for ${compiler_target_host}" + quiet_pushd ${source_dir}/boringssl + run cmake \ + -GNinja \ + -B ${build_dir}/$arch/boringssl \ + -DANDROID_ABI=$android_abi \ + -DANDROID_PLATFORM=android-$android_api \ + -DCMAKE_TOOLCHAIN_FILE=$ndk_home/build/cmake/android.toolchain.cmake \ + -DCMAKE_BUILD_TYPE=$build_type \ + -DCMAKE_INSTALL_PREFIX=$sdk_root/usr \ + -DBUILD_SHARED_LIBS=OFF \ + -DBUILD_STATIC_LIBS=ON \ + -DBUILD_TESTING=OFF + + quiet_pushd ${build_dir}/$arch/boringssl + run ninja -j$parallel_jobs + quiet_popd + + header "Installing BoringSSL for $arch" + quiet_pushd ${build_dir}/$arch/boringssl + run ninja -j$parallel_jobs install + quiet_popd + quiet_popd + groupend + + groupstart "Building libcurl for ${compiler_target_host}" + quiet_pushd ${source_dir}/curl + run cmake \ + -G Ninja \ + -S ${source_dir}/curl \ + -B ${build_dir}/$arch/curl \ + -DANDROID_ABI=$android_abi \ + -DANDROID_PLATFORM=android-$android_api \ + -DCMAKE_TOOLCHAIN_FILE=$ndk_home/build/cmake/android.toolchain.cmake \ + -DCMAKE_BUILD_TYPE=$build_type \ + -DCMAKE_INSTALL_PREFIX=$sdk_root/usr \ + -DOPENSSL_ROOT_DIR=$sdk_root/usr \ + -DOPENSSL_INCLUDE_DIR=$sdk_root/usr/include \ + -DOPENSSL_SSL_LIBRARY=$sdk_root/usr/lib/libssl.a \ + -DOPENSSL_CRYPTO_LIBRARY=$sdk_root/usr/lib/libcrypto.a \ + -DCURL_USE_OPENSSL=ON \ + -DCURLSSLOPT_NATIVE_CA=ON \ + -DTHREADS_PREFER_PTHREAD_FLAG=OFF \ + -DCMAKE_THREAD_PREFER_PTHREAD=OFF \ + -DCMAKE_THREADS_PREFER_PTHREAD_FLAG=OFF \ + -DCMAKE_HAVE_LIBC_PTHREAD=YES \ + -DBUILD_CURL_EXE=NO \ + -DBUILD_SHARED_LIBS=OFF \ + -DBUILD_STATIC_LIBS=ON \ + -DCURL_BUILD_TESTS=OFF + + quiet_pushd ${build_dir}/$arch/curl + run ninja -j$parallel_jobs + quiet_popd + + header "Installing libcurl for $arch" + quiet_pushd ${build_dir}/$arch/curl + run ninja -j$parallel_jobs install + quiet_popd + quiet_popd + groupend + + groupstart "Building Android SDK for ${compiler_target_host}" + quiet_pushd ${source_dir}/swift-project + build_type_flag="--debug" + case $build_type in + Debug) build_type_flag="--debug" ;; + Release) build_type_flag="--release" ;; + RelWithDebInfo) build_type_flag="--release-debuginfo" ;; + esac + + # use an out-of-tree build folder, otherwise subsequent arch builds have conflicts + export SWIFT_BUILD_ROOT=${build_dir}/$arch/swift-project + + ./swift/utils/build-script \ + $build_type_flag \ + --reconfigure \ + --no-assertions \ + --android \ + --android-ndk=$ndk_home \ + --android-arch=$arch \ + --android-api-level=$android_api \ + --native-swift-tools-path=$host_toolchain/bin \ + --native-clang-tools-path=$host_toolchain/bin \ + --cross-compile-hosts=android-$arch \ + --cross-compile-deps-path=$sdk_root \ + --install-destdir=$sdk_root \ + --build-llvm=0 \ + --build-swift-tools=0 \ + --skip-build-cmark \ + --skip-local-build \ + --build-swift-static-stdlib \ + --install-swift \ + --install-libdispatch \ + --install-foundation \ + --xctest --install-xctest \ + --swift-testing --install-swift-testing \ + --cross-compile-append-host-target-to-destdir=False + + # need to remove symlink that gets created in the NDK to the previous arch's build + # or else we get errors like: + # error: could not find module '_Builtin_float' for target 'x86_64-unknown-linux-android'; found: aarch64-unknown-linux-android, at: /home/runner/work/_temp/swift-android-sdk/ndk/android-ndk-r27c/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/swift/android/_Builtin_float.swiftmodule + rm -f $ndk_toolchain/sysroot/usr/lib/swift + quiet_popd + groupend +done + +# Now generate the bundle +groupstart "Bundling SDK" + +sdk_base=swift-android +sdk_staging="sdk_staging" + +bundle="${sdk_name}.artifactbundle" + +rm -rf ${build_dir}/$bundle +mkdir -p ${build_dir}/$bundle +quiet_pushd ${build_dir}/$bundle + +# First the info.json, for SwiftPM +cat > info.json < $sysroot_path/SDKSettings.json < swift-sdk.json <> swift-sdk.json <> swift-sdk.json <> swift-sdk.json < swift-toolset.json <|--swift-tag + |--swift-version ] + [--curl-version ] + [--boringssl-version ] + [--clone-with-ssh] + [--source-dir ] + +Fetch all the sources required to build the fully statically linked Linux +SDK for Swift. Options are: + + --clone-with-ssh Use git-over-SSH rather than HTTPS where possible. + --source-dir Specify the path in which the sources should be checked + out. This directory will be created it if does not exist. + --swift-scheme + --swift-tag + --swift-version + Select the version of Swift to check out sources for. + If starts with "scheme:" or "tag:", it will + select a scheme or tag; otherwise it will be treated as + a version number. + --libxml2-version + --curl-version + --boringssl-version +EOF +} + +# Defaults +if [[ -z "${SWIFT_VERSION}" ]]; then + SWIFT_VERSION=scheme:release/6.1 +fi +if [[ -z "${LIBXML2_VERSION}" ]]; then + LIBXML2_VERSION=2.12.7 + #LIBXML2_VERSION=2.14.2 +fi +if [[ -z "${CURL_VERSION}" ]]; then + CURL_VERSION=8.7.1 + #CURL_VERSION=8.13.0 +fi +if [[ -z "${BORINGSSL_VERSION}" ]]; then + BORINGSSL_VERSION=fips-20220613 +fi + +clone_with_ssh=false +while [ "$#" -gt 0 ]; do + case "$1" in + --swift-scheme) + SWIFT_VERSION="scheme:$2"; shift ;; + --swift-tag) + SWIFT_VERSION="tag:$2"; shift ;; + --swift-version) + SWIFT_VERSION="$2"; shift ;; + --libxml2-version) + LIBXML2_VERSION="$2"; shift ;; + --curl-version) + CURL_VERSION="$2"; shift ;; + --boringssl-version) + BORINGSSL_VERSION="$2"; shift ;; + --clone-with-ssh) + clone_with_ssh=true ;; + --source-dir) + source_dir="$2"; shift ;; + *) + usage; exit 0 ;; + esac + shift +done + +if [[ ! -z "$source_dir" ]]; then + mkdir -p "$source_dir" +else + source_dir=. +fi + +if [[ "$clone_with_ssh" == "true" ]]; then + github=git@github.com: + clone_arg=--clone-with-ssh +else + github=https://github.com/ + clone_arg=--clone +fi + +cd "$source_dir" + +# Fetch Swift +mkdir -p swift-project + +groupstart "Fetching Swift" +pushd swift-project >/dev/null + +[[ -d swift ]] || git clone ${github}apple/swift.git +cd swift + +# Get its dependencies +header "Fetching Swift Dependencies" + +extra_args="--skip-history --all-repositories" +if [[ $SWIFT_VERSION == scheme:* ]]; then + utils/update-checkout ${clone_arg} --scheme ${SWIFT_VERSION#scheme:} ${extra_args} +elif [[ $SWIFT_VERSION == tag:* ]]; then + utils/update-checkout ${clone_arg} --tag ${SWIFT_VERSION#tag:} ${extra_args} +else + utils/update-checkout ${clone_arg} --tag swift-${SWIFT_VERSION}-RELEASE ${extra_args} +fi + +popd >/dev/null +groupend + +# Fetch libxml2 +groupstart "Fetching libxml2" +[[ -d libxml2 ]] || git clone ${github}GNOME/libxml2.git +pushd libxml2 >/dev/null 2>&1 +git checkout v${LIBXML2_VERSION} +popd >/dev/null 2>&1 +groupend + +# Fetch curl +groupstart "Fetching curl" +[[ -d curl ]] || git clone ${github}curl/curl.git +pushd curl >/dev/null 2>&1 +git checkout curl-$(echo ${CURL_VERSION} | tr '.' '_') +popd >/dev/null 2>&1 +groupend + +# Fetch BoringSSL +groupstart "Fetching BoringSSL" +[[ -d boringssl ]] || git clone https://boringssl.googlesource.com/boringssl +pushd boringssl >/dev/null 2>&1 +git checkout ${BORINGSSL_VERSION} +popd >/dev/null 2>&1 +groupend +