├── .github └── workflows │ └── sdks.yml ├── .gitignore ├── LICENSE ├── README.md ├── get-packages-and-swift-source.swift ├── libc++-stdlib.h.patch ├── swift-android-ci-except-release.patch ├── swift-android-ci-release.patch ├── swift-android-ci.patch ├── swift-android-devel.patch ├── swift-android-testing-except-release.patch ├── swift-android-testing-release.patch ├── swift-android-trunk-libdispatch.patch ├── swift-android.patch ├── swift-nio-disable-ecn-tests.patch ├── swift-nio-filesystem.patch └── swift-nio-ssl-test.patch /.github/workflows/sdks.yml: -------------------------------------------------------------------------------- 1 | name: SDKs 2 | on: 3 | pull_request: 4 | schedule: 5 | - cron: '0 5 * * *' 6 | 7 | jobs: 8 | bundle-tests: 9 | runs-on: ${{ matrix.os }} 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | version: [release, devel, trunk] 14 | os: [ubuntu-24.04, macos-13] 15 | env: 16 | ANDROID_API_LEVEL: 24 17 | BUNDLE_VERSION: 0.1 18 | NDK_VERSION: 27c 19 | steps: 20 | - name: Check for latest Swift ${{ matrix.version }} toolchain 21 | id: version 22 | run: | 23 | if [ ${{ matrix.version }} = 'release' ]; then 24 | LATEST_TOOLCHAIN_VERSION=$(curl -sL https://github.com/apple/swift/releases | grep -m1 swift-6.1 | cut -d- -f2) 25 | SWIFT_TAG="swift-${LATEST_TOOLCHAIN_VERSION}-RELEASE" 26 | elif [ ${{ matrix.version }} = 'devel' ]; then 27 | LATEST_TOOLCHAIN_VERSION=$(curl -sL https://github.com/apple/swift/tags | grep -m1 swift-6.2-DEV | cut -d- -f8-10) 28 | SWIFT_TAG="swift-6.2-DEVELOPMENT-SNAPSHOT-${LATEST_TOOLCHAIN_VERSION}-a" 29 | else 30 | LATEST_TOOLCHAIN_VERSION=$(curl -sL https://github.com/apple/swift/tags | grep -m1 swift-DEV | cut -d- -f7-9) 31 | SWIFT_TAG="swift-DEVELOPMENT-SNAPSHOT-${LATEST_TOOLCHAIN_VERSION}-a" 32 | fi 33 | echo "tag=$SWIFT_TAG" >> $GITHUB_OUTPUT 34 | echo "key=$SWIFT_TAG-ndk-${NDK_VERSION}-bt-bundle" >> $GITHUB_OUTPUT 35 | - name: Get cached SDK bundle 36 | id: cache-bundle 37 | uses: actions/cache/restore@v4 38 | with: 39 | path: ~/${{ steps.version.outputs.tag }}-android-${{ env.ANDROID_API_LEVEL }}-${{ env.BUNDLE_VERSION }}.artifactbundle.tar.gz 40 | key: ${{ steps.version.outputs.key }} 41 | fail-on-cache-miss: ${{ startsWith(matrix.os, 'macos') && 'true' || 'false' }} 42 | - name: Get cached ${{ matrix.os }} ${{ steps.version.outputs.tag }} toolchain 43 | id: cache-toolchain 44 | uses: actions/cache@v4 45 | with: 46 | path: ~/${{ steps.version.outputs.tag }}-${{ startsWith(matrix.os, 'macos') && 'osx.pkg' || 'ubuntu24.04.tar.gz' }} 47 | key: swift-${{ matrix.os }}-${{ steps.version.outputs.tag }}-toolchain 48 | - name: Download toolchain 49 | if: ${{ steps.cache-toolchain.outputs.cache-hit != 'true' }} 50 | env: 51 | SWIFT_TAG: ${{ steps.version.outputs.tag }} 52 | run: | 53 | if [ ${{ matrix.version }} != 'trunk' ]; then 54 | SWIFT_BRANCH="swift-$(echo $SWIFT_TAG | cut -d- -f2)-${{ matrix.version == 'release' && 'release' || 'branch' }}" 55 | else 56 | SWIFT_BRANCH="development" 57 | fi 58 | cd 59 | if ${{ steps.cache-toolchain.outputs.cache-hit != 'true' }}; then 60 | wget -q https://download.swift.org/$SWIFT_BRANCH/${{ startsWith(matrix.os, 'macos') && 'xcode' || 'ubuntu2404' }}/$SWIFT_TAG/$SWIFT_TAG-${{ startsWith(matrix.os, 'macos') && 'osx.pkg' || 'ubuntu24.04.tar.gz' }} 61 | echo "downloaded latest ${{ matrix.os }} toolchain: ${SWIFT_TAG}" 62 | fi 63 | 64 | - name: Extract toolchain and set it up 65 | env: 66 | SWIFT_TAG: ${{ steps.version.outputs.tag }} 67 | run: | 68 | if ${{ startsWith(matrix.os, 'macos') }}; then 69 | mkdir ${SWIFT_TAG} 70 | pushd ${SWIFT_TAG} 71 | xar -x -C . -f ~/${SWIFT_TAG}-osx.pkg 72 | tar xz -C . -f ${SWIFT_TAG}-osx-package.pkg/Payload 73 | TOOLCHAIN=${PWD}/usr 74 | popd 75 | elif ${{ startsWith(matrix.os, 'ubuntu') }}; then 76 | SWIFT_TOOLS=$SWIFT_TAG-$(echo ${{ matrix.os }} | tr -d - ) 77 | tar xf ~/$SWIFT_TOOLS.tar.gz 78 | TOOLCHAIN=${PWD}/$SWIFT_TOOLS/usr 79 | fi 80 | 81 | echo "TOOLCHAIN=${TOOLCHAIN}" >> $GITHUB_ENV 82 | ${TOOLCHAIN}/bin/swift --version 83 | - name: Get cached Android NDK sysroot and runtime libraries 84 | id: cache-ndk 85 | uses: actions/cache@v4 86 | if: ${{ (steps.cache-bundle.outputs.cache-hit != 'true') && startsWith(matrix.os, 'ubuntu') }} 87 | with: 88 | path: ~/android-sysroot.tar.xz 89 | key: android-ndk-${{ env.NDK_VERSION }} 90 | - name: Extract Android NDK sysroot if not cached before 91 | if: ${{ steps.cache-bundle.outputs.cache-hit != 'true' && steps.cache-ndk.outputs.cache-hit != 'true' && startsWith(matrix.os, 'ubuntu') }} 92 | run: | 93 | wget -q https://dl.google.com/android/repository/android-ndk-r$NDK_VERSION-linux.zip 94 | if [ "$(sha1sum android-ndk-r$NDK_VERSION-linux.zip | cut -f1 -d" ")" != '090e8083a715fdb1a3e402d0763c388abb03fb4e' ]; then 95 | echo "NDK checksum didn't match" 96 | exit 1 97 | fi 98 | unzip -q android-ndk-r$NDK_VERSION-linux.zip 99 | rm android-ndk-r$NDK_VERSION-linux.zip 100 | mv android-ndk-r$NDK_VERSION/toolchains/llvm/prebuilt/linux-x86_64/sysroot . 101 | rm -r sysroot/usr/{include,lib}/{i686,riscv64}-linux-android 102 | mv android-ndk-r$NDK_VERSION/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/*/lib/linux sysroot 103 | rm -r sysroot/linux/*{i[36]86,riscv64}* android-ndk-r$NDK_VERSION 104 | tar cJf ~/android-sysroot.tar.xz sysroot 105 | - name: Clone 106 | uses: actions/checkout@v4 107 | with: 108 | path: sdk-config 109 | - name: Build Swift ${{ matrix.version }} Android SDK bundle if not the latest 110 | # build-script currently only works on ubuntu 111 | if: ${{ (steps.cache-bundle.outputs.cache-hit != 'true') && startsWith(matrix.os, 'ubuntu') }} 112 | env: 113 | SWIFT_TAG: ${{ steps.version.outputs.tag }} 114 | run: | 115 | set -x 116 | 117 | if ${{ startsWith(matrix.os, 'macos') }}; then 118 | brew install ninja patchelf 119 | elif ${{ startsWith(matrix.os, 'ubuntu') }}; then 120 | sudo apt install ninja-build 121 | fi 122 | 123 | cd sdk-config 124 | 125 | ANDROID_ARCH=aarch64 BUILD_SWIFT_PM=1 ${TOOLCHAIN}/bin/swift get-packages-and-swift-source.swift 126 | 127 | git apply -C1 swift-android.patch swift-android-ci.patch 128 | if ${{ matrix.version == 'release' }}; then 129 | perl -pi -e 's%r26%ndk/27%' swift/stdlib/cmake/modules/AddSwiftStdlib.cmake 130 | LSP_BUILD="--sourcekit-lsp" 131 | git apply swift-android-ci-release.patch swift-android-testing-release.patch 132 | else 133 | if ${{ matrix.version == 'trunk' }}; then 134 | git apply swift-android-trunk-libdispatch.patch 135 | else 136 | git apply swift-android-devel.patch 137 | fi 138 | git apply -C2 swift-android-ci-except-release.patch swift-android-testing-except-release.patch 139 | SDK_NAME=$(ls | grep swift-${{ matrix.version }}-android-aarch64) 140 | perl -pi -e 's%33%24%' $ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/execinfo.h 141 | fi 142 | 143 | perl -pi -e 's%String\(cString: getpass%\"fake\" //%' swiftpm/Sources/PackageRegistryCommand/PackageRegistryCommand+Auth.swift 144 | perl -pi -e "s%swift/android',%swift/android', '-Xlinker', '-landroid-spawn',%" sourcekit-lsp/Utilities/build-script-helper.py 145 | VERSION="$(echo ${{ steps.version.outputs.tag }} | cut -f1,2 -d-)-${{ matrix.version }}" 146 | 147 | # e.g. swift-6.1-release-android-24-sdk 148 | SDK_DIR=$VERSION-android-${ANDROID_API_LEVEL}-sdk 149 | ROOT=android-${NDK_VERSION}-sysroot 150 | SYSROOT=$SDK_DIR/$ROOT 151 | mkdir ${SDK_DIR} 152 | 153 | tar xf ~/android-sysroot.tar.xz 154 | mv sysroot $SYSROOT 155 | 156 | for arch in aarch64 x86_64 armv7; do 157 | if [[ $arch != 'aarch64' ]]; then 158 | ANDROID_ARCH=$arch BUILD_SWIFT_PM=1 ${TOOLCHAIN}/bin/swift get-packages-and-swift-source.swift 159 | fi 160 | SDK_NAME=$(ls | grep swift-${{ matrix.version }}-android-$arch) 161 | SDK=`pwd`/$SDK_NAME 162 | 163 | # Patch the NDK execinfo.h to work with the backported libandroid-execinfo 164 | cp $SYSROOT/usr/include/execinfo.h ${SDK_NAME}/usr/include 165 | perl -pi -e 's%33%24%' ${SDK_NAME}/usr/include/execinfo.h 166 | 167 | ./swift/utils/build-script -RA --skip-build-cmark --build-llvm=0 --android --android-ndk $ANDROID_NDK_HOME --android-arch $arch --android-api-level $ANDROID_API_LEVEL --build-swift-tools=0 --native-swift-tools-path=${TOOLCHAIN}/bin --native-clang-tools-path=${TOOLCHAIN}/bin --cross-compile-hosts=android-$arch --cross-compile-deps-path=$SDK --skip-local-build --build-swift-static-stdlib --xctest --install-swift --install-libdispatch --install-foundation --install-xctest --install-destdir=$SDK --swift-install-components='compiler;clang-resource-dir-symlink;license;stdlib;sdk-overlay' --cross-compile-append-host-target-to-destdir=False -b --install-llbuild --swift-testing --install-swift-testing -p $LSP_BUILD 168 | 169 | rm $ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/swift 170 | 171 | pushd ${SDK_NAME}/usr 172 | 173 | patchelf --set-rpath \$ORIGIN lib/swift/android/lib[dFXs]*.so 174 | # Remove executables and unused toolchain headers/libraries 175 | rm -r bin lib/libsqlite3.so lib/lib{curses,ncurses}.so lib/terminfo share/{tabset,terminfo} 176 | mv include/curl include/execinfo.h include/libxml2 include/spawn.h . 177 | rm -r include/* 178 | mv curl execinfo.h libxml2 spawn.h include/ 179 | cp -r ../../swift/lib/ClangImporter/SwiftBridging/{module.modulemap,swift} include/ 180 | 181 | TRIPLE="$arch-linux-android" 182 | if [[ $arch == 'armv7' ]]; then 183 | TRIPLE="arm-linux-androideabi" 184 | fi 185 | 186 | mkdir lib/${TRIPLE} 187 | mv lib/lib[a-z]*.so lib/pkgconfig lib/swift/android/lib*.{a,so} lib/${TRIPLE} 188 | 189 | mv lib/swift_static lib/swift_static-$arch 190 | mv lib/libandroid-spawn.a lib/swift_static-$arch/android 191 | rm lib/swift{,_static-$arch}/clang 192 | 193 | popd 194 | 195 | # copy all the processed SDK files into the Android sysroot 196 | rsync -ar ${SDK_NAME}/ $SYSROOT 197 | done 198 | 199 | # Copy necessary headers and libraries from the toolchain and NDK clang resource directories 200 | mkdir -p $SYSROOT/usr/lib/swift/clang/lib 201 | cp -r $TOOLCHAIN/lib/clang/*/include $SYSROOT/usr/lib/swift/clang 202 | mv $SYSROOT/linux $SYSROOT/usr/lib/swift/clang/lib 203 | ln -s ../swift/clang $SYSROOT/usr/lib/swift_static-aarch64/clang 204 | ln -s ../swift/clang $SYSROOT/usr/lib/swift_static-armv7/clang 205 | ln -s ../swift/clang $SYSROOT/usr/lib/swift_static-x86_64/clang 206 | 207 | # Patch a single libc++ header to work around a Swift compiler bug 208 | cd $SYSROOT 209 | git apply ../../libc++-stdlib.h.patch 210 | cd ../.. 211 | 212 | BUNDLE=${{ steps.version.outputs.tag }}-android-${ANDROID_API_LEVEL}-${BUNDLE_VERSION} 213 | BUNDLE_DIR=$BUNDLE.artifactbundle 214 | mkdir ${BUNDLE_DIR} 215 | mv ${SDK_DIR} ${BUNDLE_DIR} 216 | 217 | cat > $BUNDLE_DIR/info.json << EOF 218 | { 219 | "schemaVersion": "1.0", 220 | "artifacts": { 221 | "${BUNDLE}": { 222 | "variants": [ { "path": "${SDK_DIR}" } ], 223 | "version": "${BUNDLE_VERSION}", 224 | "type": "swiftSDK" 225 | } 226 | } 227 | } 228 | EOF 229 | 230 | cat > $BUNDLE_DIR/$SDK_DIR/swift-sdk.json << EOF 231 | { 232 | "schemaVersion": "4.0", 233 | "targetTriples": { 234 | EOF 235 | 236 | for api in $(eval echo "{$ANDROID_API_LEVEL..35}"); do 237 | if [[ ${api} == "35" ]]; then 238 | TRAILING_COMMA="" 239 | else 240 | TRAILING_COMMA="," 241 | fi 242 | cat >> $BUNDLE_DIR/$SDK_DIR/swift-sdk.json << EOF 243 | "aarch64-unknown-linux-android$api": { 244 | "sdkRootPath": "${ROOT}", 245 | "swiftResourcesPath": "${ROOT}/usr/lib/swift", 246 | "swiftStaticResourcesPath": "${ROOT}/usr/lib/swift_static-aarch64", 247 | "toolsetPaths": ["swift-toolset.json"] 248 | }, 249 | "x86_64-unknown-linux-android$api": { 250 | "sdkRootPath": "${ROOT}", 251 | "swiftResourcesPath": "${ROOT}/usr/lib/swift", 252 | "swiftStaticResourcesPath": "${ROOT}/usr/lib/swift_static-x86_64", 253 | "toolsetPaths": ["swift-toolset.json"] 254 | }, 255 | "armv7-unknown-linux-androideabi$api": { 256 | "sdkRootPath": "${ROOT}", 257 | "swiftResourcesPath": "${ROOT}/usr/lib/swift", 258 | "swiftStaticResourcesPath": "${ROOT}/usr/lib/swift_static-armv7", 259 | "toolsetPaths": ["swift-toolset.json"] 260 | }${TRAILING_COMMA} 261 | EOF 262 | done 263 | 264 | cat >> $BUNDLE_DIR/$SDK_DIR/swift-sdk.json << EOF 265 | } 266 | } 267 | EOF 268 | 269 | cat > $BUNDLE_DIR/$SDK_DIR/swift-toolset.json << EOF 270 | { 271 | "cCompiler": { "extraCLIOptions": ["-fPIC"] }, 272 | "swiftCompiler": { "extraCLIOptions": ["-Xclang-linker", "-fuse-ld=lld"] }, 273 | "schemaVersion": "1.0" 274 | } 275 | EOF 276 | 277 | cat > $BUNDLE_DIR/$SYSROOT/SDKSettings.json << EOF 278 | { 279 | "DisplayName": "Android NDK ${NDK_VERSION} sysroot with ${VERSION} runtime libraries for API ${ANDROID_API_LEVEL}", 280 | "Version": "27.2.12479018", 281 | "VersionMap": {}, 282 | "CanonicalName": "${VERSION}-android${ANDROID_API_LEVEL}" 283 | } 284 | EOF 285 | 286 | # output visualization of the SDK bundle file tree 287 | tree $BUNDLE_DIR 288 | 289 | du -skh "${BUNDLE_DIR}" 290 | tar czf ~/${BUNDLE_DIR}.tar.gz "${BUNDLE_DIR}" 291 | du -skh ~/${BUNDLE_DIR}.tar.gz 292 | shasum -a 256 ~/${BUNDLE_DIR}.tar.gz 293 | rm -rf build/ swift-${{ matrix.version }}-android-*-sdk/ $BUNDLE_DIR llvm-project/ 294 | - name: Cache SDK bundle 295 | uses: actions/cache/save@v4 296 | if: ${{ (steps.cache-bundle.outputs.cache-hit != 'true') && startsWith(matrix.os, 'ubuntu') }} 297 | with: 298 | path: ~/${{ steps.version.outputs.tag }}-android-${{ env.ANDROID_API_LEVEL }}-${{ env.BUNDLE_VERSION }}.artifactbundle.tar.gz 299 | key: ${{ steps.version.outputs.key }} 300 | - name: Upload SDK bundle 301 | if: ${{ startsWith(matrix.os, 'ubuntu') }} 302 | uses: actions/upload-artifact@v4 303 | with: 304 | name: ${{ steps.version.outputs.tag }}-android-${{ env.ANDROID_API_LEVEL }}-${{ env.BUNDLE_VERSION }}.artifactbundle.tar.gz 305 | path: ~/${{ steps.version.outputs.tag }}-android-${{ env.ANDROID_API_LEVEL }}-${{ env.BUNDLE_VERSION }}.artifactbundle.tar.gz 306 | compression-level: 0 307 | - name: Install ${{ matrix.version }} Android SDK bundle and set SwiftPM flags 308 | run: | 309 | ${TOOLCHAIN}/bin/swift sdk install ~/${{ steps.version.outputs.tag }}-android-*.artifactbundle.tar.gz 310 | ${TOOLCHAIN}/bin/swift sdk configure --show-configuration ${{ steps.version.outputs.tag }}-android-${ANDROID_API_LEVEL}-${BUNDLE_VERSION} armv7-unknown-linux-androideabi${ANDROID_API_LEVEL} 311 | 312 | echo "ANDROID_NDK_ROOT=" >> $GITHUB_ENV 313 | 314 | SFLAGS="--swift-sdk aarch64-unknown-linux-android${ANDROID_API_LEVEL} ${FLAGS}" 315 | echo "SWIFTPM_AARCH_FLAGS=${SFLAGS}" >> $GITHUB_ENV 316 | XFLAGS="--swift-sdk x86_64-unknown-linux-android${ANDROID_API_LEVEL} ${FLAGS}" 317 | echo "SWIFTPM_X_FLAGS=${XFLAGS}" >> $GITHUB_ENV 318 | AFLAGS="--swift-sdk armv7-unknown-linux-androideabi${ANDROID_API_LEVEL} ${FLAGS}" 319 | echo "SWIFTPM_ARM_FLAGS=${AFLAGS}" >> $GITHUB_ENV 320 | - name: Get Swift Argument Parser package 321 | uses: actions/checkout@v4 322 | with: 323 | repository: apple/swift-argument-parser 324 | path: swift-argument-parser 325 | - name: Build Swift Argument Parser package 326 | run: | 327 | cd swift-argument-parser 328 | rm Examples/count-lines/CountLines.swift Tools/changelog-authors/*.swift 329 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_AARCH_FLAGS} 330 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_X_FLAGS} 331 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_ARM_FLAGS} 332 | - name: Get Swift crypto package 333 | uses: actions/checkout@v4 334 | with: 335 | repository: apple/swift-crypto 336 | path: swift-crypto 337 | - name: Build Swift crypto package 338 | run: | 339 | cd swift-crypto 340 | perl -pi -e 's%\\\\(testsDirectory)/.*Vectors%/data/local/tmp/pack/crypto-vectors%' Tests/{Crypto,_CryptoExtras}Tests/Utils/{RFCVector,Wycheproof}.swift 341 | perl -pi -e 's%#file%"/data/local/tmp/pack/crypto-vectors"%;s%../_CryptoExtrasVectors/%%' Tests/_CryptoExtrasTests/TestRSABlindSigning.swift 342 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_AARCH_FLAGS} 343 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_X_FLAGS} 344 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_ARM_FLAGS} 345 | - name: Get Swift NIO package 346 | uses: actions/checkout@v4 347 | with: 348 | repository: apple/swift-nio 349 | path: swift-nio 350 | - name: Build Swift NIO package 351 | run: | 352 | cd swift-nio 353 | git apply ../sdk-config/swift-nio-disable-ecn-tests.patch ../sdk-config/swift-nio-filesystem.patch 354 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_AARCH_FLAGS} 355 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_X_FLAGS} 356 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_ARM_FLAGS} 357 | - name: Get Swift Numerics package 358 | uses: actions/checkout@v4 359 | with: 360 | repository: apple/swift-numerics 361 | path: swift-numerics 362 | - name: Build Swift Numerics package 363 | run: | 364 | cd swift-numerics 365 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_AARCH_FLAGS} 366 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_X_FLAGS} 367 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_ARM_FLAGS} 368 | - name: Get Swift System package 369 | uses: actions/checkout@v4 370 | with: 371 | repository: apple/swift-system 372 | path: swift-system 373 | - name: Build Swift System package 374 | run: | 375 | cd swift-system 376 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_AARCH_FLAGS} 377 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_X_FLAGS} 378 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_ARM_FLAGS} 379 | - name: Get Swift Collections package 380 | uses: actions/checkout@v4 381 | with: 382 | repository: apple/swift-collections 383 | path: swift-collections 384 | - name: Build Swift Collections package 385 | run: | 386 | cd swift-collections 387 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_AARCH_FLAGS} 388 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_X_FLAGS} 389 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_ARM_FLAGS} 390 | - name: Get Swift Atomics package 391 | uses: actions/checkout@v4 392 | with: 393 | repository: apple/swift-atomics 394 | path: swift-atomics 395 | ref: 1.2.0 396 | - name: Get Swift NIO SSH package 397 | uses: actions/checkout@v4 398 | with: 399 | repository: apple/swift-nio-ssh 400 | path: sns 401 | - name: Build Swift NIO SSH package 402 | run: | 403 | cd sns 404 | perl -pi -e 's%url: .*swift-([a-z]*)\.git.*$%path: \"../swift-\1\"),%g' Package.swift 405 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_AARCH_FLAGS} 406 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_X_FLAGS} 407 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_ARM_FLAGS} 408 | - name: Get Swift NIO SSL package 409 | uses: actions/checkout@v4 410 | with: 411 | repository: apple/swift-nio-ssl 412 | path: snl 413 | - name: Build Swift NIO SSL package 414 | run: | 415 | cd snl 416 | git apply ../sdk-config/swift-nio-ssl-test.patch 417 | SWIFTCI_USE_LOCAL_DEPS=1 ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_AARCH_FLAGS} 418 | SWIFTCI_USE_LOCAL_DEPS=1 ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_X_FLAGS} 419 | SWIFTCI_USE_LOCAL_DEPS=1 ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_ARM_FLAGS} 420 | - name: Get Yams package 421 | uses: actions/checkout@v4 422 | with: 423 | repository: jpsim/Yams 424 | path: yams 425 | - name: Build Yams package 426 | run: | 427 | cd yams 428 | perl -pi -e 's% fixturesDirectory + \"/SourceKitten#289% \"/data/local/tmp/pack%' Tests/YamsTests/PerformanceTests.swift 429 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_AARCH_FLAGS} 430 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_X_FLAGS} 431 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_ARM_FLAGS} 432 | - name: Get Swift NIO HTTP/2 package 433 | uses: actions/checkout@v4 434 | with: 435 | repository: apple/swift-nio-http2 436 | path: snh 437 | - name: Build Swift NIO HTTP/2 package 438 | run: | 439 | cd snh 440 | perl -pi -e 's%url: .*swift-([a-z]*)\.git.*$%path: \"../swift-\1\"),%g' Package.swift 441 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_AARCH_FLAGS} 442 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_X_FLAGS} 443 | - name: Get Swift Algorithms package 444 | uses: actions/checkout@v4 445 | with: 446 | repository: apple/swift-algorithms 447 | path: sa 448 | - name: Build Swift Algorithms package 449 | run: | 450 | cd sa 451 | perl -pi -e 's%url: .*$%path: \"../swift-numerics\"),%' Package.swift 452 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_AARCH_FLAGS} 453 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_X_FLAGS} 454 | ${TOOLCHAIN}/bin/swift build --build-tests ${SWIFTPM_ARM_FLAGS} 455 | - name: Get cached Termux debug app for NIO tests 456 | id: cache-termux 457 | uses: actions/cache@v4 458 | with: 459 | path: ~/termux-debug.apk 460 | key: termux-app 461 | - name: Get Termux debug app if not cached 462 | if: ${{ steps.cache-termux.outputs.cache-hit != 'true' }} 463 | run: wget -O ~/termux-debug.apk https://github.com/termux/termux-app/releases/download/v0.118.0/termux-app_v0.118.0+github-debug_x86_64.apk 464 | - name: Prepare Android emulator test package and script 465 | run: | 466 | set -x 467 | # create the test runner script 468 | cat > ~/test-toolchain.sh << EOF 469 | adb install ~/termux-debug.apk 470 | adb push pack /data/local/tmp 471 | adb shell "run-as com.termux mkdir /data/data/com.termux/pack" 472 | adb shell "run-as com.termux cp /data/local/tmp/pack/{lib*.so,swift-nioPackageTests.xctest,FileHandleTests.swift} /data/data/com.termux/pack" 473 | adb shell "run-as com.termux cp -r /data/local/tmp/pack/Test\ Data /data/data/com.termux/pack" 474 | adb shell "run-as com.termux ln -s README.md /data/data/com.termux/pack/Test\ Data/README.md.symlink" 475 | adb shell "run-as com.termux ln -s Foo /data/data/com.termux/pack/Test\ Data/Foo.symlink" 476 | adb shell "run-as com.termux sh -c 'TMPDIR=/data/data/com.termux /data/data/com.termux/pack/swift-nioPackageTests.xctest'" 477 | adb shell "TMPDIR=/data/local/tmp /data/local/tmp/pack/swift-systemPackageTests.xctest" 478 | EOF 479 | 480 | mkdir pack 481 | TARGET="x86_64-unknown-linux-android$ANDROID_API_LEVEL" 482 | 483 | cp swift-argument-parser/.build/$TARGET/debug/{generate-manual,math,repeat,roll,swift-argument-parserPackageTests.xctest} pack 484 | echo 'adb shell /data/local/tmp/pack/swift-argument-parserPackageTests.xctest' >> ~/test-toolchain.sh 485 | 486 | wget -q https://raw.githubusercontent.com/termux/termux-elf-cleaner/v2.1.1/elf-cleaner.cpp 487 | wget -q https://raw.githubusercontent.com/termux/termux-elf-cleaner/v2.1.1/elf.h 488 | wget -q https://raw.githubusercontent.com/termux/termux-elf-cleaner/v2.1.1/arghandling.h 489 | wget -q https://raw.githubusercontent.com/termux/termux-elf-cleaner/v2.1.1/arghandling.c 490 | clang -c arghandling.c 491 | clang -o elf-cleaner arghandling.o elf-cleaner.cpp -DCOPYRIGHT=\"foo\" -DPACKAGE_NAME=\"termux-elf-cleaner\" -DPACKAGE_VERSION=\"2.2.1\" 492 | ./elf-cleaner --api-level $ANDROID_API_LEVEL pack/{generate-manual,math,repeat,roll} || true 493 | 494 | cp swift-crypto/.build/$TARGET/debug/swift-cryptoPackageTests.xctest pack 495 | echo 'adb shell /data/local/tmp/pack/swift-cryptoPackageTests.xctest' >> ~/test-toolchain.sh 496 | 497 | cp swift-nio/.build/$TARGET/debug/swift-nioPackageTests.xctest pack 498 | 499 | cp swift-numerics/.build/$TARGET/debug/swift-numericsPackageTests.xctest pack 500 | echo 'adb shell /data/local/tmp/pack/swift-numericsPackageTests.xctest' >> ~/test-toolchain.sh 501 | 502 | cp swift-system/.build/$TARGET/debug/swift-systemPackageTests.xctest pack 503 | cp swift-collections/.build/$TARGET/debug/swift-collectionsPackageTests.xctest pack 504 | echo 'adb shell /data/local/tmp/pack/swift-collectionsPackageTests.xctest' >> ~/test-toolchain.sh 505 | 506 | cp sns/.build/$TARGET/debug/swift-nio-sshPackageTests.xctest pack 507 | echo 'adb shell /data/local/tmp/pack/swift-nio-sshPackageTests.xctest' >> ~/test-toolchain.sh 508 | 509 | cp snl/.build/$TARGET/debug/swift-nio-sslPackageTests.xctest pack 510 | echo 'adb shell /data/local/tmp/pack/swift-nio-sslPackageTests.xctest' >> ~/test-toolchain.sh 511 | 512 | cp snh/.build/$TARGET/debug/swift-nio-http2PackageTests.xctest pack 513 | echo 'adb shell /data/local/tmp/pack/swift-nio-http2PackageTests.xctest' >> ~/test-toolchain.sh 514 | 515 | cp yams/.build/$TARGET/debug/YamsPackageTests.xctest pack 516 | echo 'adb shell /data/local/tmp/pack/YamsPackageTests.xctest' >> ~/test-toolchain.sh 517 | 518 | cp sa/.build/$TARGET/debug/swift-algorithmsPackageTests.xctest pack 519 | echo 'adb shell /data/local/tmp/pack/swift-algorithmsPackageTests.xctest' >> ~/test-toolchain.sh 520 | 521 | mkdir pack/crypto-vectors pack/swift-crypto_CryptoTests.resources 522 | cp swift-crypto/Tests/Test\ Vectors/* swift-crypto/Tests/_CryptoExtrasVectors/* pack/crypto-vectors 523 | cp swift-crypto/Tests/CryptoTests/HPKE/hpke-test-vectors.json pack/swift-crypto_CryptoTests.resources 524 | rm swift-nio/Tests/NIOFileSystemIntegrationTests/Test\ Data/*symlink 525 | cp -r swift-nio/Tests/NIOFileSystemIntegrationTests/Test\ Data/ swift-nio/Tests/NIOFileSystemIntegrationTests/FileHandleTests.swift pack 526 | cp yams/Tests/YamsTests/Fixtures/SourceKitten#289/debug.yaml pack 527 | cp ~/.${{ startsWith(matrix.os, 'ubuntu') && 'config/' || '' }}swiftpm/swift-sdks/${{ steps.version.outputs.tag }}-android-${ANDROID_API_LEVEL}-*.artifactbundle/swift*sdk/android*sysroot/usr/lib/x86_64-linux-android/lib*so pack 528 | 529 | # need to free up some space or else the emulator fails to launch: 530 | # ERROR | Not enough space to create userdata partition. Available: 6086.191406 MB at /home/runner/.android/avd/../avd/test.avd, need 7372.800000 MB. 531 | rm -rf ${{ steps.version.outputs.tag }}-$(echo ${{ matrix.os }} | tr -d - )/ */.build 532 | 533 | chmod +x ~/test-toolchain.sh 534 | 535 | echo "TEST SCRIPT:" 536 | cat ~/test-toolchain.sh 537 | 538 | if ${{ startsWith(matrix.os, 'ubuntu') }}; then 539 | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules 540 | sudo udevadm control --reload-rules 541 | sudo udevadm trigger --name-match=kvm 542 | fi 543 | 544 | - name: Run tests on Android x86_64 emulator 545 | uses: reactivecircus/android-emulator-runner@v2 546 | with: 547 | api-level: ${{ env.ANDROID_API_LEVEL }} 548 | arch: x86_64 549 | script: ~/test-toolchain.sh 550 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | 204 | 205 | ## Runtime Library Exception to the Apache 2.0 License: ## 206 | 207 | 208 | As an exception, if you use this Software to compile your source code and 209 | portions of this Software are embedded into the binary product as a result, 210 | you may redistribute such product without providing attribution as would 211 | otherwise be required by Sections 4(a), 4(b) and 4(d) of the License. 212 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Swift cross-compilation SDK bundle for Android 2 | 3 | The patches used to build this SDK bundle are open source and listed below. I 4 | maintain [a daily CI on github Actions](https://github.com/finagolfin/swift-android-sdk/actions?query=event%3Aschedule) 5 | that [cross-compiles the SDK bundle from the release and development source branches of 6 | the Swift toolchain for AArch64, armv7, and x86_64, builds several Swift 7 | packages against those SDKs, and then runs their tests in the Android x86_64 8 | emulator](https://github.com/finagolfin/swift-android-sdk/blob/main/.github/workflows/sdks.yml). 9 | 10 | ## Cross-compiling and testing Swift packages with the Android SDK bundle 11 | 12 | To build with the Swift 6.1.2 SDK bundle, first download [the official open-source 13 | Swift 6.1.2 toolchain for linux or macOS](https://swift.org/install) 14 | (make sure to install the Swift dependencies linked there). Install the OSS 15 | toolchain on macOS as detailed in [the instructions for using the static linux 16 | Musl SDK bundle at swift.org](https://www.swift.org/documentation/articles/static-linux-getting-started.html). 17 | On linux, simply download the toolchain, unpack it, and add it to your `PATH`. 18 | 19 | Next, install the Android SDK bundle by having the Swift toolchain directly 20 | download it: 21 | ``` 22 | swift sdk install https://github.com/finagolfin/swift-android-sdk/releases/download/6.1.2/swift-6.1.2-RELEASE-android-24-0.1.artifactbundle.tar.gz --checksum 6d817c947870e8c85e6cab9a6ab6d7313b50fa5a20b890c396723c0b16ab32d9 23 | ``` 24 | or alternately, download the SDK bundle with your favorite downloader and install 25 | it separately: 26 | ``` 27 | > wget https://github.com/finagolfin/swift-android-sdk/releases/download/6.1.2/swift-6.1.2-RELEASE-android-24-0.1.artifactbundle.tar.gz 28 | > sha256sum swift-6.1.2-RELEASE-android-24-0.1.artifactbundle.tar.gz 29 | 6d817c947870e8c85e6cab9a6ab6d7313b50fa5a20b890c396723c0b16ab32d9 swift-6.1.2-RELEASE-android-24-0.1.artifactbundle.tar.gz 30 | > swift sdk install swift-6.1.2-RELEASE-android-24-0.1.artifactbundle.tar.gz 31 | ``` 32 | You can check if it was properly installed by running `swift sdk list`. 33 | 34 | Now you're ready to cross-compile a Swift package and run its tests on Android. 35 | I'll demonstrate with the swift-argument-parser package: 36 | ``` 37 | git clone --depth 1 https://github.com/apple/swift-argument-parser.git 38 | 39 | cd swift-argument-parser/ 40 | 41 | swift build --build-tests --swift-sdk aarch64-unknown-linux-android24 42 | ``` 43 | 44 | Note: On macOS, building for Android requires specifying an OSS toolchain like so: 45 | ``` 46 | swift build --build-tests --swift-sdk aarch64-unknown-linux-android24 --toolchain 47 | ``` 48 | 49 | This will cross-compile the package for Android aarch64 at API 24 and produce a 50 | test runner executable with the `.xctest` extension, in this case at 51 | `.build/aarch64-unknown-linux-android24/debug/swift-argument-parserPackageTests.xctest`. 52 | 53 | Sometimes the test runner will depend on additional files or executables: this 54 | one depends on the example executables `color`, `generate-manual`, `math`, 55 | `repeat`, and `roll` in the same build directory. Other packages use `#file` to 56 | point at test data in the repo: I've had success moving this data with the test 57 | runner, after modifying the test source so it has the path to this test data in 58 | the Android test environment. See the example of [swift-crypto on the 59 | CI](https://github.com/finagolfin/swift-android-sdk/blob/6.1.2/.github/workflows/sdks.yml#L521). 60 | 61 | You can copy these executables and the Swift runtime libraries to [an emulator 62 | or a USB debugging-enabled device with adb](https://github.com/swiftlang/swift/blob/release/6.1/docs/Android.md#3-deploying-the-build-products-to-the-device), 63 | or put them on an Android device with [a terminal emulator app like Termux](https://termux.dev/en/). 64 | I test aarch64 with Termux so I'll show how to run the test runner there, but 65 | the process is similar with adb, [as can be seen on the CI](https://github.com/finagolfin/swift-android-sdk/blob/6.1.2/.github/workflows/sdks.yml#L469). 66 | 67 | Copy the test executables to the same directory as the Swift 6.1.2 runtime libraries: 68 | ``` 69 | cp .build/aarch64-unknown-linux-android24/debug/{swift-argument-parserPackageTests.xctest,color,generate-manual,math,repeat,roll} .. 70 | cp ~/.swiftpm/swift-sdks/swift-6.1.2-RELEASE-android-24-0.1.artifactbundle/swift-6.1.2-release-android-24-sdk/android-27c-sysroot/usr/lib/aarch64-linux-android/lib*.so .. 71 | ``` 72 | You can copy the test executables and Swift 6.1.2 runtime libraries to Termux using 73 | scp from OpenSSH, run these commands in Termux on the Android device: 74 | ``` 75 | uname -m # check if you're running on the right architecture, should say `aarch64` 76 | cd # move to the Termux app's home directory 77 | pkg install openssh 78 | 79 | scp yourname@192.168.1.1:"lib*.so" . 80 | scp yourname@192.168.1.1:{swift-argument-parserPackageTests.xctest,color,generate-manual,math,repeat,roll} . 81 | 82 | ./swift-argument-parserPackageTests.xctest 83 | ``` 84 | I've tried several Swift packages, including some mostly written in C or C++, 85 | and all the cross-compiled tests passed. Note that while this SDK bundle is 86 | compiled against Android API 24, you can also specify an arbitrary later API to 87 | compile against, eg `--swift-sdk aarch64-unknown-linux-android29`. 88 | 89 | You can even run armv7 tests on an aarch64 device, though Termux may require 90 | running `unset LD_PRELOAD` before invoking an armv7 test runner on aarch64. 91 | Revert that with `export LD_PRELOAD=/data/data/com.termux/files/usr/lib/libtermux-exec.so` 92 | when you're done running armv7 tests and want to go back to the normal aarch64 93 | mode. 94 | 95 | Two issues were recently introduced into the Swift toolchain that you may need 96 | to work around: 97 | 98 | 1. If you have the `ANDROID_NDK_ROOT` environment variable set, as it is on 99 | github Actions runners, this SDK bundle won't work, so unset it. 100 | 101 | 2. There is a bug when trying to [cross-compile `Testing` tests with the open-source 102 | macOS toolchain alone](https://github.com/swiftlang/swift-package-manager/issues/8362)- 103 | it works fine with the linux toolchain- use the `-plugin-path` workaround listed 104 | there until it is fixed on macOS. 105 | 106 | ## Porting Swift packages to Android 107 | 108 | The most commonly needed change is to import the new Android overlay, so add 109 | these two lines for Android when calling Android's C APIs: 110 | ``` 111 | #if canImport(Android) 112 | import Android 113 | ``` 114 | You may also need to add some Android-specific support using `#if canImport(Android)`, 115 | for example, since FILE is an opaque struct since Android 7, you will [have to 116 | refer to any FILE pointers like this](https://github.com/swiftlang/swift-tools-support-core/pull/243/files): 117 | ``` 118 | #if canImport(Android) 119 | typealias FILEPointer = OpaquePointer 120 | ``` 121 | Those changes are all I had to make [to port swift-argument-parser to 122 | Android](https://github.com/apple/swift-argument-parser/pull/651/files). 123 | 124 | ## Building an Android app with Swift 125 | 126 | Some people have reported an issue with using previous libraries from this SDK in 127 | their Android app, that the Android toolchain strips `libdispatch.so` and 128 | complains that it has an `empty/missing DT_HASH/DT_GNU_HASH`. You can [work 129 | around this issue by adding the following to your `build.gradle`](https://github.com/finagolfin/swift-android-sdk/issues/67#issuecomment-1227460068): 130 | ``` 131 | packagingOptions { 132 | doNotStrip "*/arm64-v8a/libdispatch.so" 133 | doNotStrip "*/armeabi-v7a/libdispatch.so" 134 | doNotStrip "*/x86_64/libdispatch.so" 135 | } 136 | ``` 137 | 138 | ## Building an Android SDK from source 139 | 140 | Download the Swift 6.1.2 compiler as above and Android NDK 27c (only building 141 | the Android SDKs on linux works for now). Check out this repo and run 142 | `SWIFT_TAG=swift-6.1.2-RELEASE ANDROID_ARCH=aarch64 swift get-packages-and-swift-source.swift` 143 | to get some prebuilt Android libraries and the Swift source to build an AArch64 144 | SDK. If you pass in a different tag like `swift-DEVELOPMENT-SNAPSHOT-2025-04-03-a` 145 | for the latest Swift trunk snapshot and pass in the path to the corresponding 146 | prebuilt Swift toolchain to `build-script` below, you can build a Swift trunk 147 | SDK too, as seen on the CI. 148 | 149 | Next, apply two patches from this repo to the Swift source, which make 150 | modifications for NDK 27 and [the Foundation rewrite in Swift 6 that was merged 151 | last summer](https://www.swift.org/blog/foundation-preview-now-available/), and 152 | substitute a string for NDK 27: 153 | ``` 154 | git apply swift-android.patch swift-android-testing-release.patch 155 | perl -pi -e 's%r26%r27%' swift/stdlib/cmake/modules/AddSwiftStdlib.cmake 156 | ``` 157 | 158 | After making sure [needed build tools like python 3, CMake, and ninja](https://github.com/swiftlang/swift/blob/release/6.1/docs/HowToGuides/GettingStarted.md#linux) 159 | are installed, run the following `build-script` command with your local paths 160 | substituted instead: 161 | ``` 162 | ./swift/utils/build-script -RA --skip-build-cmark --build-llvm=0 --android 163 | --android-ndk /home/finagolfin/android-ndk-r27c/ --android-arch aarch64 --android-api-level 24 164 | --build-swift-tools=0 --native-swift-tools-path=/home/finagolfin/swift-6.1.2-RELEASE-ubuntu22.04/usr/bin/ 165 | --native-clang-tools-path=/home/finagolfin/swift-6.1.2-RELEASE-ubuntu22.04/usr/bin/ 166 | --host-cc=/usr/bin/clang-13 --host-cxx=/usr/bin/clang++-13 167 | --cross-compile-hosts=android-aarch64 --cross-compile-deps-path=/home/finagolfin/swift-release-android-aarch64-24-sdk 168 | --skip-local-build --xctest --swift-install-components='clang-resource-dir-symlink;license;stdlib;sdk-overlay' 169 | --install-swift --install-libdispatch --install-foundation --install-xctest 170 | --install-destdir=/home/finagolfin/swift-release-android-aarch64-24-sdk --skip-early-swiftsyntax 171 | --cross-compile-append-host-target-to-destdir=False --build-swift-static-stdlib -j9 172 | ``` 173 | Make sure you have an up-to-date CMake and not something old like 3.16. The 174 | `--host-cc` and `--host-cxx` flags are not needed if you have a `clang` and 175 | `clang++` in your `PATH` already, but I don't and they're unused for this build 176 | anyway but required by `build-script`. Substitute armv7 or x86_64 for aarch64 177 | into these commands to build SDKs for those architectures instead. 178 | 179 | Finally, copy `libc++_shared.so` from the NDK and modify the cross-compiled 180 | Swift corelibs to include `$ORIGIN` and other relative directories in their rpaths: 181 | ``` 182 | cp /home/yourname/android-ndk-r27c/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so swift-release-android-aarch64-24-sdk/usr/lib 183 | patchelf --set-rpath \$ORIGIN/../..:\$ORIGIN swift-release-android-aarch64-24-sdk/usr/lib/swift/android/lib*.so 184 | ``` 185 | 186 | Here is a description of what the above Swift script is doing: 187 | 188 | This prebuilt SDK was compiled against Android API 24, because the Swift 189 | Foundation libraries require some libraries like libcurl, that are pulled from the 190 | prebuilt library packages used by the Termux app, which are built against Android 191 | API 24. Specifically, it downloads the libandroid-execinfo, libandroid-spawn, 192 | libcurl, and libxml2 packages and their handful of dependencies from the [Termux 193 | package repository](https://packages.termux.dev/apt/termux-main/pool/main/). 194 | 195 | Each one is unpacked with `ar x libcurl_8.13.0_aarch64.deb; tar xf data.tar.xz` and 196 | the resulting files moved to a newly-created Swift release SDK directory: 197 | ``` 198 | mkdir swift-release-android-aarch64-24-sdk 199 | mv data/data/com.termux/files/usr swift-release-android-aarch64-24-sdk 200 | ``` 201 | It removes two config scripts in `usr/bin`, runs `patchelf` to remove the 202 | Termux rpath from all Termux shared libraries, removes some unused libraries 203 | and config files, and modifies the libraries to get rid of the versioning and 204 | symlinks, which can't always be used on Android: 205 | ``` 206 | rm swift-release-android-aarch64-24-sdk/usr/bin/*-config 207 | cd swift-release-android-aarch64-24-sdk/usr/lib 208 | 209 | patchelf --set-rpath \$ORIGIN libandroid-spawn.so libcurl.so libxml2.so 210 | 211 | # repeat the following for all versioned Termux libraries, as needed 212 | rm libxml2.so libxml2.so.2 213 | readelf -d libxml2.so.2.13.7 214 | mv libxml2.so.2.13.7 libxml2.so 215 | patchelf --set-soname libxml2.so libxml2.so 216 | patchelf --replace-needed libz.so.1 libz.so libxml2.so 217 | ``` 218 | The libcurl and libxml2 packages are [only needed for the FoundationNetworking 219 | and FoundationXML libraries respectively](https://github.com/swiftlang/swift-corelibs-foundation/blob/release/5.10/Docs/ReleaseNotes_Swift5.md), 220 | so you don't have to deploy them on the Android device if you don't use those 221 | extra Foundation libraries. 222 | 223 | This Swift SDK for Android could be built without using any prebuilt Termux 224 | packages, by compiling against a more recent Android API that doesn't need the 225 | `libandroid-spawn` backport, and by cross-compiling libcurl/libxml2 and their 226 | dependencies yourself or not using FoundationNetworking and FoundationXML. 227 | 228 | Finally, it gets [the 6.1.2 source](https://github.com/swiftlang/swift/releases/tag/swift-6.1.2-RELEASE) 229 | tarballs for eleven Swift repos and renames them to `llvm-project/`, `swift/`, 230 | `swift-syntax`, `swift-experimental-string-processing`, `swift-corelibs-libdispatch`, 231 | `swift-corelibs-foundation`, `swift-collections`, `swift-foundation`, 232 | `swift-foundation-icu`, `swift-corelibs-xctest`, and `swift-testing`, as required 233 | by the Swift `build-script`. 234 | -------------------------------------------------------------------------------- /get-packages-and-swift-source.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // The Termux packages to download and unpack 4 | // libxml2 needs liblzma and libiconv 5 | // libcurl needs zlib, libnghttp3, libnghttp2, libssh2, and openssl 6 | // Testing needs backtrace() from libandroid-execinfo 7 | var termuxPackages = ["libandroid-execinfo", "libandroid-spawn", "libandroid-spawn-static", "libcurl", "zlib", "libxml2", "libnghttp3", "libnghttp2", "libssh2", "openssl", "liblzma", "libiconv"] 8 | let termuxURL = "https://packages.termux.dev/apt/termux-main" 9 | 10 | var swiftRepos = ["llvm-project", "swift", "swift-experimental-string-processing", "swift-corelibs-libdispatch", 11 | "swift-corelibs-foundation", "swift-corelibs-xctest", "swift-syntax", "swift-collections", 12 | "swift-foundation", "swift-foundation-icu", "swift-testing"] 13 | 14 | let extraSwiftRepos = ["swift-llbuild", "swift-package-manager", "swift-driver", 15 | "swift-tools-support-core", "swift-argument-parser", "swift-crypto", 16 | "Yams", "indexstore-db", "sourcekit-lsp", "swift-system", "swift-lmdb", 17 | "swift-certificates", "swift-asn1", "swift-toolchain-sqlite"] 18 | let appleRepos = ["swift-argument-parser", "swift-crypto", "swift-system", "swift-collections", "swift-certificates", "swift-asn1"] 19 | let renameRepos = ["swift-llbuild" : "llbuild", "swift-package-manager" : "swiftpm", "Yams" : "yams"] 20 | var repoTags = ["swift-system" : "1.4.1", "swift-collections" : "1.1.3", "swift-asn1" : "1.0.0", 21 | "swift-certificates" : "1.0.1", "Yams" : "5.0.6", "swift-argument-parser" : "1.4.0", 22 | "swift-crypto" : "3.0.0", "swift-toolchain-sqlite" : "1.0.1"] 23 | if ProcessInfo.processInfo.environment["BUILD_SWIFT_PM"] != nil { 24 | swiftRepos += extraSwiftRepos 25 | termuxPackages += ["ncurses", "libsqlite"] 26 | } 27 | 28 | guard let SWIFT_TAG = ProcessInfo.processInfo.environment["SWIFT_TAG"] else { 29 | fatalError("You must specify a SWIFT_TAG environment variable.") 30 | } 31 | 32 | guard let ANDROID_ARCH = ProcessInfo.processInfo.environment["ANDROID_ARCH"] else { 33 | fatalError("You must specify an ANDROID_ARCH environment variable.") 34 | } 35 | 36 | var sdkDir = "", swiftVersion = "", swiftBranch = "", swiftSnapshotDate = "" 37 | 38 | let tagRange = NSRange(SWIFT_TAG.startIndex..., in: SWIFT_TAG) 39 | let tagExtract = try NSRegularExpression(pattern: "swift-([5-9]\\.[0-9]+)?\\.?[1-9]*-?([A-Z-]+)([0-9-]+[0-9])?") 40 | 41 | if tagExtract.numberOfMatches(in: SWIFT_TAG, range: tagRange) == 1 { 42 | let match = tagExtract.firstMatch(in: SWIFT_TAG, range: tagRange) 43 | if match!.range(at: 1).location != NSNotFound { 44 | swiftVersion = (SWIFT_TAG as NSString).substring(with: match!.range(at: 1)) 45 | } 46 | 47 | swiftBranch = (SWIFT_TAG as NSString).substring(with: match!.range(at: 2)) 48 | 49 | if match!.range(at: 3).location != NSNotFound { 50 | swiftSnapshotDate = (SWIFT_TAG as NSString).substring(with: match!.range(at: 3)) 51 | } 52 | } else { 53 | fatalError("Something went wrong with extracting data from the SWIFT_TAG environment variable: \(SWIFT_TAG)") 54 | } 55 | 56 | if swiftBranch == "RELEASE" { 57 | repoTags["swift-system"] = "1.3.0" 58 | sdkDir = "swift-release-android-\(ANDROID_ARCH)-24-sdk" 59 | } else { 60 | sdkDir = "swift-\(swiftVersion == "" ? "trunk" : "devel")-android-\(ANDROID_ARCH)-\(swiftSnapshotDate)-24-sdk" 61 | if ProcessInfo.processInfo.environment["BUILD_SWIFT_PM"] != nil { 62 | swiftRepos += ["swift-build"] 63 | } 64 | } 65 | 66 | // takes the name of a command-line executable and the arguments to pass to it 67 | func runCommand(_ name: String, with args: [String]) -> String { 68 | 69 | let command = Process() 70 | #if os(Android) 71 | command.executableURL = URL(fileURLWithPath: "/system/bin/which") 72 | #else 73 | command.executableURL = URL(fileURLWithPath: "/usr/bin/which") 74 | #endif 75 | 76 | command.arguments = [name] 77 | let output = Pipe() 78 | let error = Pipe() 79 | command.standardOutput = output 80 | command.standardError = error 81 | do { 82 | try command.run() 83 | } catch { 84 | fatalError("couldn't find \(name) with error: \(error)") 85 | } 86 | 87 | guard let result = String(data: output.fileHandleForReading.availableData, encoding: .utf8) else { 88 | fatalError("couldn't read `which` output") 89 | } 90 | guard let errorResult = String(data: error.fileHandleForReading.availableData, encoding: .ascii) else { 91 | fatalError("couldn't read `which` stderr") 92 | } 93 | 94 | if result != "" { 95 | let chompResult = result.replacingOccurrences(of: "\\s+$", with: "", options: .regularExpression) 96 | let command = Process() 97 | command.executableURL = URL(fileURLWithPath: chompResult) 98 | command.arguments = args 99 | let output = Pipe() 100 | let error = Pipe() 101 | command.standardOutput = output 102 | command.standardError = error 103 | do { 104 | print("running command: \(([command.executableURL!.path] + args).joined(separator: " "))") 105 | fflush(stdout) 106 | try command.run() 107 | } catch { 108 | fatalError("couldn't run \(name) \(args) with error: \(error)") 109 | } 110 | 111 | command.waitUntilExit() 112 | guard let commandResult = String(data: output.fileHandleForReading.availableData, encoding: .utf8) else { 113 | fatalError("couldn't read `\(name)` output") 114 | } 115 | guard let errorResult = String(data: error.fileHandleForReading.availableData, encoding: .ascii) else { 116 | fatalError("couldn't read `\(name)` stderr") 117 | } 118 | 119 | if command.terminationStatus == 0 { 120 | return commandResult.replacingOccurrences(of: "\\s+$", with: "", options: .regularExpression) 121 | } else { 122 | fatalError("couldn't run \(name) \(args) because of \(errorResult)") 123 | } 124 | } else { 125 | if errorResult != "" { 126 | fatalError("couldn't find \(name) because of \(errorResult)") 127 | } else { 128 | fatalError("couldn't find \(name), maybe a problem with `\(command.executableURL!.path)`?") 129 | } 130 | } 131 | } 132 | 133 | print("Checking if needed system utilities are installed...") 134 | print(runCommand("cmake", with: ["--version"])) 135 | print("ninja \(runCommand("ninja", with: ["--version"]))") 136 | 137 | #if os(macOS) 138 | print(runCommand("python3", with: ["--version"])) 139 | #else 140 | print(runCommand("python", with: ["--version"])) 141 | #endif 142 | print(runCommand("patchelf", with: ["--version"])) 143 | #if !os(macOS) 144 | // ar does not take a "--version" arg on macOS 145 | print(runCommand("ar", with: ["--version"])) 146 | #endif 147 | print(runCommand("tar", with: ["--version"])) 148 | print(runCommand("xz", with: ["--version"])) 149 | print(runCommand("curl", with: ["--version"])) 150 | print(runCommand("gzip", with: ["--version"])) 151 | 152 | #if os(macOS) 153 | extension String { 154 | func appendingPathComponent(_ path: String) -> String { 155 | (self as NSString).appendingPathComponent(path) 156 | } 157 | } 158 | #endif 159 | 160 | let fmd = FileManager.default 161 | let cwd = fmd.currentDirectoryPath 162 | let termuxArchive = cwd.appendingPathComponent("termux") 163 | if !fmd.fileExists(atPath: termuxArchive) { 164 | try fmd.createDirectory(atPath: termuxArchive, withIntermediateDirectories: false) 165 | } 166 | 167 | if !fmd.fileExists(atPath: termuxArchive.appendingPathComponent("Packages-\(ANDROID_ARCH)")) { 168 | _ = runCommand("curl", with: ["-o", "termux/Packages-\(ANDROID_ARCH)", 169 | "\(termuxURL)/dists/stable/main/binary-\(ANDROID_ARCH == "armv7" ? "arm" : ANDROID_ARCH)/Packages"]) 170 | } 171 | 172 | let packages = try String(contentsOfFile: termuxArchive.appendingPathComponent("Packages-\(ANDROID_ARCH)"), encoding: .utf8) 173 | 174 | for termuxPackage in termuxPackages { 175 | guard let packagePathRange = packages.range(of: "Filename: \\S+/\(termuxPackage)_\\S+", options: .regularExpression) else { 176 | fatalError("couldn't find \(termuxPackage) in Packages list") 177 | } 178 | let packagePath = packages[packagePathRange].dropFirst("Filename: ".count).description 179 | 180 | guard let packageNameRange = packagePath.range(of: "\(termuxPackage)_\\S+", options: .regularExpression) else { 181 | fatalError("couldn't extract \(termuxPackage) .deb package from package path") 182 | } 183 | let packageName = packagePath[packageNameRange] 184 | 185 | print("Checking for \(packageName)") 186 | if !fmd.fileExists(atPath: termuxArchive.appendingPathComponent(String(packageName))) { 187 | print("Downloading \(packageName)") 188 | _ = runCommand("curl", with: ["-f", "-o", "termux/\(packageName)", 189 | "\(termuxURL)/\(packagePath)"]) 190 | } 191 | 192 | if !fmd.fileExists(atPath: cwd.appendingPathComponent(sdkDir)) { 193 | print("Unpacking \(packageName)") 194 | #if os(macOS) 195 | _ = runCommand("tar", with: ["xf", "\(termuxArchive.appendingPathComponent(String(packageName)))"]) 196 | #else 197 | _ = runCommand("ar", with: ["x", "\(termuxArchive.appendingPathComponent(String(packageName)))"]) 198 | #endif 199 | _ = runCommand("tar", with: ["xf", "data.tar.xz"]) 200 | } 201 | } 202 | 203 | let sdkPath = cwd.appendingPathComponent(sdkDir) 204 | if !fmd.fileExists(atPath: sdkPath) { 205 | try fmd.removeItem(atPath: cwd.appendingPathComponent("data.tar.xz")) 206 | try fmd.removeItem(atPath: cwd.appendingPathComponent("control.tar.xz")) 207 | try fmd.removeItem(atPath: cwd.appendingPathComponent("debian-binary")) 208 | 209 | try fmd.createDirectory(atPath: sdkPath, withIntermediateDirectories: false) 210 | try fmd.moveItem(atPath: cwd.appendingPathComponent("data/data/com.termux/files/usr"), 211 | toPath: sdkPath.appendingPathComponent("usr")) 212 | 213 | try fmd.removeItem(atPath: cwd.appendingPathComponent("data")) 214 | try fmd.removeItem(atPath: sdkPath.appendingPathComponent("usr/bin/curl-config")) 215 | try fmd.removeItem(atPath: sdkPath.appendingPathComponent("usr/bin/xml2-config")) 216 | try fmd.removeItem(atPath: sdkPath.appendingPathComponent("usr/share/man")) 217 | try fmd.removeItem(atPath: sdkPath.appendingPathComponent("usr/lib/ossl-modules")) 218 | try fmd.removeItem(atPath: sdkPath.appendingPathComponent("usr/lib/engines-3")) 219 | try fmd.removeItem(atPath: sdkPath.appendingPathComponent("usr/etc")) 220 | } 221 | 222 | let libPath = sdkPath.appendingPathComponent("usr/lib") 223 | 224 | // flatten each of the shared object file links, since Android APKs do not support version-suffixed .so.x.y.z paths 225 | var renamedSharedObjects: [String: String] = [:] 226 | for soFile in try fmd.contentsOfDirectory(atPath: libPath) { 227 | let parts = soFile.split(separator: ".") 228 | guard let soIndex = parts.firstIndex(of: "so") else { continue } 229 | 230 | // e.g., for "libtinfo.so.6.5": soBase="libtinfo.so" soVersion="6.5" 231 | let soBase = parts[0...soIndex].joined(separator: ".") 232 | let soVersion = parts.dropFirst(soIndex + 1).joined(separator: ".") 233 | 234 | if !soVersion.isEmpty { 235 | renamedSharedObjects[soFile] = soBase // libtinfo.so.6.5->libtinfo.so 236 | } 237 | 238 | let soPath = libPath.appendingPathComponent(soFile) 239 | let soBasePath = libPath.appendingPathComponent(soBase) 240 | if (try? fmd.destinationOfSymbolicLink(atPath: soPath)) != nil { 241 | try fmd.removeItem(atPath: soPath) // clear links 242 | } else if !soVersion.isEmpty { 243 | // otherwise move the version-suffixed path to the un-versioned destination 244 | if (try? fmd.destinationOfSymbolicLink(atPath: soBasePath)) != nil { 245 | // need to remove the destination before we can move 246 | try fmd.removeItem(atPath: soBasePath) 247 | } 248 | try fmd.moveItem(atPath: soPath, toPath: soBasePath) 249 | } 250 | } 251 | 252 | if ProcessInfo.processInfo.environment["BUILD_SWIFT_PM"] != nil { 253 | // Rename ncurses for llbuild and add a symlink for SwiftPM 254 | try fmd.moveItem(atPath: libPath.appendingPathComponent("libncursesw.so"), toPath: libPath.appendingPathComponent("libcurses.so")) 255 | try fmd.createSymbolicLink(atPath: libPath.appendingPathComponent("libncurses.so"), withDestinationPath: "libcurses.so") 256 | } 257 | 258 | // update the rpath to be $ORIGIN, set the soname, and update all the "needed" sections for each of the peer libraries 259 | for soFile in try fmd.contentsOfDirectory(atPath: libPath).filter({ $0.hasSuffix(".so")} ) { 260 | let soPath = libPath.appendingPathComponent(soFile) 261 | // fix the soname (e.g., libtinfo.so.6.5->libtinfo.so) 262 | _ = runCommand("patchelf", with: ["--set-soname", soFile, soPath]) 263 | _ = runCommand("patchelf", with: ["--set-rpath", "$ORIGIN", soPath]) 264 | 265 | let needed = Set(runCommand("patchelf", with: ["--print-needed", soPath]).split(separator: "\n").map(\.description)) 266 | for needs in needed { 267 | if let unversioned = renamedSharedObjects[needs] { 268 | _ = runCommand("patchelf", with: ["--replace-needed", needs, unversioned, soPath]) 269 | } 270 | } 271 | } 272 | 273 | for repo in swiftRepos { 274 | print("Checking for \(repo) source") 275 | if !fmd.fileExists(atPath: cwd.appendingPathComponent(renameRepos[repo] ?? repo)) { 276 | print("Downloading and extracting \(repo) source") 277 | let tag = repoTags[repo] ?? SWIFT_TAG 278 | var repoOrg = "swiftlang" 279 | if repo == "Yams" { 280 | repoOrg = "jpsim" 281 | } else if appleRepos.contains(repo) { 282 | repoOrg = "apple" 283 | } 284 | _ = runCommand("curl", with: ["-f", "-L", "-O", 285 | "https://github.com/\(repoOrg)/\(repo)/archive/refs/tags/\(tag).tar.gz"]) 286 | _ = runCommand("tar", with: ["xf", "\(tag).tar.gz"]) 287 | try fmd.moveItem(atPath: cwd.appendingPathComponent("\(repo)-\(tag)"), 288 | toPath: cwd.appendingPathComponent(renameRepos[repo] ?? repo)) 289 | try fmd.removeItem(atPath: cwd.appendingPathComponent("\(tag).tar.gz")) 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /libc++-stdlib.h.patch: -------------------------------------------------------------------------------- 1 | --- a/usr/include/c++/v1/stdlib.h 2024-11-08 20:01:18 2 | +++ b/usr/include/c++/v1/stdlib.h 2024-11-08 20:03:38 3 | @@ -109,6 +109,7 @@ 4 | # endif 5 | 6 | // MSVCRT already has the correct prototype in if __cplusplus is defined 7 | +# if !defined(__swift__) 8 | # if !defined(_LIBCPP_MSVCRT) 9 | _LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI long abs(long __x) _NOEXCEPT { return __builtin_labs(__x); } 10 | _LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI long long abs(long long __x) _NOEXCEPT { 11 | @@ -127,6 +128,7 @@ 12 | _LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI long double abs(long double __lcpp_x) _NOEXCEPT { 13 | return __builtin_fabsl(__lcpp_x); 14 | } 15 | +# endif // !defined(__swift__) 16 | 17 | // div 18 | 19 | @@ -141,7 +143,7 @@ 20 | # endif 21 | 22 | // MSVCRT already has the correct prototype in if __cplusplus is defined 23 | -# if !defined(_LIBCPP_MSVCRT) 24 | +# if !defined(_LIBCPP_MSVCRT) && !defined(__swift__) 25 | inline _LIBCPP_HIDE_FROM_ABI ldiv_t div(long __x, long __y) _NOEXCEPT { return ::ldiv(__x, __y); } 26 | # if !(defined(__FreeBSD__) && !defined(__LONG_LONG_SUPPORTED)) 27 | inline _LIBCPP_HIDE_FROM_ABI lldiv_t div(long long __x, long long __y) _NOEXCEPT { return ::lldiv(__x, __y); } 28 | -------------------------------------------------------------------------------- /swift-android-ci-except-release.patch: -------------------------------------------------------------------------------- 1 | diff --git a/swift-build/Sources/SWBUtil/FSProxy.swift b/swift-build/Sources/SWBUtil/FSProxy.swift 2 | index b446d21..f88f3c3 100644 3 | --- a/swift-build/Sources/SWBUtil/FSProxy.swift 4 | +++ b/swift-build/Sources/SWBUtil/FSProxy.swift 5 | @@ -49,7 +49,7 @@ public struct FileInfo: Equatable, Sendable { 6 | #if os(Windows) 7 | return (statBuf.st_mode & UInt16(ucrt.S_IFREG)) != 0 8 | #else 9 | - return (statBuf.st_mode & S_IFREG) != 0 10 | + return (mode_t(statBuf.st_mode) & S_IFREG) != 0 11 | #endif 12 | } 13 | 14 | @@ -57,7 +57,7 @@ public struct FileInfo: Equatable, Sendable { 15 | #if os(Windows) 16 | return (statBuf.st_mode & UInt16(ucrt.S_IFDIR)) != 0 17 | #else 18 | - return (statBuf.st_mode & S_IFDIR) != 0 19 | + return (mode_t(statBuf.st_mode) & S_IFDIR) != 0 20 | #endif 21 | } 22 | 23 | @@ -65,7 +65,7 @@ public struct FileInfo: Equatable, Sendable { 24 | #if os(Windows) 25 | return (statBuf.st_mode & UInt16(S_IFLNK)) == S_IFLNK 26 | #else 27 | - return (statBuf.st_mode & S_IFMT) == S_IFLNK 28 | + return (mode_t(statBuf.st_mode) & S_IFMT) == S_IFLNK 29 | #endif 30 | } 31 | 32 | @@ -75,7 +75,7 @@ public struct FileInfo: Equatable, Sendable { 33 | // Don't use FileManager.isExecutableFile due to https://github.com/swiftlang/swift-foundation/issues/860 34 | return (statBuf.st_mode & UInt16(_S_IEXEC)) != 0 35 | #else 36 | - return (statBuf.st_mode & S_IXUSR) != 0 37 | + return (mode_t(statBuf.st_mode) & S_IXUSR) != 0 38 | #endif 39 | } 40 | 41 | @@ -1395,9 +1395,9 @@ public class PseudoFS: FSProxy, @unchecked Sendable { 42 | #else 43 | info.st_mtimespec = timespec(tv_sec: time_t(node.timestamp), tv_nsec: 0) 44 | #endif 45 | - info.st_size = off_t(contents.bytes.count) 46 | - info.st_dev = node.device 47 | - info.st_ino = node.inode 48 | + info.st_size = numericCast(contents.bytes.count) 49 | + info.st_dev = numericCast(node.device) 50 | + info.st_ino = numericCast(node.inode) 51 | return createFileInfo(info) 52 | case .directory(let dir): 53 | var info = stat() 54 | @@ -1405,12 +1405,12 @@ public class PseudoFS: FSProxy, @unchecked Sendable { 55 | info.st_mode = UInt16(ucrt.S_IFDIR) 56 | info.st_mtimespec = timespec(tv_sec: Int64(node.timestamp), tv_nsec: 0) 57 | #else 58 | - info.st_mode = S_IFDIR 59 | + info.st_mode = numericCast(S_IFDIR) 60 | info.st_mtimespec = timespec(tv_sec: time_t(node.timestamp), tv_nsec: 0) 61 | #endif 62 | - info.st_size = off_t(dir.contents.count) 63 | - info.st_dev = node.device 64 | - info.st_ino = node.inode 65 | + info.st_size = numericCast(dir.contents.count) 66 | + info.st_dev = numericCast(node.device) 67 | + info.st_ino = numericCast(node.inode) 68 | return createFileInfo(info) 69 | case .symlink(_): 70 | var info = stat() 71 | @@ -1418,12 +1418,12 @@ public class PseudoFS: FSProxy, @unchecked Sendable { 72 | info.st_mode = UInt16(S_IFLNK) 73 | info.st_mtimespec = timespec(tv_sec: Int64(node.timestamp), tv_nsec: 0) 74 | #else 75 | - info.st_mode = S_IFLNK 76 | + info.st_mode = numericCast(S_IFLNK) 77 | info.st_mtimespec = timespec(tv_sec: time_t(node.timestamp), tv_nsec: 0) 78 | #endif 79 | - info.st_size = off_t(0) 80 | - info.st_dev = node.device 81 | - info.st_ino = node.inode 82 | + info.st_size = numericCast(0) 83 | + info.st_dev = numericCast(node.device) 84 | + info.st_ino = numericCast(node.inode) 85 | return createFileInfo(info) 86 | } 87 | } 88 | diff --git a/swift-build/Sources/SWBUtil/Lock.swift b/swift-build/Sources/SWBUtil/Lock.swift 89 | index 2135ce6..fbff6f6 100644 90 | --- a/swift-build/Sources/SWBUtil/Lock.swift 91 | +++ b/swift-build/Sources/SWBUtil/Lock.swift 92 | @@ -14,6 +14,8 @@ 93 | public import os 94 | #elseif os(Windows) 95 | public import WinSDK 96 | +#elseif canImport(Android) 97 | +public import Android 98 | #else 99 | public import SWBLibc 100 | #endif 101 | diff --git a/swiftpm/Utilities/bootstrap b/swiftpm/Utilities/bootstrap 102 | index 156bf002a..d891da556 100755 103 | --- a/swiftpm/Utilities/bootstrap 104 | +++ b/swiftpm/Utilities/bootstrap 105 | @@ -941,6 +941,7 @@ def get_swiftpm_flags(args): 106 | build_flags += ["--arch", "x86_64", "--arch", "arm64"] 107 | elif cross_compile_hosts.startswith('android-'): 108 | build_flags.extend(["--destination", args.cross_compile_config]) 109 | + build_flags.extend(["-Xlinker", "-landroid-spawn"]) 110 | else: 111 | logging.error("cannot cross-compile for %s", cross_compile_hosts) 112 | raise SystemExit(1) 113 | -------------------------------------------------------------------------------- /swift-android-ci-release.patch: -------------------------------------------------------------------------------- 1 | diff --git a/swift-system/Sources/System/Internals/CInterop.swift b/swift-system/Sources/System/Internals/CInterop.swift 2 | index 13abc75..2ad551a 100644 3 | --- a/swift-system/Sources/System/Internals/CInterop.swift 4 | +++ b/swift-system/Sources/System/Internals/CInterop.swift 5 | @@ -25,6 +25,9 @@ import Glibc 6 | #elseif canImport(Musl) 7 | @_implementationOnly import CSystem 8 | import Musl 9 | +#elseif canImport(Bionic) 10 | +@_implementationOnly import CSystem 11 | +import Bionic 12 | #else 13 | #error("Unsupported Platform") 14 | #endif 15 | diff --git a/swift-system/Sources/System/Internals/Constants.swift b/swift-system/Sources/System/Internals/Constants.swift 16 | index 53e215f..27039de 100644 17 | --- a/swift-system/Sources/System/Internals/Constants.swift 18 | +++ b/swift-system/Sources/System/Internals/Constants.swift 19 | @@ -18,6 +18,8 @@ import CSystem 20 | import ucrt 21 | #elseif canImport(Glibc) 22 | import Glibc 23 | +#elseif canImport(Android) 24 | +import Android 25 | #elseif canImport(Musl) 26 | import CSystem 27 | import Musl 28 | diff --git a/swift-system/Sources/System/Internals/Exports.swift b/swift-system/Sources/System/Internals/Exports.swift 29 | index 5b08725..899be25 100644 30 | --- a/swift-system/Sources/System/Internals/Exports.swift 31 | +++ b/swift-system/Sources/System/Internals/Exports.swift 32 | @@ -23,6 +23,9 @@ import Glibc 33 | #elseif canImport(Musl) 34 | @_implementationOnly import CSystem 35 | import Musl 36 | +#elseif canImport(Android) 37 | +@_implementationOnly import CSystem 38 | +import Android 39 | #else 40 | #error("Unsupported Platform") 41 | #endif 42 | @@ -58,6 +61,11 @@ internal var system_errno: CInt { 43 | get { Musl.errno } 44 | set { Musl.errno = newValue } 45 | } 46 | +#elseif canImport(Android) 47 | +internal var system_errno: CInt { 48 | + get { Android.errno } 49 | + set { Android.errno = newValue } 50 | +} 51 | #endif 52 | 53 | // MARK: C stdlib decls 54 | diff --git a/swift-system/Sources/System/Internals/Syscalls.swift b/swift-system/Sources/System/Internals/Syscalls.swift 55 | index 555f63b..f0db35f 100644 56 | --- a/swift-system/Sources/System/Internals/Syscalls.swift 57 | +++ b/swift-system/Sources/System/Internals/Syscalls.swift 58 | @@ -15,6 +15,8 @@ import Glibc 59 | import Musl 60 | #elseif os(Windows) 61 | import ucrt 62 | +#elseif canImport(Android) 63 | +import Android 64 | #else 65 | #error("Unsupported Platform") 66 | #endif 67 | diff --git a/swiftpm/Utilities/bootstrap b/swiftpm/Utilities/bootstrap 68 | index 085056de..1ded1a90 100755 69 | --- a/swiftpm/Utilities/bootstrap 70 | +++ b/swiftpm/Utilities/bootstrap 71 | @@ -827,6 +827,7 @@ def get_swiftpm_flags(args): 72 | # Don't use GNU strerror_r on Android. 73 | if '-android' in args.build_target: 74 | build_flags.extend(["-Xswiftc", "-Xcc", "-Xswiftc", "-U_GNU_SOURCE"]) 75 | + build_flags.extend(["-Xlinker", "-landroid-spawn"]) 76 | 77 | cross_compile_hosts = args.cross_compile_hosts 78 | if cross_compile_hosts: 79 | diff --git a/yams/Sources/Yams/Representer.swift b/yams/Sources/Yams/Representer.swift 80 | index a749c52..b74ef8e 100644 81 | --- a/yams/Sources/Yams/Representer.swift 82 | +++ b/yams/Sources/Yams/Representer.swift 83 | @@ -14,6 +14,10 @@ private let cpow: (_: Double, _: Double) -> Double = Darwin.pow 84 | #elseif os(Windows) 85 | import ucrt 86 | private let cpow: (_: Double, _: Double) -> Double = ucrt.pow 87 | +#elseif canImport(Bionic) 88 | +import CoreFoundation 89 | +import Bionic 90 | +private let cpow: (_: Double, _: Double) -> Double = Bionic.pow 91 | #else 92 | import CoreFoundation 93 | import Glibc 94 | -------------------------------------------------------------------------------- /swift-android-ci.patch: -------------------------------------------------------------------------------- 1 | diff --git a/llbuild/CMakeLists.txt b/llbuild/CMakeLists.txt 2 | index 766e38e7..ad4d369f 100644 3 | --- a/llbuild/CMakeLists.txt 4 | +++ b/llbuild/CMakeLists.txt 5 | @@ -158,6 +158,7 @@ elseif(MSVC) 6 | else () 7 | add_compile_options( 8 | # Enable additional Clang warnings. 9 | + "$<$:-D_FORTIFY_SOURCE=0>" 10 | "$<$:-fno-rtti>" 11 | "$<$:-fno-exceptions>" 12 | "$<$:-Wbool-conversion>" 13 | diff --git a/llbuild/lib/llvm/Support/CMakeLists.txt b/llbuild/lib/llvm/Support/CMakeLists.txt 14 | index 9d5a714b..3f8f8c1d 100644 15 | --- a/llbuild/lib/llvm/Support/CMakeLists.txt 16 | +++ b/llbuild/lib/llvm/Support/CMakeLists.txt 17 | @@ -66,4 +66,15 @@ endif() 18 | 19 | if(${CMAKE_SYSTEM_NAME} MATCHES "Android|Darwin|Linux") 20 | target_link_libraries(llvmSupport PRIVATE curses) 21 | +if(${CMAKE_SYSTEM_NAME} MATCHES "Android") 22 | + target_link_libraries(llvmSupport PRIVATE android-spawn) 23 | + list(GET CMAKE_FIND_ROOT_PATH 0 SPAWN_DIR) 24 | + target_include_directories(llvmSupport 25 | + PUBLIC 26 | + ${SPAWN_DIR}/usr/include 27 | + ) 28 | + target_link_directories(llvmSupport PUBLIC 29 | + ${SPAWN_DIR}/usr/lib 30 | + ) 31 | +endif() 32 | endif() 33 | diff --git a/llbuild/unittests/CMakeLists.txt b/llbuild/unittests/CMakeLists.txt 34 | index 92a1ee38..52273afb 100644 35 | --- a/llbuild/unittests/CMakeLists.txt 36 | +++ b/llbuild/unittests/CMakeLists.txt 37 | @@ -6,4 +6,4 @@ function(add_llbuild_unittest test_dirname) 38 | add_subdirectory(CAPI) 39 | add_subdirectory(Core) 40 | add_subdirectory(BuildSystem) 41 | -add_subdirectory(Ninja) 42 | +#add_subdirectory(Ninja) 43 | diff --git a/swift-argument-parser/Sources/ArgumentParser/Utilities/Platform.swift b/swift-argument-parser/Sources/ArgumentParser/Utilities/Platform.swift 44 | index b7fa046..a94e3b8 100644 45 | --- a/swift-argument-parser/Sources/ArgumentParser/Utilities/Platform.swift 46 | +++ b/swift-argument-parser/Sources/ArgumentParser/Utilities/Platform.swift 47 | @@ -19,6 +19,8 @@ import Darwin 48 | import CRT 49 | #elseif canImport(WASILibc) 50 | import WASILibc 51 | +#elseif canImport(Android) 52 | +import Android 53 | #endif 54 | 55 | enum Platform {} 56 | @@ -88,6 +90,8 @@ extension Platform { 57 | ucrt._exit(code) 58 | #elseif canImport(WASILibc) 59 | WASILibc.exit(code) 60 | +#elseif canImport(Android) 61 | + Android.exit(code) 62 | #endif 63 | } 64 | } 65 | @@ -108,7 +112,7 @@ extension Platform { 66 | 67 | // MARK: Terminal size 68 | 69 | -#if canImport(Glibc) 70 | +#if canImport(Glibc) || canImport(Android) 71 | func ioctl(_ a: Int32, _ b: Int32, _ p: UnsafeMutableRawPointer) -> Int32 { 72 | ioctl(CInt(a), UInt(b), p) 73 | } 74 | diff --git a/swift-certificates/Sources/X509/Verifier/RFC5280/URIConstraints.swift b/swift-certificates/Sources/X509/Verifier/RFC5280/URIConstraints.swift 75 | --- a/swift-certificates/Sources/X509/Verifier/RFC5280/URIConstraints.swift 76 | +++ b/swift-certificates/Sources/X509/Verifier/RFC5280/URIConstraints.swift 77 | @@ -21,6 +21,9 @@ 78 | #elseif canImport(Musl) 79 | import Musl 80 | import CoreFoundation 81 | +#elseif canImport(Android) 82 | +import Android 83 | +import CoreFoundation 84 | #elseif canImport(Darwin) 85 | import Darwin 86 | #endif 87 | diff --git a/swift-crypto/Sources/Crypto/Key Derivation/HKDF.swift b/swift-crypto/Sources/Crypto/Key Derivation/HKDF.swift 88 | index 5f47c2f..4b5579e 100644 89 | --- a/swift-crypto/Sources/Crypto/Key Derivation/HKDF.swift 90 | +++ b/swift-crypto/Sources/Crypto/Key Derivation/HKDF.swift 91 | @@ -15,6 +15,9 @@ 92 | @_exported import CryptoKit 93 | #else 94 | import Foundation 95 | +#if canImport(Android) 96 | +import Android 97 | +#endif 98 | 99 | /// A standards-based implementation of an HMAC-based Key Derivation Function 100 | /// (HKDF). 101 | -------------------------------------------------------------------------------- /swift-android-devel.patch: -------------------------------------------------------------------------------- 1 | diff --git a/swift-corelibs-foundation/Sources/CoreFoundation/CFPlatform.c b/swift-corelibs-foundation/Sources/CoreFoundation/CFPlatform.c 2 | index 5769a3317e..916a7accbb 100644 3 | --- a/swift-corelibs-foundation/Sources/CoreFoundation/CFPlatform.c 4 | +++ b/swift-corelibs-foundation/Sources/CoreFoundation/CFPlatform.c 5 | @@ -1948,7 +1948,7 @@ CF_CROSS_PLATFORM_EXPORT void *_CFReallocf(void *ptr, size_t size) { 6 | #endif 7 | } 8 | 9 | -#if TARGET_OS_ANDROID 10 | +#if TARGET_OS_ANDROID && __ANDROID_API__ < 28 11 | 12 | #include 13 | #include 14 | @@ -2277,6 +2277,10 @@ CF_EXPORT int _CFPosixSpawnFileActionsAddClose(_CFPosixSpawnFileActionsRef file_ 15 | return _CFPosixSpawnFileActionsAddCloseImpl(file_actions, filedes); 16 | } 17 | 18 | +CF_EXPORT int _CFPosixSpawnFileActionsChdir(_CFPosixSpawnFileActionsRef file_actions, const char *path) { 19 | + return ENOSYS; 20 | +} 21 | + 22 | CF_EXPORT int _CFPosixSpawn(pid_t *_CF_RESTRICT pid, const char *_CF_RESTRICT path, _CFPosixSpawnFileActionsRef file_actions, _CFPosixSpawnAttrRef _Nullable _CF_RESTRICT attrp, char *_Nullable const argv[_Nullable _CF_RESTRICT], char *_Nullable const envp[_Nullable _CF_RESTRICT]) { 23 | _CFPosixSpawnInitialize(); 24 | return _CFPosixSpawnImpl(pid, path, file_actions, attrp, argv, envp); 25 | @@ -2317,12 +2317,13 @@ CF_EXPORT int _CFPosixSpawnFileActionsChdir(_CFPosixSpawnFileActionsRef file_act 26 | // Glibc versions prior to 2.29 don't support posix_spawn_file_actions_addchdir_np, impacting: 27 | // - Amazon Linux 2 (EoL mid-2025) 28 | return ENOSYS; 29 | - #elif defined(__OpenBSD__) || defined(__QNX__) 30 | + #elif defined(__OpenBSD__) || defined(__QNX__) || (defined(__ANDROID__) && __ANDROID_API__ < 34) 31 | // Currently missing as of: 32 | // - OpenBSD 7.5 (April 2024) 33 | // - QNX 8 (December 2023) 34 | + // - Android 13 35 | return ENOSYS; 36 | - #elif defined(__GLIBC__) || TARGET_OS_DARWIN || defined(__FreeBSD__) || (defined(__ANDROID__) && __ANDROID_API__ >= 34) || defined(__musl__) 37 | + #elif defined(__GLIBC__) || TARGET_OS_DARWIN || defined(__FreeBSD__) || defined(__ANDROID__) || defined(__musl__) 38 | // Pre-standard posix_spawn_file_actions_addchdir_np version available in: 39 | // - Solaris 11.3 (October 2015) 40 | // - Glibc 2.29 (February 2019) 41 | -------------------------------------------------------------------------------- /swift-android-testing-except-release.patch: -------------------------------------------------------------------------------- 1 | diff --git a/swift-corelibs-xctest/cmake/modules/PlatformInfo.cmake b/swift-corelibs-xctest/cmake/modules/PlatformInfo.cmake 2 | index 468dc61..a90ae3d 100644 3 | --- a/swift-corelibs-xctest/cmake/modules/PlatformInfo.cmake 4 | +++ b/swift-corelibs-xctest/cmake/modules/PlatformInfo.cmake 5 | @@ -2,6 +2,10 @@ 6 | set(print_target_info_invocation "${CMAKE_Swift_COMPILER}" -print-target-info) 7 | if(CMAKE_Swift_COMPILER_TARGET) 8 | list(APPEND print_target_info_invocation -target ${CMAKE_Swift_COMPILER_TARGET}) 9 | +else() 10 | + set(arg_list ${CMAKE_Swift_FLAGS}) 11 | + separate_arguments(arg_list) 12 | + list(APPEND print_target_info_invocation ${arg_list}) 13 | endif() 14 | execute_process(COMMAND ${print_target_info_invocation} OUTPUT_VARIABLE target_info_json) 15 | message(CONFIGURE_LOG "Swift Target Info: ${print_target_info_invocation}\n" 16 | diff --git a/swift-testing/cmake/modules/PlatformInfo.cmake b/swift-testing/cmake/modules/PlatformInfo.cmake 17 | index 94c60ef..ab8a491 100644 18 | --- a/swift-testing/cmake/modules/PlatformInfo.cmake 19 | +++ b/swift-testing/cmake/modules/PlatformInfo.cmake 20 | @@ -9,6 +9,10 @@ 21 | set(print_target_info_invocation "${CMAKE_Swift_COMPILER}" -print-target-info) 22 | if(CMAKE_Swift_COMPILER_TARGET) 23 | list(APPEND print_target_info_invocation -target ${CMAKE_Swift_COMPILER_TARGET}) 24 | +else() 25 | + set(arg_list ${CMAKE_Swift_FLAGS}) 26 | + separate_arguments(arg_list) 27 | + list(APPEND print_target_info_invocation ${arg_list}) 28 | endif() 29 | execute_process(COMMAND ${print_target_info_invocation} OUTPUT_VARIABLE target_info_json) 30 | message(CONFIGURE_LOG "Swift Target Info: ${print_target_info_invocation}\n" 31 | -------------------------------------------------------------------------------- /swift-android-testing-release.patch: -------------------------------------------------------------------------------- 1 | diff --git a/swift/utils/swift_build_support/swift_build_support/products/swift_testing.py b/swift/utils/swift_build_support/swift_build_support/products/swift_testing.py 2 | index b6bfa5760ef..324d1a77eea 100644 3 | --- a/swift/utils/swift_build_support/swift_build_support/products/swift_testing.py 4 | +++ b/swift/utils/swift_build_support/swift_build_support/products/swift_testing.py 5 | @@ -51,7 +51,7 @@ class SwiftTesting(product.Product): 6 | return False 7 | 8 | def should_install(self, host_target): 9 | - return self.args.install_swift_testing_macros 10 | + return self.args.install_swift_testing 11 | 12 | def _cmake_product(self, host_target): 13 | build_root = os.path.dirname(self.build_dir) 14 | diff --git a/swift-corelibs-foundation/Sources/CoreFoundation/CFPlatform.c b/swift-corelibs-foundation/Sources/CoreFoundation/CFPlatform.c 15 | index 90f4aa78..0429425b 100644 16 | --- a/swift-corelibs-foundation/Sources/CoreFoundation/CFPlatform.c 17 | +++ b/swift-corelibs-foundation/Sources/CoreFoundation/CFPlatform.c 18 | @@ -1948,7 +1948,7 @@ CF_CROSS_PLATFORM_EXPORT void *_CFReallocf(void *ptr, size_t size) { 19 | #endif 20 | } 21 | 22 | -#if TARGET_OS_ANDROID 23 | +#if TARGET_OS_ANDROID && __ANDROID_API__ < 28 24 | 25 | #include 26 | #include 27 | @@ -2277,6 +2277,10 @@ CF_EXPORT int _CFPosixSpawnFileActionsAddClose(_CFPosixSpawnFileActionsRef file_ 28 | return _CFPosixSpawnFileActionsAddCloseImpl(file_actions, filedes); 29 | } 30 | 31 | +CF_EXPORT int _CFPosixSpawnFileActionsChdir(_CFPosixSpawnFileActionsRef file_actions, const char *path) { 32 | + return ENOSYS; 33 | +} 34 | + 35 | CF_EXPORT int _CFPosixSpawn(pid_t *_CF_RESTRICT pid, const char *_CF_RESTRICT path, _CFPosixSpawnFileActionsRef file_actions, _CFPosixSpawnAttrRef _Nullable _CF_RESTRICT attrp, char *_Nullable const argv[_Nullable _CF_RESTRICT], char *_Nullable const envp[_Nullable _CF_RESTRICT]) { 36 | _CFPosixSpawnInitialize(); 37 | return _CFPosixSpawnImpl(pid, path, file_actions, attrp, argv, envp); 38 | @@ -2279,7 +2279,7 @@ CF_EXPORT int _CFPosixSpawnFileActionsAddClose(_CFPosixSpawnFileActionsRef file_ 39 | } 40 | 41 | CF_EXPORT int _CFPosixSpawnFileActionsChdir(_CFPosixSpawnFileActionsRef file_actions, const char *path) { 42 | - #if defined(__GLIBC__) && !__GLIBC_PREREQ(2, 29) 43 | + #if defined(__GLIBC__) && !__GLIBC_PREREQ(2, 29) || (defined(__ANDROID__) && __ANDROID_API__ < 34) 44 | // Glibc versions prior to 2.29 don't support posix_spawn_file_actions_addchdir_np, impacting: 45 | // - Amazon Linux 2 (EoL mid-2025) 46 | return ENOSYS; 47 | diff --git a/swift-testing/cmake/modules/SwiftModuleInstallation.cmake b/swift-testing/cmake/modules/SwiftModuleInstallation.cmake 48 | index 1553725..d9f9e5b 100644 49 | --- a/swift-testing/cmake/modules/SwiftModuleInstallation.cmake 50 | +++ b/swift-testing/cmake/modules/SwiftModuleInstallation.cmake 51 | @@ -75,6 +75,10 @@ function(_swift_testing_install_target module) 52 | set(module_triple_command "${CMAKE_Swift_COMPILER}" -print-target-info) 53 | if(CMAKE_Swift_COMPILER_TARGET) 54 | list(APPEND module_triple_command -target ${CMAKE_Swift_COMPILER_TARGET}) 55 | + else() 56 | + set(arg_list ${CMAKE_Swift_FLAGS}) 57 | + separate_arguments(arg_list) 58 | + list(APPEND module_triple_command ${arg_list}) 59 | endif() 60 | execute_process(COMMAND ${module_triple_command} OUTPUT_VARIABLE target_info_json) 61 | string(JSON module_triple GET "${target_info_json}" "target" "moduleTriple") 62 | -------------------------------------------------------------------------------- /swift-android-trunk-libdispatch.patch: -------------------------------------------------------------------------------- 1 | diff --git a/swift-corelibs-libdispatch/cmake/modules/SwiftSupport.cmake b/swift-corelibs-libdispatch/cmake/modules/SwiftSupport.cmake 2 | index 3da519e..e2dd8ed 100644 3 | --- a/swift-corelibs-libdispatch/cmake/modules/SwiftSupport.cmake 4 | +++ b/swift-corelibs-libdispatch/cmake/modules/SwiftSupport.cmake 5 | @@ -4,6 +4,10 @@ if(NOT dispatch_MODULE_TRIPLE) 6 | set(module_triple_command "${CMAKE_Swift_COMPILER}" -print-target-info) 7 | if(CMAKE_Swift_COMPILER_TARGET) 8 | list(APPEND module_triple_command -target ${CMAKE_Swift_COMPILER_TARGET}) 9 | + else() 10 | + set(arg_list ${CMAKE_Swift_FLAGS}) 11 | + separate_arguments(arg_list) 12 | + list(APPEND module_triple_command ${arg_list}) 13 | endif() 14 | execute_process(COMMAND ${module_triple_command} OUTPUT_VARIABLE target_info_json) 15 | 16 | diff --git a/swift-corelibs-libdispatch/src/swift/CMakeLists.txt b/swift-corelibs-libdispatch/src/swift/CMakeLists.txt 17 | index 38bef37..d0ddf98 100644 18 | --- a/swift-corelibs-libdispatch/src/swift/CMakeLists.txt 19 | +++ b/swift-corelibs-libdispatch/src/swift/CMakeLists.txt 20 | @@ -15,6 +15,7 @@ add_library(swiftDispatch 21 | Source.swift 22 | Time.swift 23 | Wrapper.swift) 24 | +set(CMAKE_SHARED_LINKER_FLAGS "") 25 | target_compile_options(swiftDispatch PRIVATE 26 | "SHELL:-Xcc -fblocks" 27 | "SHELL:-Xcc -fmodule-map-file=${PROJECT_SOURCE_DIR}/dispatch/module.modulemap" 28 | -------------------------------------------------------------------------------- /swift-android.patch: -------------------------------------------------------------------------------- 1 | diff --git a/swift/utils/build-script-impl b/swift/utils/build-script-impl 2 | index 16e05052609..7ab8cebfab8 100755 3 | --- a/swift/utils/build-script-impl 4 | +++ b/swift/utils/build-script-impl 5 | @@ -2622,6 +2622,7 @@ for host in "${ALL_HOSTS[@]}"; do 6 | echo "Cleaning the libdispatch build directory" 7 | call rm -rf "${LIBDISPATCH_BUILD_DIR}" 8 | fi 9 | + call ln -sf "${SWIFT_BUILD_PATH}/lib/swift" "${ANDROID_NDK}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib" 10 | 11 | cmake_options=( 12 | -DENABLE_SWIFT=YES 13 | diff --git a/swift/utils/swift_build_support/swift_build_support/products/swift_testing.py b/swift/utils/swift_build_support/swift_build_support/products/swift_testing.py 14 | index 324d1a77eea..e88601a8701 100644 15 | --- a/swift/utils/swift_build_support/swift_build_support/products/swift_testing.py 16 | +++ b/swift/utils/swift_build_support/swift_build_support/products/swift_testing.py 17 | @@ -13,6 +13,9 @@ 18 | import os 19 | 20 | from build_swift.build_swift.versions import Version 21 | +from ..host_specific_configuration \ 22 | + import HostSpecificConfiguration 23 | +from ..targets import StdlibDeploymentTarget 24 | 25 | from . import cmake_product 26 | from . import product 27 | @@ -115,6 +117,22 @@ class SwiftTestingCMakeShim(cmake_product.CMakeProduct): 28 | # FIXME: If we build macros for the builder, specify the path. 29 | self.cmake_options.define('SwiftTesting_MACRO', 'NO') 30 | 31 | + if host_target.startswith('android') and self.is_cross_compile_target(host_target): 32 | + host_config = HostSpecificConfiguration(host_target, self.args) 33 | + self.cmake_options.extend(host_config.cmake_options) 34 | + flags = '-target %s-unknown-linux-android%s ' % (self.args.android_arch, 35 | + self.args.android_api_level) 36 | + 37 | + flags += '-resource-dir %s/lib/swift ' % ( 38 | + self.host_install_destdir(host_target) + self.args.install_prefix) 39 | + 40 | + ndk_path = StdlibDeploymentTarget.get_target_for_name(host_target).platform.ndk_toolchain_path(self.args) 41 | + flags += '-sdk %s/sysroot ' % (ndk_path) 42 | + flags += '-tools-directory %s/bin' % (ndk_path) 43 | + self.cmake_options.define('CMAKE_Swift_FLAGS', flags) 44 | + self.cmake_options.define('CMAKE_CXX_COMPILER_WORKS', 'True') 45 | + self.cmake_options.define('CMAKE_FIND_ROOT_PATH', self.args.cross_compile_deps_path) 46 | + 47 | self.generate_toolchain_file_for_darwin_or_linux( 48 | host_target, override_macos_deployment_version=override_deployment_version) 49 | self.build_with_cmake([], self.args.build_variant, [], 50 | diff --git a/swift-corelibs-foundation/CMakeLists.txt b/swift-corelibs-foundation/CMakeLists.txt 51 | index 7f290d16..95366592 100644 52 | --- a/swift-corelibs-foundation/CMakeLists.txt 53 | +++ b/swift-corelibs-foundation/CMakeLists.txt 54 | @@ -51,6 +51,7 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL Windows) 55 | endif() 56 | endif() 57 | 58 | +set(CMAKE_SHARED_LINKER_FLAGS "") 59 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 60 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 61 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 62 | diff --git a/swift-corelibs-foundation/Sources/Foundation/CMakeLists.txt b/swift-corelibs-foundation/Sources/Foundation/CMakeLists.txt 63 | index 016bf294..5c42986a 100644 64 | --- a/swift-corelibs-foundation/Sources/Foundation/CMakeLists.txt 65 | +++ b/swift-corelibs-foundation/Sources/Foundation/CMakeLists.txt 66 | @@ -162,6 +162,10 @@ if(NOT BUILD_SHARED_LIBS) 67 | "SHELL:$<$:-Xfrontend -public-autolink-library -Xfrontend _FoundationICU>") 68 | target_compile_options(Foundation PRIVATE 69 | "SHELL:$<$:-Xfrontend -public-autolink-library -Xfrontend swiftSynchronization>") 70 | + if(${CMAKE_SYSTEM_NAME} STREQUAL Android) 71 | + target_compile_options(Foundation PRIVATE 72 | + "SHELL:$<$:-Xfrontend -public-autolink-library -Xfrontend android-spawn>") 73 | + endif() 74 | endif() 75 | 76 | set_target_properties(Foundation PROPERTIES 77 | @@ -174,6 +174,12 @@ 78 | target_link_libraries(Foundation PUBLIC 79 | swiftDispatch) 80 | endif() 81 | + if(${CMAKE_SYSTEM_NAME} STREQUAL Android) 82 | + target_link_libraries(Foundation PRIVATE android-spawn) 83 | + list(GET CMAKE_FIND_ROOT_PATH 0 SPAWN_DIR) 84 | + target_include_directories(Foundation PUBLIC ${SPAWN_DIR}/usr/include) 85 | + target_link_directories(Foundation PUBLIC ${SPAWN_DIR}/usr/lib) 86 | + endif() 87 | 88 | if(LINKER_SUPPORTS_BUILD_ID) 89 | target_link_options(Foundation PRIVATE "LINKER:--build-id=sha1") 90 | diff --git a/swift-corelibs-foundation/Sources/Foundation/Process.swift b/swift-corelibs-foundation/Sources/Foundation/Process.swift 91 | index 758dd1df..02970992 100644 92 | --- a/swift-corelibs-foundation/Sources/Foundation/Process.swift 93 | +++ b/swift-corelibs-foundation/Sources/Foundation/Process.swift 94 | @@ -944,7 +944,7 @@ open class Process: NSObject, @unchecked Sendable { 95 | var spawnAttrs: posix_spawnattr_t = posix_spawnattr_t() 96 | #endif 97 | try _throwIfPosixError(posix_spawnattr_init(&spawnAttrs)) 98 | -#if os(Android) 99 | +#if os(Windows) 100 | guard var spawnAttrs else { 101 | throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno), 102 | userInfo: [NSURLErrorKey:self.executableURL!]) 103 | diff --git a/swift-foundation/cmake/modules/SwiftFoundationSwiftSupport.cmake b/swift-foundation/cmake/modules/SwiftFoundationSwiftSupport.cmake 104 | index cbdfc2a..bb4121d 100644 105 | --- a/swift-foundation/cmake/modules/SwiftFoundationSwiftSupport.cmake 106 | +++ b/swift-foundation/cmake/modules/SwiftFoundationSwiftSupport.cmake 107 | @@ -37,6 +37,10 @@ function(_swift_foundation_install_target module) 108 | set(module_triple_command "${CMAKE_Swift_COMPILER}" -print-target-info) 109 | if(CMAKE_Swift_COMPILER_TARGET) 110 | list(APPEND module_triple_command -target ${CMAKE_Swift_COMPILER_TARGET}) 111 | + else() 112 | + set(arg_list ${CMAKE_Swift_FLAGS}) 113 | + separate_arguments(arg_list) 114 | + list(APPEND module_triple_command ${arg_list}) 115 | endif() 116 | execute_process(COMMAND ${module_triple_command} OUTPUT_VARIABLE target_info_json) 117 | string(JSON module_triple GET "${target_info_json}" "target" "moduleTriple") 118 | diff --git a/swift-testing/CMakeLists.txt b/swift-testing/CMakeLists.txt 119 | index 1be9a4b..bd7b1bd 100644 120 | --- a/swift-testing/CMakeLists.txt 121 | +++ b/swift-testing/CMakeLists.txt 122 | @@ -28,6 +28,7 @@ list(APPEND CMAKE_MODULE_PATH 123 | ${PROJECT_SOURCE_DIR}/cmake/modules 124 | ${PROJECT_SOURCE_DIR}/cmake/modules/shared) 125 | 126 | +set(CMAKE_SHARED_LINKER_FLAGS "") 127 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 128 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 129 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 130 | diff --git a/swift-testing/Sources/Testing/CMakeLists.txt b/swift-testing/Sources/Testing/CMakeLists.tx 131 | index e40cb1b..ff2f920 100644 132 | --- a/swift-testing/Sources/Testing/CMakeLists.txt 133 | +++ b/swift-testing/Sources/Testing/CMakeLists.txt 134 | @@ -110,7 +110,10 @@ target_link_libraries(Testing PRIVATE 135 | if(NOT APPLE) 136 | if(NOT CMAKE_SYSTEM_NAME STREQUAL WASI) 137 | target_link_libraries(Testing PUBLIC 138 | - dispatch) 139 | + dispatch android-execinfo) 140 | + list(GET CMAKE_FIND_ROOT_PATH 0 BT_DIR) 141 | + target_include_directories(Testing PUBLIC ${BT_DIR}/usr/include) 142 | + target_link_directories(Testing PUBLIC ${BT_DIR}/usr/lib) 143 | endif() 144 | target_link_libraries(Testing PUBLIC 145 | Foundation) 146 | diff --git a/swift-testing/cmake/modules/TargetTriple.cmake b/swift-testing/cmake/modules/TargetTriple.cmake 147 | index e087cc4..02f3a95 100644 148 | --- a/swift-testing/cmake/modules/TargetTriple.cmake 149 | +++ b/swift-testing/cmake/modules/TargetTriple.cmake 150 | @@ -10,6 +10,10 @@ 151 | set(SWT_TARGET_INFO_COMMAND "${CMAKE_Swift_COMPILER}" -print-target-info) 152 | if(CMAKE_Swift_COMPILER_TARGET) 153 | list(APPEND SWT_TARGET_INFO_COMMAND -target ${CMAKE_Swift_COMPILER_TARGET}) 154 | +else() 155 | + set(arg_list ${CMAKE_Swift_FLAGS}) 156 | + separate_arguments(arg_list) 157 | + list(APPEND SWT_TARGET_INFO_COMMAND ${arg_list}) 158 | endif() 159 | execute_process(COMMAND ${SWT_TARGET_INFO_COMMAND} OUTPUT_VARIABLE SWT_TARGET_INFO_JSON) 160 | string(JSON SWT_TARGET_TRIPLE GET "${SWT_TARGET_INFO_JSON}" "target" "unversionedTriple") 161 | -------------------------------------------------------------------------------- /swift-nio-disable-ecn-tests.patch: -------------------------------------------------------------------------------- 1 | # The ECN tests only fail for older Android APIs. 2 | diff --git a/Tests/NIOPosixTests/DatagramChannelTests.swift b/Tests/NIOPosixTests/DatagramChannelTests.swift 3 | index 8cfe8de4..c36fb838 100644 4 | --- a/Tests/NIOPosixTests/DatagramChannelTests.swift 5 | +++ b/Tests/NIOPosixTests/DatagramChannelTests.swift 6 | @@ -755,7 +755,7 @@ class DatagramChannelTests: XCTestCase { 7 | } 8 | 9 | func testEcnSendReceiveIPV4() { 10 | - testEcnAndPacketInfoReceive(address: "127.0.0.1", vectorRead: false, vectorSend: false) 11 | + //testEcnAndPacketInfoReceive(address: "127.0.0.1", vectorRead: false, vectorSend: false) 12 | } 13 | 14 | func testEcnSendReceiveIPV6() { 15 | @@ -766,7 +766,7 @@ class DatagramChannelTests: XCTestCase { 16 | } 17 | 18 | func testEcnSendReceiveIPV4VectorRead() { 19 | - testEcnAndPacketInfoReceive(address: "127.0.0.1", vectorRead: true, vectorSend: false) 20 | + //testEcnAndPacketInfoReceive(address: "127.0.0.1", vectorRead: true, vectorSend: false) 21 | } 22 | 23 | func testEcnSendReceiveIPV6VectorRead() { 24 | @@ -777,7 +777,7 @@ class DatagramChannelTests: XCTestCase { 25 | } 26 | 27 | func testEcnSendReceiveIPV4VectorReadVectorWrite() { 28 | - testEcnAndPacketInfoReceive(address: "127.0.0.1", vectorRead: true, vectorSend: true) 29 | + //testEcnAndPacketInfoReceive(address: "127.0.0.1", vectorRead: true, vectorSend: true) 30 | } 31 | 32 | func testEcnSendReceiveIPV6VectorReadVectorWrite() { 33 | @@ -887,7 +887,7 @@ class DatagramChannelTests: XCTestCase { 34 | } 35 | 36 | func testSimpleReceivePacketInfoIPV4() throws { 37 | - try testSimpleReceivePacketInfo(address: "127.0.0.1") 38 | + //try testSimpleReceivePacketInfo(address: "127.0.0.1") 39 | } 40 | 41 | func testSimpleReceivePacketInfoIPV6() throws { 42 | @@ -898,7 +898,7 @@ class DatagramChannelTests: XCTestCase { 43 | } 44 | 45 | func testReceiveEcnAndPacketInfoIPV4() { 46 | - testEcnAndPacketInfoReceive(address: "127.0.0.1", vectorRead: false, vectorSend: false, receivePacketInfo: true) 47 | + //testEcnAndPacketInfoReceive(address: "127.0.0.1", vectorRead: false, vectorSend: false, receivePacketInfo: true) 48 | } 49 | 50 | func testReceiveEcnAndPacketInfoIPV6() { 51 | @@ -909,7 +909,7 @@ class DatagramChannelTests: XCTestCase { 52 | } 53 | 54 | func testReceiveEcnAndPacketInfoIPV4VectorRead() { 55 | - testEcnAndPacketInfoReceive(address: "127.0.0.1", vectorRead: true, vectorSend: false, receivePacketInfo: true) 56 | + //testEcnAndPacketInfoReceive(address: "127.0.0.1", vectorRead: true, vectorSend: false, receivePacketInfo: true) 57 | } 58 | 59 | func testReceiveEcnAndPacketInfoIPV6VectorRead() { 60 | @@ -920,7 +920,7 @@ class DatagramChannelTests: XCTestCase { 61 | } 62 | 63 | func testReceiveEcnAndPacketInfoIPV4VectorReadVectorWrite() { 64 | - testEcnAndPacketInfoReceive(address: "127.0.0.1", vectorRead: true, vectorSend: true, receivePacketInfo: true) 65 | + //testEcnAndPacketInfoReceive(address: "127.0.0.1", vectorRead: true, vectorSend: true, receivePacketInfo: true) 66 | } 67 | 68 | func testReceiveEcnAndPacketInfoIPV6VectorReadVectorWrite() { 69 | -------------------------------------------------------------------------------- /swift-nio-filesystem.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Sources/NIOFileSystem/Internal/SystemFileHandle.swift b/Sources/NIOFileSystem/Internal/SystemFileHandle.swift 2 | index 3dc51872..49aeeeca 100644 3 | --- a/Sources/NIOFileSystem/Internal/SystemFileHandle.swift 4 | +++ b/Sources/NIOFileSystem/Internal/SystemFileHandle.swift 5 | @@ -1113,7 +1113,7 @@ extension SystemFileHandle { 6 | let truncate = options.contains(.truncate) 7 | let delayMaterialization = transactional && isWritable && (exclusiveCreate || truncate) 8 | 9 | - if delayMaterialization { 10 | + if false { 11 | // When opening in this mode we can more "atomically" create the file, that is, by not 12 | // leaving the user with a half written file should e.g. the system crash or throw an 13 | // error while writing. On non-Android Linux we do this by opening the directory for 14 | diff --git a/Tests/NIOFileSystemIntegrationTests/BufferedReaderTests.swift b/Tests/NIOFileSystemIntegrationTests/BufferedReaderTests.swift 15 | index 8404e159..151fccc1 100644 16 | --- a/Tests/NIOFileSystemIntegrationTests/BufferedReaderTests.swift 17 | +++ b/Tests/NIOFileSystemIntegrationTests/BufferedReaderTests.swift 18 | @@ -21,7 +21,7 @@ import XCTest 19 | final class BufferedReaderTests: XCTestCase { 20 | func testBufferedReaderSizeAndCapacity() async throws { 21 | let fs = FileSystem.shared 22 | - try await fs.withFileHandle(forReadingAt: #filePath) { handle in 23 | + try await fs.withFileHandle(forReadingAt: "/data/data/com.termux/pack/FileHandleTests.swift") { handle in 24 | var reader = handle.bufferedReader(capacity: .bytes(128 * 1024)) 25 | XCTAssertEqual(reader.count, 0) 26 | XCTAssertEqual(reader.capacity, 128 * 1024) 27 | @@ -88,7 +88,7 @@ final class BufferedReaderTests: XCTestCase { 28 | 29 | func testBufferedReaderReadingShort() async throws { 30 | let fs = FileSystem.shared 31 | - try await fs.withFileHandle(forReadingAt: #filePath) { handle in 32 | + try await fs.withFileHandle(forReadingAt: "/data/data/com.termux/pack/FileHandleTests.swift") { handle in 33 | var reader = handle.bufferedReader(capacity: .bytes(128)) 34 | var buffer = ByteBuffer() 35 | while true { 36 | diff --git a/Tests/NIOFileSystemIntegrationTests/FileHandleTests.swift b/Tests/NIOFileSystemIntegrationTests/FileHandleTests.swift 37 | index c18e2c8e..65872fb9 100644 38 | --- a/Tests/NIOFileSystemIntegrationTests/FileHandleTests.swift 39 | +++ b/Tests/NIOFileSystemIntegrationTests/FileHandleTests.swift 40 | @@ -20,9 +20,8 @@ import XCTest 41 | 42 | @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) 43 | final class FileHandleTests: XCTestCase { 44 | - static let thisFile = FilePath(#filePath) 45 | - static let testData = FilePath(#filePath) 46 | - .removingLastComponent() // FileHandleTests.swift 47 | + static let thisFile = FilePath("/data/data/com.termux/pack/FileHandleTests.swift") 48 | + static let testData = FilePath("/data/data/com.termux/pack/") 49 | .appending("Test Data") 50 | .lexicallyNormalized() 51 | 52 | @@ -995,7 +994,7 @@ final class FileHandleTests: XCTestCase { 53 | } 54 | } 55 | 56 | - func testOpenExclusiveCreateForFileWhichExistsWithoutOTMPFILE() async throws { 57 | + /*func testOpenExclusiveCreateForFileWhichExistsWithoutOTMPFILE() async throws { 58 | // Takes the path where 'O_TMPFILE' doesn't exist, so materializing the file is done via 59 | // creating a temporary file and then renaming it using 'renamex_np'/'renameat2' (Darwin/Linux). 60 | let temporaryDirectory = try await FileSystem.shared.temporaryDirectory 61 | @@ -1013,7 +1012,7 @@ final class FileHandleTests: XCTestCase { 62 | try await handle.close() 63 | let info = try await FileSystem.shared.info(forFileAt: path) 64 | XCTAssertNotNil(info) 65 | - } 66 | + }*/ 67 | 68 | func testOpenExclusiveCreateForFileWhichExistsWithoutOTMPFILEOrRenameat2() async throws { 69 | // Takes the path where 'O_TMPFILE' doesn't exist, so materializing the file is done via 70 | diff --git a/Tests/NIOFileSystemIntegrationTests/FileSystemTests.swift b/Tests/NIOFileSystemIntegrationTests/FileSystemTests.swift 71 | index f24736a7..310d9691 100644 72 | --- a/Tests/NIOFileSystemIntegrationTests/FileSystemTests.swift 73 | +++ b/Tests/NIOFileSystemIntegrationTests/FileSystemTests.swift 74 | @@ -19,8 +19,8 @@ import NIOCore 75 | @_spi(Testing) @testable import _NIOFileSystem 76 | 77 | extension FilePath { 78 | - static let testData = FilePath(#filePath) 79 | - .removingLastComponent() // FileHandleTests.swift 80 | + static let testFile = FilePath("/data/data/com.termux/pack/FileHandleTests.swift") 81 | + static let testData = FilePath("/data/data/com.termux/pack/") 82 | .appending("Test Data") 83 | .lexicallyNormalized() 84 | 85 | @@ -100,7 +100,7 @@ final class FileSystemTests: XCTestCase { 86 | } 87 | 88 | func testOpenFileWhereIntermediateIsNotADirectory() async throws { 89 | - let path = FilePath(#filePath).appending("foobar") 90 | + let path = FilePath.testFile.appending("foobar") 91 | 92 | // For reading: 93 | await XCTAssertThrowsFileSystemErrorAsync { 94 | @@ -183,7 +183,7 @@ final class FileSystemTests: XCTestCase { 95 | XCTAssertEqual(contents, ByteBuffer(bytes: [0, 1, 2])) 96 | } 97 | 98 | - func testOpenNonExistentFileForWritingWithMaterialization() async throws { 99 | + /*func testOpenNonExistentFileForWritingWithMaterialization() async throws { 100 | for isAbsolute in [true, false] { 101 | let path = try await self.fs.temporaryFilePath(inTemporaryDirectory: isAbsolute) 102 | XCTAssertEqual(path.isAbsolute, isAbsolute) 103 | @@ -256,7 +256,7 @@ final class FileSystemTests: XCTestCase { 104 | XCTAssertEqual(buffer.readBytes(length: 1024), Array(repeating: 0, count: 1024)) 105 | XCTAssertEqual(buffer.readBytes(length: 1024), Array(repeating: 1, count: 1024)) 106 | XCTAssertEqual(buffer.readableBytes, 0) 107 | - } 108 | + }*/ 109 | 110 | func testOpenFileForReadingAndWriting() async throws { 111 | let path = try await self.fs.temporaryFilePath() 112 | @@ -315,7 +315,7 @@ final class FileSystemTests: XCTestCase { 113 | } 114 | } 115 | 116 | - func testOpenNonExistentFileForWritingRelativeToDirectoryWithMaterialization() async throws { 117 | + /*func testOpenNonExistentFileForWritingRelativeToDirectoryWithMaterialization() async throws { 118 | // (false, false) isn't supported. 119 | let isPathAbsolute: [(Bool, Bool)] = [(true, true), (true, false), (false, true)] 120 | 121 | @@ -419,7 +419,7 @@ final class FileSystemTests: XCTestCase { 122 | } 123 | } 124 | } 125 | - } 126 | + }*/ 127 | 128 | func testCreateDirectory() async throws { 129 | let path = try await self.fs.temporaryFilePath() 130 | @@ -559,7 +559,7 @@ final class FileSystemTests: XCTestCase { 131 | } 132 | } 133 | 134 | - func testCopyLargeFile() async throws { 135 | +/* func testCopyLargeFile() async throws { 136 | let sourcePath = try await self.fs.temporaryFilePath() 137 | let destPath = try await self.fs.temporaryFilePath() 138 | self.addTeardownBlock { [fs] in 139 | @@ -584,7 +584,7 @@ final class FileSystemTests: XCTestCase { 140 | try await self.fs.copyItem(at: sourcePath, to: destPath) 141 | let destInfo = try await self.fs.info(forFileAt: destPath) 142 | XCTAssertEqual(destInfo?.size, sourceInfo.size) 143 | - } 144 | + }*/ 145 | 146 | func testCopySingleFileCopiesAttributesAndPermissions() async throws { 147 | let original = try await self.fs.temporaryFilePath() 148 | @@ -1284,7 +1284,7 @@ extension FileSystemTests { 149 | } 150 | 151 | func testReadChunksRange() async throws { 152 | - try await self.fs.withFileHandle(forReadingAt: FilePath(#filePath)) { handle in 153 | + try await self.fs.withFileHandle(forReadingAt: FilePath.testFile) { handle in 154 | let info = try await handle.info() 155 | let size = info.size 156 | let endIndex = size + 1 157 | @@ -1310,7 +1310,7 @@ extension FileSystemTests { 158 | } 159 | 160 | func testReadChunksClosedRange() async throws { 161 | - try await self.fs.withFileHandle(forReadingAt: FilePath(#filePath)) { handle in 162 | + try await self.fs.withFileHandle(forReadingAt: FilePath.testFile) { handle in 163 | let info = try await handle.info() 164 | let size = info.size 165 | let endIndex = size + 1 166 | @@ -1337,7 +1337,7 @@ extension FileSystemTests { 167 | } 168 | 169 | func testReadChunksPartialRangeUpTo() async throws { 170 | - try await self.fs.withFileHandle(forReadingAt: FilePath(#filePath)) { handle in 171 | + try await self.fs.withFileHandle(forReadingAt: FilePath.testFile) { handle in 172 | let info = try await handle.info() 173 | let size = info.size 174 | let endIndex = size + 1 175 | @@ -1365,7 +1365,7 @@ extension FileSystemTests { 176 | } 177 | 178 | func testReadChunksPartialRangeThrough() async throws { 179 | - try await self.fs.withFileHandle(forReadingAt: FilePath(#filePath)) { handle in 180 | + try await self.fs.withFileHandle(forReadingAt: FilePath.testFile) { handle in 181 | let info = try await handle.info() 182 | let size = info.size 183 | let endIndex = size + 1 184 | @@ -1394,7 +1394,7 @@ extension FileSystemTests { 185 | } 186 | 187 | func testReadChunksPartialRangeFrom() async throws { 188 | - try await self.fs.withFileHandle(forReadingAt: FilePath(#filePath)) { handle in 189 | + try await self.fs.withFileHandle(forReadingAt: FilePath.testFile) { handle in 190 | let info = try await handle.info() 191 | let size = info.size 192 | let endIndex = size + 1 193 | @@ -1418,7 +1418,7 @@ extension FileSystemTests { 194 | } 195 | 196 | func testReadChunksUnboundedRange() async throws { 197 | - try await self.fs.withFileHandle(forReadingAt: FilePath(#filePath)) { handle in 198 | + try await self.fs.withFileHandle(forReadingAt: FilePath.testFile) { handle in 199 | let info = try await handle.info() 200 | let size = info.size 201 | 202 | diff --git a/Tests/NIOFileSystemTests/Internal/SyscallTests.swift b/Tests/NIOFileSystemTests/Internal/SyscallTests.swift 203 | index 66ed1171..5253a650 100644 204 | --- a/Tests/NIOFileSystemTests/Internal/SyscallTests.swift 205 | +++ b/Tests/NIOFileSystemTests/Internal/SyscallTests.swift 206 | @@ -17,6 +17,10 @@ 207 | import XCTest 208 | @_spi(Testing) import _NIOFileSystem 209 | 210 | +#if canImport(Android) 211 | +import Android 212 | +#endif 213 | + 214 | #if ENABLE_MOCKING 215 | final class SyscallTests: XCTestCase { 216 | func test_openat() throws { 217 | -------------------------------------------------------------------------------- /swift-nio-ssl-test.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Tests/NIOSSLTests/NIOSSLTestHelpers.swift b/Tests/NIOSSLTests/NIOSSLTestHelpers.swift 2 | index 494186e..090ceb8 100644 3 | --- a/Tests/NIOSSLTests/NIOSSLTestHelpers.swift 4 | +++ b/Tests/NIOSSLTests/NIOSSLTestHelpers.swift 5 | @@ -19,6 +19,10 @@ import NIOEmbedded 6 | 7 | @testable import NIOSSL 8 | 9 | +#if canImport(Android) 10 | +import Android 11 | +#endif 12 | + 13 | #if compiler(>=6.1) 14 | internal import CNIOBoringSSL 15 | #else 16 | diff --git a/Tests/NIOSSLTests/SSLCertificateTest.swift b/Tests/NIOSSLTests/SSLCertificateTest.swift 17 | index 18d3a1a..9bbd447 100644 18 | --- a/Tests/NIOSSLTests/SSLCertificateTest.swift 19 | +++ b/Tests/NIOSSLTests/SSLCertificateTest.swift 20 | @@ -18,6 +18,10 @@ import XCTest 21 | 22 | @testable import NIOSSL 23 | 24 | +#if canImport(Android) 25 | +import Android 26 | +#endif 27 | + 28 | let multiSanCert = """ 29 | -----BEGIN CERTIFICATE----- 30 | MIIDEzCCAfugAwIBAgIURiMaUmhI1Xr0mZ4p+JmI0XjZTaIwDQYJKoZIhvcNAQEL 31 | diff --git a/Tests/NIOSSLTests/SSLPKCS12BundleTest.swift b/Tests/NIOSSLTests/SSLPKCS12BundleTest.swift 32 | index 609b7c3..4e6accc 100644 33 | --- a/Tests/NIOSSLTests/SSLPKCS12BundleTest.swift 34 | +++ b/Tests/NIOSSLTests/SSLPKCS12BundleTest.swift 35 | @@ -11,6 +11,9 @@ 36 | // SPDX-License-Identifier: Apache-2.0 37 | // 38 | //===----------------------------------------------------------------------===// 39 | +#if canImport(Android) 40 | +import Android 41 | +#endif 42 | 43 | import Foundation 44 | import NIOCore 45 | diff --git a/Tests/NIOSSLTests/SSLPrivateKeyTests.swift b/Tests/NIOSSLTests/SSLPrivateKeyTests.swift 46 | index 7ef2dfd..a8c6ac1 100644 47 | --- a/Tests/NIOSSLTests/SSLPrivateKeyTests.swift 48 | +++ b/Tests/NIOSSLTests/SSLPrivateKeyTests.swift 49 | @@ -18,6 +18,10 @@ import XCTest 50 | 51 | @testable import NIOSSL 52 | 53 | +#if canImport(Android) 54 | +import Android 55 | +#endif 56 | + 57 | class SSLPrivateKeyTest: XCTestCase { 58 | static let dynamicallyGeneratedKey = generateSelfSignedCert().1 59 | 60 | --------------------------------------------------------------------------------