ci: put ccache in front of the Hermes build - #439
Open
kraenhansen wants to merge 2 commits into
Open
Conversation
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.
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.
This was referenced Aug 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hermes is the iOS build. Everything else is rounding error.
Measured from the job logs of run 31691647982:
Build test app[RN] [1] Build Hermesc[RN] [2] Build HermesBuild test appstepIt is not hidden concurrency: no
CompileCorSwiftCompiletask appears anywhere in the 13m35s[2] Build Hermeswindow — just ninja progress — and all 54CompileCtasks in the entire build land in the final 66 seconds. Hermes serialises the build.And ccache never saw any of it.
C_COMPILER_LAUNCHERis an Xcode build setting, whereas Hermes is built by CMake from a script phase, so the two never meet. That job logged 549 ccache calls in total, of which only 68 were cacheable — against 2190 calls / 1082 cacheable on a build that compiles React Native itself.Approach
build-hermes-xcode.shhard-codes its CMake flags and offers no hook for extra arguments, but it does not sanitise the environment — and CMake readsCMAKE_TOOLCHAIN_FILEfrom there. So a generated toolchain file settingCMAKE_C_COMPILER_LAUNCHER/CMAKE_CXX_COMPILER_LAUNCHERis enough to put ccache in front of Hermes' compiler without patching React Native.Verified locally before pushing: with
CMAKE_TOOLCHAIN_FILEpresent only in the environment, CMake applies the toolchain and the launcher reaches the compile rule.The ccache ceiling also goes from 3G to 6G, since Hermes is far larger than anything cached here so far.
Known limit
[RN] [1] Build Hermescis out of reach. It runs its CMake underenv -iwith onlyPATHandSDKROOT, so no environment-based injection can reach it and it keeps costing its 3m40s. Reaching that one would need a change in React Native itself.What this does not do
The bigger prize is not compiling Hermes at all. React Native supports it —
HERMES_ENGINE_TARBALL_PATHselectsLOCAL_PREBUILT_TARBALLand the script phases then do not run — buthermes_source_type()checksoverride_hermes_dir_envvar_defined()first, and that override comes from this repo's Podfile integration rather than from CI. So consuming a prebuilt Hermes is a change to how the library vendors Hermes, affecting consumers and not just this workflow. Deliberately left for a separate PR.Test plan
Test app (iOS)passes (label-gated onApple 🍎, added)[2] Build Hermesphase drop sharplyGenerated by Claude Code