fix(iOS): keep prebuilt Headers/ in place on a Debug/Release swap - #57814
Open
chrfalch wants to merge 1 commit into
Open
fix(iOS): keep prebuilt Headers/ in place on a Debug/Release swap#57814chrfalch wants to merge 1 commit into
chrfalch wants to merge 1 commit into
Conversation
An iOS Release build can fail in `PrecompileModule React` with seven `include of non-modular header inside framework module` errors, but only when the build follows a Debug/Release configuration switch (#57803). `replace-rncore-version.js` deleted and recreated `Pods/React-Core-prebuilt/Headers/` on a swap. That directory holds `module.modulemap`, which `rncore.rb` activates on every target through `-fmodule-map-file`. Nothing orders an unrelated target's dependency scan against this script phase, so a scan can run while the module map is missing; the React module is then precompiled without it and `<yoga/...>`, `<react/...>` and `<RCTDeprecation/...>` resolve non-modularly. Those headers never needed replacing. The prebuild compose job emits one set of ReactNativeHeaders for both configurations, so they are identical in the Debug and Release tarballs — only the compiled framework differs. Replace `React.xcframework` and nothing else. ## Changelog: [IOS] [FIXED] - Keep the prebuilt `Headers/` in place on a Debug/Release configuration switch so the React explicit module still resolves its module map Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
@fabriziocucci has imported this pull request. If you are a Meta employee, you can view this in D114735639. |
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.
Summary
Fixes #57803. An iOS Release build can fail in
PrecompileModule Reactwith seveninclude of non-modular header inside framework moduleerrors — but only when the build follows a Debug/Release configuration switch, and only when the project contains a pod target that does not depend on React.replace-rncore-version.jsdeleted and recreatedPods/React-Core-prebuilt/Headers/on a swap. That directory holdsmodule.modulemap, whichrncore.rbactivates on every target through-fmodule-map-file.A pod that depends on React has a target-dependency edge that orders its module scan behind
React-Core-prebuilt's script phase. A pod with no React dependency has no such edge, so its scan is free to run before the swap. TheReactmodule is then precompiled without the module map, and<yoga/...>,<react/...>and<RCTDeprecation/...>resolve textually and trip-Wnon-modular-include-in-framework-module.Those headers never needed replacing. The prebuild compose job emits one set of ReactNativeHeaders for both configurations, so they are identical in the Debug and Release tarballs — only the compiled framework differs. This replaces
React.xcframeworkand nothing else, so the module map stays put for the whole build and the ordering stops mattering.Changelog:
[IOS] [FIXED] - Keep the prebuilt
Headers/in place on a Debug/Release configuration switch so the React explicit module still resolves its module mapTest Plan
The premise, on the published 0.87.0-rc.3 artifacts (
ios-arm64_x86_64-simulator):ReactNativeHeaders…/Headers/module.modulemapReact.framework/Modules/module.modulemapReactNativeHeaders…/Headerstree (diff -rq)React.framework/Headerstree (diff -rq)The reproducer from #57803, on Xcode 26.3 with CocoaPods 1.15.2:
** BUILD SUCCEEDED **, 0 errorsThe swap still does its job in the passing build — it logs
Replacing React-Core-prebuilt/React.xcframework, and the installed binary is the Release one:A Release→Debug swap was verified the same way. Across a swap,
Headers/module.modulemapkeeps its inode whileReact.xcframeworkgets a new one.Isolating the precondition
On stock 0.87.0-rc.3, changing only the reproducer's
IndependentPod, and reading back which targets'ScanDependenciesran before the swap:IndependentPod.podspecIndependentPod+ spec.dependency 'React-Core'Adding the dependency was the only change — same Podfile declaration, same local
:pathpod, same source file importing onlyFoundation.Note this is an ordering race, not a structural guarantee: a project with no React-independent pod is very likely safe but not provably so, since a different job count or machine load could reorder scans. This PR removes the race rather than the ordering, so the precondition stops mattering either way.
Adds a unit test for the script (3 cases: correct framework installed, module map untouched, fail on a tarball with no
React.xcframework). The script needed arequire.main === moduleguard and one export to be importable.Note for the release crew
This is a candidate for 0.87.0-rc.4. #57803 reproduces on rc.2 and rc.3 and is not fixed by anything currently on
0.87-stable; I verified #57742 in particular does not address it.Exposure: a stock template app has no React-independent pod and passed here. Apps that pull a native SDK pod directly (Firebase, Sentry, analytics or networking libraries) or vendor a local utility pod are the exposed shape, including via transitive pods of an RN wrapper.
Not fixed here:
React.xcframeworkis still replaced mid-build, and Xcode's xcframework-extraction task is not ordered against this script phase either. No failure was observed from that, and closing it properly means installing both configurations side by side instead of mutating pod content during a build — too large for a release cut.🤖 Generated with Claude Code