Repository navigation
Commit 8bfa9dd
Fix Hermes Debug builds after installing another pod (#59159)
Summary:
A successful Release build followed by adding a new CocoaPods dependency can cause the next Debug build to fail with undefined Hermes debugger symbols, including `CDPDebugAPI::create` and `CDPAgent::create`.
The Release build installs the Release Hermes binary and records `Release` in `Pods/hermes-engine/.last_build_configuration`. When a subsequent `pod install` installs another pod, CocoaPods cleans the existing Hermes pod. The `Pre-built` subspec does not preserve the configuration marker, so the marker is removed while the Release framework remains on disk.
On the next Debug build, `replace_hermes_version.js` receives the correct `Debug` configuration but assumes that a missing marker means Hermes is already Debug. It skips replacement, leaving Debug React Native code to link against a Release Hermes binary that does not export the required debugger symbols.
This change:
- Adds `.last_build_configuration` to the `Pre-built` subspec's `preserve_paths`, so installing another pod does not discard the configuration recorded for the existing Hermes binary.
- Removes the assumption that a missing marker implies Debug. If the marker is absent, the replacement script extracts the requested configuration and writes its marker.
- Adds regression coverage for missing markers, configuration switches, fresh installations, and the existing matching-configuration fast path.
A matching marker still skips extraction. A fresh Debug installation without a marker now performs one initial extraction; subsequent builds with the same recorded configuration continue to skip it.
## Changelog:
[IOS] [FIXED] - Fix Hermes Debug link failures after installing another pod following a Release build.
Pull Request resolved: #59159
Test Plan:
### Environment
The failure was reproduced in RNTester on the unmodified main baseline `27e77216ef2557ccbf31a01067a44dc1dd2ec846`, using:
- Xcode 27.0 (`27A266a`), iPhoneOS SDK, arm64.
- Ruby 3.3.11, Bundler 2.5.22, CocoaPods 1.15.2.
- Node.js 22.22.3, prebuilt Hermes `260318099.0.2`, and `hermes-compiler` `260318099.0.4` selected by the repository's installation hook.
- Default RNTester CocoaPods integration, with `USE_FRAMEWORKS` unset.
Both the unmodified and patched versions were tested through complete Debug → Release → add a pod → Debug sequences. Each sequence used the same workspace and DerivedData directory throughout; the patched sequence started with fresh Pods and a separate empty DerivedData directory. JavaScript bundling was enabled. Signing was disabled with `CODE_SIGNING_ALLOWED=NO`; the app was not launched on a device.
### Reproduction on the unmodified baseline
1. Start with a fresh checkout of the baseline above, without Masonry in RNTester's Podfile. Prepare the repository and RNTester dependencies from the repository root:
```bash
yarn install
yarn --cwd packages/react-native-codegen build
cd packages/rn-tester
bundle install
bundle exec pod update hermes-engine --no-repo-update
```
On this specific baseline, the checked-in RNTester lockfile references an older Hermes version than the local podspec. The final command aligns that dependency once, matching the repository's RNTester CI setup. This is environment preparation; the dependency installation that triggers the bug below uses ordinary `pod install`.
2. Define the build command in the same terminal. The directory is inside RNTester and is shared by Debug and Release:
```bash
REPRO_DIR="$PWD/build/hermes-marker-repro-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$REPRO_DIR"
build_rntester() {
xcodebuild \
-workspace RNTesterPods.xcworkspace \
-scheme RNTester \
-configuration "$1" \
-sdk iphoneos \
-destination 'generic/platform=iOS' \
-derivedDataPath "$REPRO_DIR/DerivedData" \
-jobs 6 \
CODE_SIGNING_ALLOWED=NO \
build
}
```
3. Build Debug to establish a working baseline:
```bash
build_rntester Debug
```
Result: `BUILD SUCCEEDED`.
4. Build Release to simulate a release build:
```bash
build_rntester Release
```
Result: `BUILD SUCCEEDED`. The normal Xcode build phase switches Hermes to Release and writes the `Release` marker.
5. Add a new third-party dependency inside the existing RNTester target in `packages/rn-tester/Podfile`:
```ruby
target 'RNTester' do
pods('RNTester')
pod 'Masonry', '1.1.0'
end
```
Masonry is a published pod used only to trigger a normal new-pod installation in this reproduction. You can replace it with any other compatible pod that is not already installed in the project.
6. Install the dependency, retaining the existing Pods and DerivedData directories:
```bash
bundle exec pod install
```
Result: installation succeeds and reports `Installing Masonry (1.1.0)`. The Hermes configuration marker is now absent, but the installed arm64 Hermes binary still matches the Release archive.
7. Build Debug again:
```bash
build_rntester Debug
```
Result: `BUILD FAILED`, with `xcodebuild` exiting with code 65. The failing link is RNTester's `RNTester.debug.dylib`; unresolved references originate from `libReact-hermes.a`.
The Hermes build phase reports:
```text
No previous build detected, but Debug Configuration. No need to replace Hermes engine
```
The linker reports undefined arm64 symbols, including:
```text
Reviewed By: fabriziocucci
Differential Revision: D125847848
Pulled By: cipolleschi
fbshipit-source-id: 7a9cc0e9fbadfcc67c62a4f734b459acc303bd351 parent 27e7721 commit 8bfa9dd
3 files changed
Lines changed: 123 additions & 9 deletions
File tree
- packages/react-native
- scripts/__tests__
- sdks/hermes-engine
- utils
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
56 | 56 | | |
57 | 57 | | |
58 | 58 | | |
59 | | - | |
| 59 | + | |
| 60 | + | |
60 | 61 | | |
61 | 62 | | |
62 | 63 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | | - | |
49 | | - | |
50 | | - | |
51 | | - | |
52 | | - | |
| 45 | + | |
| 46 | + | |
53 | 47 | | |
54 | 48 | | |
55 | 49 | | |
| |||
0 commit comments