diff --git a/.github/workflows/ci-cross.yml b/.github/workflows/ci-cross.yml index a5478c8..e50e31d 100644 --- a/.github/workflows/ci-cross.yml +++ b/.github/workflows/ci-cross.yml @@ -10,8 +10,8 @@ on: branches: [ master, main ] workflow_dispatch: -env: - SWIFT_VERSION: "6.3.3" +# The container tags are bumped by Renovate. Scripts/install-swift-sdk.sh installs the +# SDK matching whatever toolchain the container provides. jobs: musl: @@ -24,9 +24,8 @@ jobs: - name: Install Static Linux SDK run: | - swift sdk install \ - "https://download.swift.org/swift-${SWIFT_VERSION}-release/static-sdk/swift-${SWIFT_VERSION}-RELEASE/swift-${SWIFT_VERSION}-RELEASE_static-linux-0.1.0.artifactbundle.tar.gz" \ - --checksum 87c3eaf908e67c0e13a84367119e12273cec1d2cd3d81f7d74bb36722d6b607b + apt-get update -q && apt-get install -yq jq curl + Scripts/install-swift-sdk.sh static # The static Linux SDK does not ship Swift Testing, so only the library is built. - name: Build @@ -42,12 +41,13 @@ jobs: - name: Install Wasm SDK run: | - swift sdk install \ - "https://download.swift.org/swift-${SWIFT_VERSION}-release/wasm-sdk/swift-${SWIFT_VERSION}-RELEASE/swift-${SWIFT_VERSION}-RELEASE_wasm.artifactbundle.tar.gz" \ - --checksum cabfa08b73bb8ac783927ecd15fa386e99d0c139c5f232445067bcf58379cae7 + apt-get update -q && apt-get install -yq jq curl + Scripts/install-swift-sdk.sh wasm - name: Build (including tests) - run: swift build --swift-sdk "swift-${SWIFT_VERSION}-RELEASE_wasm" --build-tests -Xswiftc -warnings-as-errors + run: | + SDK=$(swift sdk list | grep -E '_wasm$' | head -n 1) + swift build --swift-sdk "$SDK" --build-tests -Xswiftc -warnings-as-errors android: name: Android @@ -59,13 +59,12 @@ jobs: - name: Install Android SDK run: | - swift sdk install \ - "https://download.swift.org/swift-${SWIFT_VERSION}-release/android-sdk/swift-${SWIFT_VERSION}-RELEASE/swift-${SWIFT_VERSION}-RELEASE_android.artifactbundle.tar.gz" \ - --checksum d160cc3206dd1886dae3fef2337af5e25ec034692cd0ec225721c56cc69da7f5 + apt-get update -q && apt-get install -yq jq curl + Scripts/install-swift-sdk.sh android - name: Install Android NDK run: | - apt-get update -q && apt-get install -yq unzip curl + apt-get install -yq unzip curl -fsSL -o ndk.zip https://dl.google.com/android/repository/android-ndk-r27d-linux.zip unzip -q ndk.zip -d "$HOME" echo "ANDROID_NDK_HOME=$HOME/android-ndk-r27d" >> "$GITHUB_ENV" @@ -73,10 +72,17 @@ jobs: - name: Link NDK into Swift SDK run: | swift sdk list - SETUP=$(find / -name setup-android-sdk.sh -path '*swift-6*' 2>/dev/null | head -n 1) + SETUP=$(find / -name setup-android-sdk.sh -path '*swift-*' 2>/dev/null | head -n 1) echo "Using $SETUP" test -n "$SETUP" bash "$SETUP" - name: Build (including tests) - run: swift build --swift-sdk aarch64-unknown-linux-android28 --build-tests -Xswiftc -warnings-as-errors + run: | + # `swift sdk list` shows bundle names, so read the aarch64 target triples from the bundle + # and build for the lowest Android API level it supports. + SDK=$(find / -path '*android.artifactbundle*' -name swift-sdk.json 2>/dev/null \ + | xargs jq -r '.targetTriples | keys[]' | grep '^aarch64-' | sort -V | head -n 1) + echo "Using Swift SDK $SDK" + test -n "$SDK" + swift build --swift-sdk "$SDK" --build-tests -Xswiftc -warnings-as-errors diff --git a/Scripts/install-swift-sdk.sh b/Scripts/install-swift-sdk.sh new file mode 100755 index 0000000..fb9c5d5 --- /dev/null +++ b/Scripts/install-swift-sdk.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# Installs the Swift SDK that matches the active toolchain. +# +# A Swift SDK must match the compiler version exactly. CI runs in `swift:X.Y.Z` +# containers whose tag Renovate bumps, so the SDK URL and checksum are looked up +# from the official swift.org release API for whatever toolchain is installed. +# +# Usage: Scripts/install-swift-sdk.sh +# Prints the installed Swift SDK ID on the last line of output. +set -euo pipefail + +KIND="${1:?usage: install-swift-sdk.sh }" + +# e.g. "Swift version 6.4.1 (swift-6.4.1-RELEASE)" +TOOLCHAIN_TAG=$(swift --version 2>&1 | grep -oE 'swift-[0-9]+(\.[0-9]+)+-RELEASE' | head -n 1) +if [ -z "${TOOLCHAIN_TAG}" ]; then + echo "error: could not determine the toolchain release tag from 'swift --version'" >&2 + exit 1 +fi +# The API spells x.y.0 releases with a trailing ".0" even when the compiler omits it. +TOOLCHAIN_TAG_PATCHED=$(echo "${TOOLCHAIN_TAG}" | sed -E 's/^swift-([0-9]+\.[0-9]+)-RELEASE$/swift-\1.0-RELEASE/') + +RELEASE=$(curl -fsSL https://www.swift.org/api/v1/install/releases.json \ + | jq -c --arg t "${TOOLCHAIN_TAG}" --arg t0 "${TOOLCHAIN_TAG_PATCHED}" \ + '[.[] | select(.tag == $t or .tag == $t0)] | first') +if [ "${RELEASE}" = "null" ]; then + echo "error: ${TOOLCHAIN_TAG} not found in the swift.org release API" >&2 + exit 1 +fi +TAG=$(echo "${RELEASE}" | jq -r .tag) +VERSION=${TAG#swift-} +VERSION=${VERSION%-RELEASE} + +PLATFORM=$(echo "${RELEASE}" | jq -c --arg p "${KIND}-sdk" '.platforms[] | select(.platform == $p)') +if [ -z "${PLATFORM}" ]; then + echo "error: ${TAG} has no ${KIND} SDK" >&2 + exit 1 +fi +CHECKSUM=$(echo "${PLATFORM}" | jq -r .checksum) + +case "${KIND}" in + static) FILE="${TAG}_static-linux-$(echo "${PLATFORM}" | jq -r .version).artifactbundle.tar.gz" ;; + wasm) FILE="${TAG}_wasm.artifactbundle.tar.gz" ;; + android) FILE="${TAG}_android.artifactbundle.tar.gz" ;; + *) echo "error: unknown SDK kind '${KIND}'" >&2; exit 1 ;; +esac + +URL="https://download.swift.org/swift-${VERSION}-release/${KIND}-sdk/${TAG}/${FILE}" +echo "Installing ${URL}" +swift sdk install "${URL}" --checksum "${CHECKSUM}"