From 10c5b887a7a4027856b0f42f9b7c5eea4bbcd4b2 Mon Sep 17 00:00:00 2001 From: William Candillon Date: Wed, 9 Sep 2026 14:41:20 +0200 Subject: [PATCH 1/3] :wrench: --- .github/workflows/build-dawn.yml | 277 ------------------ .github/workflows/build-skia-graphite.yml | 45 ++- .github/workflows/build-skia.yml | 45 ++- packages/skia/package.json | 2 +- .../skia/scripts/install-skia-graphite.ts | 172 +++++++---- packages/skia/scripts/workflow-copy-libs.ts | 107 ------- yarn.lock | 3 +- 7 files changed, 190 insertions(+), 461 deletions(-) delete mode 100644 .github/workflows/build-dawn.yml delete mode 100644 packages/skia/scripts/workflow-copy-libs.ts diff --git a/.github/workflows/build-dawn.yml b/.github/workflows/build-dawn.yml deleted file mode 100644 index 45c0082ced..0000000000 --- a/.github/workflows/build-dawn.yml +++ /dev/null @@ -1,277 +0,0 @@ -name: Build Dawn - -on: workflow_dispatch - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -env: - DAWN_BRANCH: chromium/7849 # Configure the Dawn branch to checkout - -jobs: - prepare-release: - runs-on: ubuntu-latest - outputs: - dawn_branch: ${{ steps.dawn_meta.outputs.branch }} - dawn_branch_slug: ${{ steps.dawn_meta.outputs.branch_slug }} - tag_name: ${{ steps.release_meta.outputs.tag_name }} - release_name: ${{ steps.release_meta.outputs.release_name }} - steps: - - name: Checkout repository - uses: actions/checkout@v7.0.1 - - - name: Determine Dawn branch metadata - id: dawn_meta - run: | - set -eo pipefail - branch="${DAWN_BRANCH}" - # Convert slashes to hyphens for tag-safe slug - slug=${branch//\//-} - echo "branch=$branch" >> "$GITHUB_OUTPUT" - echo "branch_slug=$slug" >> "$GITHUB_OUTPUT" - env: - DAWN_BRANCH: ${{ env.DAWN_BRANCH }} - - - name: Compute release metadata - id: release_meta - run: | - tag="dawn-${DAWN_BRANCH_SLUG}" - echo "tag_name=$tag" >> "$GITHUB_OUTPUT" - echo "release_name=Dawn ${DAWN_BRANCH}" >> "$GITHUB_OUTPUT" - env: - DAWN_BRANCH: ${{ steps.dawn_meta.outputs.branch }} - DAWN_BRANCH_SLUG: ${{ steps.dawn_meta.outputs.branch_slug }} - - - name: Create GitHub release - id: create_release - uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ steps.release_meta.outputs.tag_name }} - name: ${{ steps.release_meta.outputs.release_name }} - body: "Dawn prebuilt binaries for version ${{ steps.dawn_meta.outputs.branch }}" - draft: false - prerelease: true - generate_release_notes: false - - mobile-android: - needs: prepare-release - strategy: - fail-fast: false - matrix: - include: - # Android builds - - arch: arm64-v8a - toolchain_file: $ANDROID_NDK/build/cmake/android.toolchain.cmake - cmake_args: -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-26 - output_dir: externals/dawn/out/android_arm64-v8a - library_path: src/dawn/native/libwebgpu_dawn.so - strip_tool: $ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip - - arch: armeabi-v7a - toolchain_file: $ANDROID_NDK/build/cmake/android.toolchain.cmake - cmake_args: -DANDROID_ABI=armeabi-v7a -DANDROID_PLATFORM=android-26 - output_dir: externals/dawn/out/android_armeabi-v7a - library_path: src/dawn/native/libwebgpu_dawn.so - strip_tool: $ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip - - arch: x86 - toolchain_file: $ANDROID_NDK/build/cmake/android.toolchain.cmake - cmake_args: -DANDROID_ABI=x86 -DANDROID_PLATFORM=android-26 - output_dir: externals/dawn/out/android_x86 - library_path: src/dawn/native/libwebgpu_dawn.so - strip_tool: $ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip - - arch: x86_64 - toolchain_file: $ANDROID_NDK/build/cmake/android.toolchain.cmake - cmake_args: -DANDROID_ABI=x86_64 -DANDROID_PLATFORM=android-26 - output_dir: externals/dawn/out/android_x86_64 - library_path: src/dawn/native/libwebgpu_dawn.so - strip_tool: $ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip - - name: Build-android-${{ matrix.arch }} - runs-on: ubuntu-latest - steps: - - name: Checkout main repository - uses: actions/checkout@v7.0.1 - - - name: Checkout Dawn repository - run: | - git clone --depth 1 --branch ${{ env.DAWN_BRANCH }} https://dawn.googlesource.com/dawn externals/dawn - - - name: Setup Android NDK - id: setup-ndk - uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1.6.0 - with: - ndk-version: r27d - - - name: Set ANDROID_NDK - run: echo "ANDROID_NDK=${{ steps.setup-ndk.outputs.ndk-path }}" >> $GITHUB_ENV - - - name: Build android ${{ matrix.arch }} - run: | - cmake -S externals/dawn -B ${{ matrix.output_dir }} -G Ninja \ - -DDAWN_MOBILE_BUILD=android \ - -C externals/dawn/.github/workflows/dawn-ci.cmake \ - -DCMAKE_TOOLCHAIN_FILE=${{ matrix.toolchain_file }} \ - ${{ matrix.cmake_args }} \ - -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_SHARED_LIBS=OFF \ - -DDAWN_BUILD_MONOLITHIC_LIBRARY=SHARED \ - -DDAWN_BUILD_PROTOBUF=OFF \ - -DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON \ - -DCMAKE_EXE_LINKER_FLAGS="-llog" \ - -DCMAKE_SHARED_LINKER_FLAGS="-llog -Wl,-z,max-page-size=16384" - ninja -C ${{ matrix.output_dir }} - - name: Strip Android binaries - run: | - ${{ matrix.strip_tool }} ${{ matrix.output_dir }}/${{ matrix.library_path }} - - - name: Upload build artifacts - uses: actions/upload-artifact@v7 - with: - name: build-android-${{ matrix.arch }} - path: ${{ matrix.output_dir }}/${{ matrix.library_path }} - - - name: Install headers (from arm64-v8a build only) - if: matrix.arch == 'arm64-v8a' - run: | - cmake --install ${{ matrix.output_dir }} --prefix dawn-headers - - - name: Upload headers (from arm64-v8a build only) - if: matrix.arch == 'arm64-v8a' - uses: actions/upload-artifact@v7 - with: - name: dawn-headers - path: dawn-headers/ - - mobile-apple: - needs: prepare-release - strategy: - fail-fast: false - matrix: - include: - # Apple builds - - platform: ios - arch: arm64 - cmake_args: -DPLATFORM=OS64 -DDEPLOYMENT_TARGET=14.0 -DENABLE_BITCODE=OFF -DENABLE_ARC=OFF -DENABLE_VISIBILITY=OFF - output_dir: externals/dawn/out/ios_arm64 - library_path: src/dawn/native/libwebgpu_dawn.a - - platform: ios - arch: sim_arm64 - cmake_args: -DPLATFORM=SIMULATORARM64 -DDEPLOYMENT_TARGET=14.0 -DENABLE_BITCODE=OFF -DENABLE_ARC=OFF -DENABLE_VISIBILITY=OFF - output_dir: externals/dawn/out/ios_sim_arm64 - library_path: src/dawn/native/libwebgpu_dawn.a - - platform: ios - arch: sim_x86_64 - cmake_args: -DPLATFORM=SIMULATOR64 -DDEPLOYMENT_TARGET=14.0 -DENABLE_BITCODE=OFF -DENABLE_ARC=OFF -DENABLE_VISIBILITY=OFF - output_dir: externals/dawn/out/ios_sim_x86_64 - library_path: src/dawn/native/libwebgpu_dawn.a - - platform: macos - arch: universal - cmake_args: -DPLATFORM=MAC_UNIVERSAL -DDEPLOYMENT_TARGET=11.0 -DENABLE_BITCODE=OFF -DENABLE_ARC=OFF -DENABLE_VISIBILITY=OFF - output_dir: externals/dawn/out/macos_universal - library_path: src/dawn/native/libwebgpu_dawn.a - - name: Build-${{ matrix.platform }}-${{ matrix.arch }} - runs-on: macos-latest-large - steps: - - name: Checkout main repository - uses: actions/checkout@v7.0.1 - - - name: Checkout Dawn repository - run: | - git clone --depth 1 --branch ${{ env.DAWN_BRANCH }} https://dawn.googlesource.com/dawn externals/dawn -# submodules: true - - - name: Setup Xcode - uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0 - with: - xcode-version: latest-stable - - - name: Download Apple toolchain - run: | - mkdir -p externals/dawn/build-tools - # Download the ios-cmake toolchain file - curl -L https://raw.githubusercontent.com/leetal/ios-cmake/6fa909e133b92343db2d099e0478448c05ffec1a/ios.toolchain.cmake -o externals/dawn/build-tools/apple.toolchain.cmake - - - name: Build ${{ matrix.platform }} ${{ matrix.arch }} - run: | - cmake -S externals/dawn -B ${{ matrix.output_dir }} -G Ninja \ - -DDAWN_MOBILE_BUILD=apple \ - -C externals/dawn/.github/workflows/dawn-ci.cmake \ - -DCMAKE_TOOLCHAIN_FILE=build-tools/apple.toolchain.cmake \ - ${{ matrix.cmake_args }} \ - -DCMAKE_BUILD_TYPE=Release \ - -DDAWN_BUILD_PROTOBUF=OFF - ninja -C ${{ matrix.output_dir }} - - name: Upload build artifacts - uses: actions/upload-artifact@v7 - with: - name: build-${{ matrix.platform }}-${{ matrix.arch }} - path: ${{ matrix.output_dir }}/${{ matrix.library_path }} - - package-mobile: - name: Package Mobile Artifacts - runs-on: macos-latest - needs: [prepare-release, mobile-android, mobile-apple] - steps: - - name: Checkout main repository - uses: actions/checkout@v7.0.1 - - - name: Download all build artifacts - uses: actions/download-artifact@v8 - with: - pattern: build-* - path: artifacts - - - name: Download headers - uses: actions/download-artifact@v8 - with: - name: dawn-headers - path: dawn-headers - - - name: Create iOS Simulator fat binary - run: | - mkdir -p libs/apple/iphonesimulator - lipo -create \ - artifacts/build-ios-sim_x86_64/libwebgpu_dawn.a \ - artifacts/build-ios-sim_arm64/libwebgpu_dawn.a \ - -output libs/apple/iphonesimulator/libwebgpu_dawn.a - - - name: Create XCFramework - run: | - xcodebuild -create-xcframework \ - -library libs/apple/iphonesimulator/libwebgpu_dawn.a \ - -library artifacts/build-ios-arm64/libwebgpu_dawn.a \ - -library artifacts/build-macos-universal/libwebgpu_dawn.a \ - -output dawn-apple.xcframework - - - name: Package Android libraries - run: | - mkdir -p dawn-android/arm64-v8a - mkdir -p dawn-android/armeabi-v7a - mkdir -p dawn-android/x86 - mkdir -p dawn-android/x86_64 - cp artifacts/build-android-arm64-v8a/libwebgpu_dawn.so dawn-android/arm64-v8a/ - cp artifacts/build-android-armeabi-v7a/libwebgpu_dawn.so dawn-android/armeabi-v7a/ - cp artifacts/build-android-x86/libwebgpu_dawn.so dawn-android/x86/ - cp artifacts/build-android-x86_64/libwebgpu_dawn.so dawn-android/x86_64/ - - - name: Create archives - run: | - TAG="${{ needs.prepare-release.outputs.tag_name }}" - tar -czf dawn-android-${TAG}.tar.gz dawn-android - tar -czf dawn-apple-${TAG}.xcframework.tar.gz dawn-apple.xcframework - tar -czf dawn-headers-${TAG}.tar.gz dawn-headers - - - name: Upload to GitHub release - uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ needs.prepare-release.outputs.tag_name }} - files: | - dawn-android-${{ needs.prepare-release.outputs.tag_name }}.tar.gz - dawn-apple-${{ needs.prepare-release.outputs.tag_name }}.xcframework.tar.gz - dawn-headers-${{ needs.prepare-release.outputs.tag_name }}.tar.gz - prerelease: true diff --git a/.github/workflows/build-skia-graphite.yml b/.github/workflows/build-skia-graphite.yml index e41b25f1c5..a72ba4667e 100644 --- a/.github/workflows/build-skia-graphite.yml +++ b/.github/workflows/build-skia-graphite.yml @@ -178,8 +178,43 @@ jobs: SK_GRAPHITE: 1 run: yarn build-skia ${{ matrix.target }} - - name: Package binaries - ${{ matrix.artifact_name }} - id: package + - name: Package Apple xcframeworks (per-framework zips) - ${{ matrix.artifact_name }} + if: startsWith(matrix.target, 'apple') + run: | + set -eo pipefail + ROOT="${{ matrix.package_root }}" + TAG="${DISPATCH_TAG}" + if [ -z "$TAG" ]; then + TAG="${SKIA_BRANCH_SLUG}" + fi + if [ -z "$TAG" ]; then + TAG="${GITHUB_REF_NAME:-}" + fi + if [ -z "$TAG" ]; then + TAG="${GITHUB_SHA}" + fi + mkdir -p release-assets + # SPM binaryTarget requires one .xcframework per .zip archive, so each + # framework in the bundle is zipped separately (ditto preserves the + # symlinks inside .xcframework, unlike the default `zip` tool) and its + # SPM checksum recorded for the future Package.swift binaryTargets. + MANIFEST="release-assets/${{ matrix.artifact_name }}-${TAG}.checksums.txt" + : > "$MANIFEST" + for fw in "$ROOT"/*.xcframework; do + NAME="$(basename "$fw" .xcframework)" + ZIP_NAME="${{ matrix.artifact_name }}-${NAME}-${TAG}.zip" + ZIP_PATH="release-assets/$ZIP_NAME" + ditto -c -k --sequesterRsrc --keepParent "$fw" "$ZIP_PATH" + CHECKSUM="$(swift package compute-checksum "$ZIP_PATH")" + echo "$ZIP_NAME $CHECKSUM" >> "$MANIFEST" + done + shell: bash + env: + DISPATCH_TAG: ${{ needs.prepare-release.outputs.tag_name }} + SKIA_BRANCH_SLUG: ${{ needs.prepare-release.outputs.skia_branch_slug }} + + - name: Package Android binaries - ${{ matrix.artifact_name }} + if: startsWith(matrix.target, 'android') run: | set -eo pipefail ROOT="${{ matrix.package_root }}" @@ -198,8 +233,6 @@ jobs: ARCHIVE="${{ matrix.artifact_name }}-${TAG}.tar.gz" mkdir -p release-assets tar -czf "release-assets/$ARCHIVE" -C "$PARENT" "$BASENAME" - echo "asset_path=release-assets/$ARCHIVE" >> "$GITHUB_OUTPUT" - echo "asset_name=$ARCHIVE" >> "$GITHUB_OUTPUT" shell: bash env: DISPATCH_TAG: ${{ needs.prepare-release.outputs.tag_name }} @@ -212,7 +245,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ needs.prepare-release.outputs.tag_name }} - files: ${{ steps.package.outputs.asset_path }} + files: release-assets/* prerelease: true - name: Upload binaries as workflow artifact (dry run) - ${{ matrix.artifact_name }} @@ -220,7 +253,7 @@ jobs: uses: actions/upload-artifact@v7 with: name: ${{ matrix.artifact_name }} - path: ${{ steps.package.outputs.asset_path }} + path: release-assets/ retention-days: 7 - name: Package Graphite Headers diff --git a/.github/workflows/build-skia.yml b/.github/workflows/build-skia.yml index f1f3dc0e66..e8b2042d90 100644 --- a/.github/workflows/build-skia.yml +++ b/.github/workflows/build-skia.yml @@ -129,8 +129,43 @@ jobs: ZERO_AR_DATE: 1 run: yarn build-skia ${{ matrix.target }} - - name: Package binaries - ${{ matrix.artifact_name }} - id: package + - name: Package Apple xcframeworks (per-framework zips) - ${{ matrix.artifact_name }} + if: startsWith(matrix.target, 'apple') + run: | + set -eo pipefail + ROOT="${{ matrix.package_root }}" + TAG="${DISPATCH_TAG}" + if [ -z "$TAG" ]; then + TAG="${SKIA_BRANCH_SLUG}" + fi + if [ -z "$TAG" ]; then + TAG="${GITHUB_REF_NAME:-}" + fi + if [ -z "$TAG" ]; then + TAG="${GITHUB_SHA}" + fi + mkdir -p release-assets + # SPM binaryTarget requires one .xcframework per .zip archive, so each + # framework in the bundle is zipped separately (ditto preserves the + # symlinks inside .xcframework, unlike the default `zip` tool) and its + # SPM checksum recorded for the future Package.swift binaryTargets. + MANIFEST="release-assets/${{ matrix.artifact_name }}-${TAG}.checksums.txt" + : > "$MANIFEST" + for fw in "$ROOT"/*.xcframework; do + NAME="$(basename "$fw" .xcframework)" + ZIP_NAME="${{ matrix.artifact_name }}-${NAME}-${TAG}.zip" + ZIP_PATH="release-assets/$ZIP_NAME" + ditto -c -k --sequesterRsrc --keepParent "$fw" "$ZIP_PATH" + CHECKSUM="$(swift package compute-checksum "$ZIP_PATH")" + echo "$ZIP_NAME $CHECKSUM" >> "$MANIFEST" + done + shell: bash + env: + DISPATCH_TAG: ${{ needs.prepare-release.outputs.tag_name }} + SKIA_BRANCH_SLUG: ${{ needs.prepare-release.outputs.skia_branch_slug }} + + - name: Package Android binaries - ${{ matrix.artifact_name }} + if: startsWith(matrix.target, 'android') run: | set -eo pipefail ROOT="${{ matrix.package_root }}" @@ -149,8 +184,6 @@ jobs: ARCHIVE="${{ matrix.artifact_name }}-${TAG}.tar.gz" mkdir -p release-assets tar -czf "release-assets/$ARCHIVE" -C "$PARENT" "$BASENAME" - echo "asset_path=release-assets/$ARCHIVE" >> "$GITHUB_OUTPUT" - echo "asset_name=$ARCHIVE" >> "$GITHUB_OUTPUT" shell: bash env: DISPATCH_TAG: ${{ needs.prepare-release.outputs.tag_name }} @@ -163,7 +196,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ needs.prepare-release.outputs.tag_name }} - files: ${{ steps.package.outputs.asset_path }} + files: release-assets/* prerelease: true - name: Upload binaries as workflow artifact (dry run) - ${{ matrix.artifact_name }} @@ -171,5 +204,5 @@ jobs: uses: actions/upload-artifact@v7 with: name: ${{ matrix.artifact_name }} - path: ${{ steps.package.outputs.asset_path }} + path: release-assets/ retention-days: 7 diff --git a/packages/skia/package.json b/packages/skia/package.json index 815dcb70bc..ba3eab3e38 100644 --- a/packages/skia/package.json +++ b/packages/skia/package.json @@ -51,7 +51,6 @@ "clang-format-ios": "find apple/ -iname '*.h' -o -iname '*.mm' -o -iname '*.cpp' | xargs clang-format -i", "clang-format-android": "find android/cpp/ -iname '*.h' -o -iname '*.m' -o -iname '*.cpp' | xargs clang-format -i", "clang-format-common": "find cpp/ \\( -path 'cpp//skia' -prune \\) -o \\( -iname '*.h' -o -iname '*.m' -o -iname '*.cpp' \\) -print | xargs clang-format -i", - "workflow-copy-libs": "tsx ./scripts/workflow-copy-libs.ts", "cpplint": "cpplint --linelength=230 --filter=-legal/copyright,-whitespace/indent,-whitespace/comments,-whitespace/ending_newline,-build/include_order,-runtime/references,-readability/todo,-whitespace/blank_line,-whitespace/todo,-runtime/int,-build/c++11,-whitespace/parens --exclude=package/cpp/skia --exclude=package/ios --exclude=package/android/build --exclude=package/node_modules --recursive package" }, "repository": { @@ -116,6 +115,7 @@ "eslint-config-react-native-wcandillon": "4.0.1", "eslint-plugin-import": "2.32.0", "eslint-plugin-react-hooks": "^5.2.0", + "extract-zip": "^2.0.1", "jest": "30.0.0", "jest-diff": "29.7.0", "jest-environment-jsdom": "30.0.0", diff --git a/packages/skia/scripts/install-skia-graphite.ts b/packages/skia/scripts/install-skia-graphite.ts index 6d2b0264a0..5e60c90698 100644 --- a/packages/skia/scripts/install-skia-graphite.ts +++ b/packages/skia/scripts/install-skia-graphite.ts @@ -15,34 +15,60 @@ import { existsSync, mkdirSync, readFileSync, - readdirSync, rmSync, writeFileSync, } from "fs"; import https from "https"; import path from "path"; +import extractZip from "extract-zip"; import { extract } from "tar"; import { copyHeaders } from "./skia-configuration"; import { fileOps } from "./utils"; +// The xcframeworks bundled for each Apple platform. Each one is published as +// its own .zip (SPM's binaryTarget requires one .xcframework per archive), so +// this list drives both the download loop below and, eventually, the +// per-framework binaryTargets in Package.swift. +const APPLE_FRAMEWORKS = [ + "libskia", + "libskottie", + "libskparagraph", + "libsksg", + "libskshaper", + "libskunicode_core", + "libskunicode_libgrapheme", + "libsvg", +] as const; + // Graphite configuration +// +// NOTE: the "apple" checksums below are placeholders (build-skia-graphite.yml +// now zips each xcframework individually - see its "Package Apple +// xcframeworks" step). They must be regenerated from that workflow's +// `*.checksums.txt` release asset the next time this GRAPHITE_CONFIG.version +// is built, or `yarn install-skia-graphite` will fail on the Apple download step. const GRAPHITE_CONFIG = { version: "m152", checksums: { - "android-armeabi-v7a": - "edc363fb63d3e629d7023d63d505c2d075030dfc40e04890d988eaff5c31c2fc", - "android-arm64-v8a": - "cefc18191d46deec3e164f3b717b06c6ae7845eeec21fe11cca53339063cf1e2", - "android-x86": - "78041f4d58fafda1821c96f83e4818cce492a7047b16f267527e3e140d0b4c0d", - "android-x86_64": - "8cfcd40b87b42aa0aaaba89852aa51f3316c90debcdf24dcc5a9b7b562a8aa6f", - "apple-ios-xcframeworks": - "9a64915dd95bf22ab3f38624ac2fc7e4a14cfd155f218170317ccef6ab9dfc69", - "apple-macos-xcframeworks": - "995cc77d575368d2df08a16ed0345395ba66308b00ba57ef190e70eb710d74f9", + android: { + "armeabi-v7a": + "edc363fb63d3e629d7023d63d505c2d075030dfc40e04890d988eaff5c31c2fc", + "arm64-v8a": + "cefc18191d46deec3e164f3b717b06c6ae7845eeec21fe11cca53339063cf1e2", + "x86": "78041f4d58fafda1821c96f83e4818cce492a7047b16f267527e3e140d0b4c0d", + "x86_64": + "8cfcd40b87b42aa0aaaba89852aa51f3316c90debcdf24dcc5a9b7b562a8aa6f", + }, + apple: { + ios: Object.fromEntries( + APPLE_FRAMEWORKS.map((name) => [name, "REPLACE_WITH_REAL_CHECKSUM"]) + ) as Record<(typeof APPLE_FRAMEWORKS)[number], string>, + macos: Object.fromEntries( + APPLE_FRAMEWORKS.map((name) => [name, "REPLACE_WITH_REAL_CHECKSUM"]) + ) as Record<(typeof APPLE_FRAMEWORKS)[number], string>, + }, }, } as const; @@ -189,6 +215,38 @@ const downloadAndExtract = async ( rmSync(tempFile, { force: true }); }; +// Download and extract a single-xcframework .zip asset (SPM-compatible +// packaging - see APPLE_FRAMEWORKS above) into destDir. +const downloadAndExtractZip = async ( + assetName: string, + destDir: string, + expectedChecksum: string +): Promise => { + const url = getDownloadUrl(assetName); + const tempFile = path.join(LIBS_DIR, `${assetName}.tmp`); + + console.log(` Downloading ${assetName}...`); + await downloadFile(url, tempFile); + + console.log(` Verifying checksum...`); + const actualChecksum = calculateFileChecksum(tempFile); + if (actualChecksum !== expectedChecksum) { + rmSync(tempFile, { force: true }); + throw new Error( + `Checksum mismatch for ${assetName}:\n` + + ` Expected: ${expectedChecksum}\n` + + ` Actual: ${actualChecksum}` + ); + } + console.log(` āœ“ Checksum verified`); + + console.log(` Extracting to ${destDir}...`); + mkdirSync(destDir, { recursive: true }); + await extractZip(tempFile, { dir: destDir }); + + rmSync(tempFile, { force: true }); +}; + // Checkout the Skia submodule to the correct branch const checkoutSkiaSubmodule = (): void => { const baseVersion = getBaseVersion(GRAPHITE_CONFIG.version); @@ -276,9 +334,10 @@ const downloadAndroidLibs = async (): Promise => { const releaseTag = getReleaseTag(GRAPHITE_CONFIG.version); for (const abi of androidAbis) { - const checksumKey = - `android-${abi.name}` as keyof typeof GRAPHITE_CONFIG.checksums; - const expectedChecksum = GRAPHITE_CONFIG.checksums[checksumKey]; + const expectedChecksum = + GRAPHITE_CONFIG.checksums.android[ + abi.name as keyof typeof GRAPHITE_CONFIG.checksums.android + ]; const assetName = `skia-graphite-${abi.asset}-${releaseTag}.tar.gz`; const destDir = path.join(LIBS_DIR, "android", abi.name); @@ -357,59 +416,46 @@ const downloadDawnLibs = async (): Promise => { console.log(` āœ“ Dawn libraries downloaded`); }; -// Download Apple libraries -const downloadAppleLibs = async (): Promise => { - console.log(`\nšŸŽ Downloading Apple Graphite libraries...`); - +// Download Apple libraries. Each xcframework is published as its own zip +// (see APPLE_FRAMEWORKS), named +// `skia-graphite-apple--xcframeworks--.zip`. +const downloadApplePlatformLibs = async ( + platform: "ios" | "macos", + artifactPrefix: string +): Promise => { const releaseTag = getReleaseTag(GRAPHITE_CONFIG.version); - const iosDir = path.join(LIBS_DIR, "ios"); - const macosDir = path.join(LIBS_DIR, "macos"); - - // Clean and create destination directories - fileOps.rm(iosDir); - fileOps.rm(macosDir); - fileOps.mkdir(iosDir); - fileOps.mkdir(macosDir); - - // Download iOS xcframeworks - const iosAsset = `skia-graphite-apple-ios-xcframeworks-${releaseTag}.tar.gz`; - const iosTempDir = path.join(LIBS_DIR, "apple-ios-temp"); - await downloadAndExtract( - iosAsset, - iosTempDir, - GRAPHITE_CONFIG.checksums["apple-ios-xcframeworks"] - ); + const destDir = path.join(LIBS_DIR, platform); + fileOps.rm(destDir); + fileOps.mkdir(destDir); - const extractedIosDir = path.join(iosTempDir, "ios"); - if (existsSync(extractedIosDir)) { - const xcframeworks = readdirSync(extractedIosDir).filter( - (f) => f.endsWith(".xcframework") && f !== "libdawn_combined.xcframework" - ); - for (const xcf of xcframeworks) { - fileOps.cp(path.join(extractedIosDir, xcf), path.join(iosDir, xcf)); - } - } - rmSync(iosTempDir, { recursive: true, force: true }); + const checksums = GRAPHITE_CONFIG.checksums.apple[platform]; + for (const framework of APPLE_FRAMEWORKS) { + const assetName = `${artifactPrefix}-${framework}-${releaseTag}.zip`; + const tempDir = path.join(LIBS_DIR, `apple-${platform}-${framework}-temp`); - // Download macOS xcframeworks - const macosAsset = `skia-graphite-apple-macos-xcframeworks-${releaseTag}.tar.gz`; - const macosTempDir = path.join(LIBS_DIR, "apple-macos-temp"); - await downloadAndExtract( - macosAsset, - macosTempDir, - GRAPHITE_CONFIG.checksums["apple-macos-xcframeworks"] - ); + await downloadAndExtractZip(assetName, tempDir, checksums[framework]); - const extractedMacosDir = path.join(macosTempDir, "macos"); - if (existsSync(extractedMacosDir)) { - const xcframeworks = readdirSync(extractedMacosDir).filter( - (f) => f.endsWith(".xcframework") && f !== "libdawn_combined.xcframework" - ); - for (const xcf of xcframeworks) { - fileOps.cp(path.join(extractedMacosDir, xcf), path.join(macosDir, xcf)); + const xcfName = `${framework}.xcframework`; + const extracted = path.join(tempDir, xcfName); + if (!existsSync(extracted)) { + throw new Error(`Missing ${xcfName} in ${assetName}`); } + fileOps.cp(extracted, path.join(destDir, xcfName)); + rmSync(tempDir, { recursive: true, force: true }); } - rmSync(macosTempDir, { recursive: true, force: true }); +}; + +const downloadAppleLibs = async (): Promise => { + console.log(`\nšŸŽ Downloading Apple Graphite libraries...`); + + await downloadApplePlatformLibs( + "ios", + "skia-graphite-apple-ios-xcframeworks" + ); + await downloadApplePlatformLibs( + "macos", + "skia-graphite-apple-macos-xcframeworks" + ); console.log(` āœ“ Apple libraries downloaded`); }; diff --git a/packages/skia/scripts/workflow-copy-libs.ts b/packages/skia/scripts/workflow-copy-libs.ts deleted file mode 100644 index a7d8417a60..0000000000 --- a/packages/skia/scripts/workflow-copy-libs.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { existsSync, writeFileSync } from "fs"; - -import { ensureFolderExists, copyRecursiveSync } from "./utils"; -import { GRAPHITE } from "./skia-configuration"; -/** - * This build script prepares the npm build command by copying - * the Skia Binaries from the artifact folder into the libs folder - * in the checkout directory. This build script is run by the - * build-npm.yml workflow and does not require anything. - */ - -console.log("Copying Skia Binaries from artifacts to libs folder"); - -const suffix = GRAPHITE ? "-graphite" : ""; -const sources = [ - `./skia${suffix}-android-arm`, - `./skia${suffix}-android-arm-64`, - `./skia${suffix}-android-arm-x86`, - `./skia${suffix}-android-arm-x64`, -]; - -const destinations = ["armeabi-v7a", "arm64-v8a", "x86", "x86_64"]; - -const androidFiles = [ - "libskia.a", - "libskshaper.a", - "libsvg.a", - "libskottie.a", - "libsksg.a", - "libskparagraph.a", - "libskunicode_core.a", - "libskunicode_icu.a", - "libjsonreader.a", - // Dawn library for Graphite builds - ...(GRAPHITE ? ["libdawn_combined.a"] : []), -]; - -const appleFiles = [ - "libskia.xcframework", - "libskshaper.xcframework", - "libsvg.xcframework", - "libskottie.xcframework", - "libsksg.xcframework", - "libskparagraph.xcframework", - "libskunicode_core.xcframework", - "libskunicode_libgrapheme.xcframework", - // Dawn library for Graphite builds - ...(GRAPHITE ? ["libdawn_combined.xcframework"] : []), -]; - -const copyFiles = (from: string, to: string, files: string[]) => { - ensureFolderExists(to); - files.forEach((f) => { - const source = "./artifacts/" + from + "/" + f; - const target = to + "/" + f; - if (!existsSync(source)) { - console.log( - "Copying failed, the artifact source", - source, - "was not found. Current dir is:", - process.cwd() - ); - process.exit(1); - } - if (!existsSync(to)) { - console.log( - "Copying failed, the destination", - to, - "was not found. Current dir is:", - process.cwd() - ); - process.exit(1); - } - copyRecursiveSync(source, target); - console.log("Copied", source, target); - }); -}; - -console.log("Copying android files..."); -destinations.forEach((d, i) => { - copyFiles(sources[i], "./libs/android/" + d, androidFiles); -}); - -console.log("Copying Apple files..."); -copyFiles(`skia${suffix}-apple-ios-xcframeworks`, "./libs/ios", appleFiles); -copyFiles(`skia${suffix}-apple-macos-xcframeworks`, "./libs/macos", appleFiles); - -if (GRAPHITE) { - writeFileSync("./libs/.graphite", ""); - console.log("Created libs/.graphite marker file"); -} - -// Copy skia-headers and skia-graphite-headers artifacts to ./cpp/ -if (GRAPHITE) { - [`skia${suffix}-headers`].forEach((headerArtifact) => { - const source = `./artifacts/${headerArtifact}`; - const target = "./cpp"; - if (existsSync(source)) { - copyRecursiveSync(source, target); - console.log(`Copied headers from ${source} to ${target}`); - } else { - console.log(`Header artifact ${source} not found, skipping.`); - } - }); -} - -console.log("Done copying artifacts."); diff --git a/yarn.lock b/yarn.lock index 57a9e959ff..fd21ae5f0d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9091,6 +9091,7 @@ __metadata: eslint-config-react-native-wcandillon: 4.0.1 eslint-plugin-import: 2.32.0 eslint-plugin-react-hooks: ^5.2.0 + extract-zip: ^2.0.1 jest: 30.0.0 jest-diff: 29.7.0 jest-environment-jsdom: 30.0.0 @@ -16589,7 +16590,7 @@ __metadata: languageName: node linkType: hard -"extract-zip@npm:2.0.1": +"extract-zip@npm:2.0.1, extract-zip@npm:^2.0.1": version: 2.0.1 resolution: "extract-zip@npm:2.0.1" dependencies: From b61e2fa032cb3ec3816b8a0bcd39f1636a34b81f Mon Sep 17 00:00:00 2001 From: William Candillon Date: Sat, 12 Sep 2026 14:49:50 +0200 Subject: [PATCH 2/3] :wrench: --- externals/depot_tools | 2 +- externals/skia | 2 +- .../skia/scripts/install-skia-graphite.ts | 47 +++++++++---------- packages/skia/scripts/skia-configuration.ts | 6 +++ 4 files changed, 31 insertions(+), 26 deletions(-) diff --git a/externals/depot_tools b/externals/depot_tools index 6afa997717..36a8df4ad0 160000 --- a/externals/depot_tools +++ b/externals/depot_tools @@ -1 +1 @@ -Subproject commit 6afa997717b2c0e1382e1465bedbe1a6855b9388 +Subproject commit 36a8df4ad006eaa0572fb446edb8145fe5403592 diff --git a/externals/skia b/externals/skia index 2a9b593bab..9f9e6beb75 160000 --- a/externals/skia +++ b/externals/skia @@ -1 +1 @@ -Subproject commit 2a9b593bab4b2fd019fa494c8d401ff1fab0b883 +Subproject commit 9f9e6beb751091ef69163d2b4fdcd1e711b594ac diff --git a/packages/skia/scripts/install-skia-graphite.ts b/packages/skia/scripts/install-skia-graphite.ts index 5e60c90698..1c6a02c9d5 100644 --- a/packages/skia/scripts/install-skia-graphite.ts +++ b/packages/skia/scripts/install-skia-graphite.ts @@ -47,19 +47,17 @@ const APPLE_FRAMEWORKS = [ // NOTE: the "apple" checksums below are placeholders (build-skia-graphite.yml // now zips each xcframework individually - see its "Package Apple // xcframeworks" step). They must be regenerated from that workflow's -// `*.checksums.txt` release asset the next time this GRAPHITE_CONFIG.version -// is built, or `yarn install-skia-graphite` will fail on the Apple download step. +// `*.checksums.txt` release asset once this GRAPHITE_CONFIG.version has +// actually been built by build-skia-graphite.yml, or `yarn install-skia-graphite` +// will fail on the Apple download step. const GRAPHITE_CONFIG = { - version: "m152", + version: "m154", checksums: { android: { - "armeabi-v7a": - "edc363fb63d3e629d7023d63d505c2d075030dfc40e04890d988eaff5c31c2fc", - "arm64-v8a": - "cefc18191d46deec3e164f3b717b06c6ae7845eeec21fe11cca53339063cf1e2", - "x86": "78041f4d58fafda1821c96f83e4818cce492a7047b16f267527e3e140d0b4c0d", - "x86_64": - "8cfcd40b87b42aa0aaaba89852aa51f3316c90debcdf24dcc5a9b7b562a8aa6f", + "armeabi-v7a": "REPLACE_WITH_REAL_CHECKSUM", + "arm64-v8a": "REPLACE_WITH_REAL_CHECKSUM", + "x86": "REPLACE_WITH_REAL_CHECKSUM", + "x86_64": "REPLACE_WITH_REAL_CHECKSUM", }, apple: { ios: Object.fromEntries( @@ -75,19 +73,17 @@ const GRAPHITE_CONFIG = { // Dawn prebuilt binaries. These are the exact artifacts react-native-webgpu // links; both packages must consume the same Dawn build so that only one Dawn // copy exists in an app that installs both, which is why the release tag is -// pinned here rather than derived from GRAPHITE_CONFIG.version. -// -// STALE: this is still the m150 Dawn (63f25feec51e9351fb25222b6d5de1af791d7c4f) -// while m152's DEPS pins 1e897275172a23f27b0022fa6beae3084ed54a9b. Bump this to -// dawn-chrome-m152 (with new checksums) once react-native-webgpu publishes that -// release; until then Graphite installs pair m152 Skia with m150 Dawn. +// pinned here rather than derived from GRAPHITE_CONFIG.version. Skia's DEPS at +// chrome/m154 pins Dawn @ 3d786993a7ded64c4ebb4884b9b079db9ad0e580 - keep this +// tag aligned with whatever milestone react-native-webgpu's Package.swift +// pins (its dawnReleaseTag fatalError check enforces the match at build time). const DAWN_CONFIG = { - releaseTag: "dawn-chrome-m150", + releaseTag: "dawn-chrome-m154", baseUrl: "https://github.com/wcandillon/react-native-webgpu/releases/download", checksums: { - android: "dee507d4fe66b57f6d33c0dac8cfd1b1263fcd9a8997bfebf936b62341580e60", - apple: "5bacd90c56aa3144d8ba74ac2d769d28b28ebf99c67a4959185c7181d8aeaf31", + android: "6fe8766dc3711e1e41e8b9d919fadd83f0e364945e66c01f49f316f4a3d96b1f", + apple: "896575ffbc99610198a83d061f8c5a2789139b7f16c669fbf3a9f7a7ac9be123", }, } as const; @@ -220,9 +216,10 @@ const downloadAndExtract = async ( const downloadAndExtractZip = async ( assetName: string, destDir: string, - expectedChecksum: string + expectedChecksum: string, + urlOverride?: string ): Promise => { - const url = getDownloadUrl(assetName); + const url = urlOverride ?? getDownloadUrl(assetName); const tempFile = path.join(LIBS_DIR, `${assetName}.tmp`); console.log(` Downloading ${assetName}...`); @@ -393,10 +390,12 @@ const downloadDawnLibs = async (): Promise => { rmSync(androidTempDir, { recursive: true, force: true }); // Apple: one xcframework carrying ios-device, ios-simulator and macos - // slices; the podspec vendors it from both platform dirs - const appleAsset = `dawn-apple-${DAWN_CONFIG.releaseTag}.xcframework.tar.gz`; + // slices; the podspec vendors it from both platform dirs. Published as a + // .zip (not .tar.gz) since it's the same SPM-compatible artifact + // react-native-webgpu's Package.swift binaryTarget links. + const appleAsset = `dawn-apple-${DAWN_CONFIG.releaseTag}.xcframework.zip`; const appleTempDir = path.join(LIBS_DIR, "dawn-apple-temp"); - await downloadAndExtract( + await downloadAndExtractZip( appleAsset, appleTempDir, DAWN_CONFIG.checksums.apple, diff --git a/packages/skia/scripts/skia-configuration.ts b/packages/skia/scripts/skia-configuration.ts index ccbb9de98a..f7941cb9e1 100644 --- a/packages/skia/scripts/skia-configuration.ts +++ b/packages/skia/scripts/skia-configuration.ts @@ -502,6 +502,12 @@ export const copyHeaders = () => { "../../externals/skia/third_party/externals/dawn/include", "./cpp/dawn/include" ); + // Dawn's cmake build (as of the Dawn revision pinned at chrome/m154) + // also generates a webgpu_upstream/ copy of webgpu_cpp.h and friends + // under its own path. Nothing in this repo or react-native-webgpu + // includes from webgpu_upstream/, and leaving it in trips the + // duplicate-header check below (same basenames as dawn/ and webgpu/). + fileOps.rm("./cpp/dawn/include/webgpu_upstream"); console.log(" - Fixing WebGPU header references..."); // Fix WebGPU header references From 648a39940e8cc2fe5f1d1f6fec172d6a98740d6d Mon Sep 17 00:00:00 2001 From: William Candillon Date: Sat, 12 Sep 2026 14:50:47 +0200 Subject: [PATCH 3/3] :wrench: --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 66a508ee5c..caf2bf8a17 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,7 @@ [submodule "externals/skia"] path = externals/skia url = https://chromium.googlesource.com/skia/ - branch = chrome/m152 + branch = chrome/m154 [submodule "externals/depot_tools"] path = externals/depot_tools url = https://chromium.googlesource.com/chromium/tools/depot_tools.git