From 2d227efc613331cb373e34e2e1cf409df23e2fff Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 13 Aug 2026 11:57:46 +0000 Subject: [PATCH 1/2] ci: put ccache in front of the Hermes build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hermes dominates the iOS build. In run 31691647982 the build step took 18m58s, of which '[RN] [1] Build Hermesc' was 3m40s and '[RN] [2] Build Hermes' 13m35s — 17m15s, or 91%. It is not hidden concurrency either: no CompileC task appears during that window, and all 54 of them land in the final 66 seconds. Hermes serialises the build. Ccache never saw any of it. C_COMPILER_LAUNCHER is an Xcode build setting, while Hermes is built by CMake from a script phase, so the two never meet — ccache logged 549 calls for that whole job, of which only 68 were cacheable. React Native hard-codes the CMake flags in build-hermes-xcode.sh with no hook for extra arguments, but it does not sanitise the environment, and CMake reads CMAKE_TOOLCHAIN_FILE from there (verified locally: the toolchain is applied and the launcher reaches the compile rule). So point it at a generated toolchain file that sets CMAKE_C/CXX_COMPILER_LAUNCHER, which needs no patching of React Native. '[1] Build Hermesc' is out of reach: it runs its CMake under `env -i` with only PATH and SDKROOT, so it keeps costing its 3m40s. Also raises the ccache ceiling to 6G, since Hermes is much larger than anything cached so far. --- .github/workflows/check.yml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 53cdb585..d15e296c 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -225,8 +225,9 @@ jobs: key: ${{ github.job }}-${{ runner.os }} # The action defaults to 500M, which a from-source React Native build # fills mid-build: it evicted 88 times in one run, discarding most of - # what it had just cached. - max-size: 3G + # what it had just cached. Raised again to also hold Hermes, which is + # by far the largest thing compiled here. + max-size: 6G - run: rustup target add aarch64-apple-ios-sim x86_64-apple-ios - run: pnpm install - run: pnpm run bootstrap @@ -238,12 +239,26 @@ jobs: # to it) and so no longer does now that it runs as a compiler launcher. # Without this sloppiness Xcode's modules, PCH and index-store flags leave # ccache treating almost every compile as uncacheable. + # + # Hermes is built from source (the Node-API fork), from a CMake build that + # React Native drives in a script phase — so C_COMPILER_LAUNCHER, an Xcode + # build setting, never reaches it. It is the dominant cost of the build: + # 17m15s of an 18m58s build step in run 31691647982. CMake reads + # CMAKE_TOOLCHAIN_FILE from the environment, so a toolchain file is enough + # to put ccache in front of its compiler without patching React Native. + # Only '[RN] [2] Build Hermes' benefits; '[1] Build Hermesc' runs under + # `env -i` and cannot see this. - name: Tune ccache for Xcode run: | ccache --set-config sloppiness=clang_index_store,file_stat_matches,include_file_ctime,include_file_mtime,ivfsoverlay,pch_defines,modules,system_headers,time_macros ccache --set-config file_clone=true ccache --set-config depend_mode=true ccache --set-config inode_cache=true + cat > "$RUNNER_TEMP/hermes-ccache-toolchain.cmake" <> $GITHUB_ENV # Must precede `pod install`: react-native-test-app embeds the resources # declared in app.json when generating the workspace, skipping missing # ones, and the app would then expect a Metro dev server at runtime. From d806a0dda22a84bc34321fd653fa6b8757fb07dc Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 13 Aug 2026 12:03:18 +0000 Subject: [PATCH 2/2] ci: retrigger checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Apple 🍎 label landed after the run for 2d227ef started, so Test app (iOS) evaluated its label gate against a payload that did not yet have it and skipped. Workflow triggers on opened/synchronize/reopened, so labelling alone does not re-run it.