feat: add support for dynamic frameworks#2943
Open
Saadnajmi wants to merge 11 commits into
Open
Conversation
The Folly `SanitizeLeak.cpp` file provides implementations for `annotate_object_leaked_impl`, `annotate_object_collected_impl`, and `annotate_object_count_leaked_uncollected_impl`. These symbols are declared in `SanitizeLeak.h` and referenced by `small_vector.h`, but the .cpp was not listed in the podspec's source_files. With static libraries this is benign — the linker skips unreferenced symbols. With `USE_FRAMEWORKS=dynamic` the linker must resolve every symbol, causing an "undefined symbols for architecture x86_64" error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a linkage: [static, dynamic] dimension to the RNTester build matrix so macOS, iOS and visionOS are each exercised with USE_FRAMEWORKS=dynamic in addition to the default static libraries. USE_FRAMEWORKS is unset for static builds so the Podfile keeps its default linkage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Several fixes that let the multi-platform (iOS/macOS/visionOS) RNTester workspace get much further building with USE_FRAMEWORKS=dynamic: - Set SUPPORTED_PLATFORMS per pod target from its SDKROOT. Without it, the per-platform framework targets (hermes.framework etc.) all look like candidates for a given -framework flag, so Xcode pulls the wrong ones in and hermes-engine's identical script-phase outputs collide with 'Multiple commands produce'. - Set $RN_PLATFORMS before podspec evaluation (not in post_install), so add_dependency() generates per-platform-suffixed framework header search paths (React-debug-iOS vs React-debug-macOS). Previously the suffix was missing, breaking headers like react/debug/react_native_assert.h. - Generate suffixed framework header search paths in the React-cxxreact, ReactCommon and React-NativeModulesApple podspecs (also corrects a React_featureflags.framework path that pointed at the React-debug dir). - Expose react/renderer/components/view/platform/macos on React-Fabric's framework header search paths; the fork compiles those macOS view files on all platforms and they include react/renderer/components/view/KeyEvent.h. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Dynamic frameworks are a work in progress on this fork, so let those matrix jobs report status without failing the build (matching upstream's continue-on-error dynamic-frameworks job). Static builds stay required. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
RCTUIKit lives in the separate React-RCTUIKit pod (module React_RCTUIKit) but is imported everywhere as <React/RCTUIKit.h>. In static builds both React-Core and React-RCTUIKit use header_dir "React", so their headers pool into one Pods/Headers/Public/React dir and the include resolves. Under use_frameworks! each pod builds its own framework module, that shared dir vanishes, and <React/RCTUIKit.h> can no longer resolve. Make React_RCTUIKit RCTUIKit's canonical namespace and re-export it from React-Core as modular aliases: - React-RCTUIKit.podspec header_dir "React" -> "React_RCTUIKit". - RCTUIKit's internal sibling imports <React/RCTUI*.h> -> <React_RCTUIKit/...> so the pod references its own module (breaks a React -> React_RCTUIKit -> React module cycle under frameworks). - Add React-Core forwarding headers (React/RCTUIKitForwarding/*.h) that #import <React_RCTUIKit/...>. Because React_RCTUIKit is a real module, these are modular includes, so <React/RCTUIKit.h> resolves without the non-modular-include-in-framework-module error a loose header would hit. All ~195 existing <React/RCTUIKit.h> imports keep working unchanged. - SwiftPM prebuild: link React/RCTUIKit into React_RCTUIKit as well (in addition to React) so the new <React_RCTUIKit/...> imports resolve; the forwarding dir is excluded from the reactCore SPM target. Verified: static RNTester iOS build passes; dynamic build resolves RCTUIKit with zero cyclic / non-modular / not-found errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move continue-on-error from the job to the pod-install and build steps for dynamic linkage. The jobs still run for coverage (real result visible in the step logs), but a dynamic build failure no longer shows the check as failed. Static builds remain strict and required. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep React_RCTUIKit as RCTUIKit's canonical module, but replace the 16 React-Core forwarding headers with only the two compatibility entry points used outside the module: - <React/RCTUIKit.h>, the public umbrella used throughout RN and by major third-party packages (WebView, Gesture Handler, SVG, Skia, Expo, etc.). - <React/RCTPlatformDisplayLink.h>, used directly by Reanimated/Worklets for their macOS display-link implementation. RCTUIKit's implementation now uses local sibling imports, avoiding the React -> React_RCTUIKit -> React module cycle without requiring a second SwiftPM header alias. This removes the RCTUIKitForwarding directory and reverts the no-longer-needed Package.swift/setup.js changes. Verified: static RNTester iOS build succeeds; dynamic build has zero RCTUIKit not-found, cyclic-module, or non-modular-header errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move the UIKit/AppKit compatibility layer and its podspec from React/ into ReactApple/Libraries/RCTUIKit, matching ReactApple's ownership convention for Apple-framework libraries. Preserve the existing React-RCTUIKit pod and React_RCTUIKit module names so this commit is path-only from a consumer's perspective. Update CocoaPods discovery, SwiftPM target path, prebuild header staging, React-Core exclusions, and macOS prebuild cache inputs. The two existing <React/...> compatibility headers remain in React-Core. Verified: static RNTester iOS build succeeds; dynamic build reports zero RCTUIKit missing-header, cyclic-module, or non-modular-header errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Rename the canonical CocoaPods and SwiftPM module from React_RCTUIKit to RCTUIKit, matching Apple framework casing and the new ReactApple ownership. Keep the React-RCTUIKit pod name unchanged for dependency compatibility. Update the two established React compatibility entry points to forward to <RCTUIKit/...>, and stage headers under both React (legacy) and RCTUIKit (canonical) in the prebuild header layout. Document the canonical import in the library README. Verified: static RNTester iOS build succeeds; dynamic builds expose RCTUIKit.framework/Headers/RCTUIKit.h with zero RCTUIKit missing-header, cyclic-module, or non-modular-header errors. Direct SwiftPM validation is deferred to required prebuild CI because local binary artifacts are absent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the broad ReactCommon podspec and shared CocoaPods utility changes from this PR. They restructured upstream-owned code to make the nonblocking dynamic canary progress further, but are not required for the core fixes. Keep the multi-platform framework workaround local to RNTester: declare RN_PLATFORMS before podspec evaluation and set SUPPORTED_PLATFORMS on generated pod targets in its post_install hook. This still prevents Hermes duplicate-output collisions without adding fork behavior to shared React Native CocoaPods code. Also add the required macOS diff tags to the Folly source addition, moved RCTUIKit podspec/README, RNTester block, and moved pod path. Verified: static RNTester iOS succeeds; dynamic has no duplicate-output or RCTUIKit missing/cyclic/non-modular errors (remaining gaps stay nonblocking). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Saadnajmi
commented
Jul 11, 2026
Saadnajmi
commented
Jul 11, 2026
After moving RCTUIKit out of the React target, excludedPaths matches upstream again and no longer needs a macOS diff tag. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.
Fixes #1969
Summary
Add RNTester coverage for
USE_FRAMEWORKS=dynamicand fix the first set of build issues it exposed.folly/memory/SanitizeLeak.cppin RCT-Folly. The declarations were already used by Folly headers, but the implementation was not part of the pod target.SUPPORTED_PLATFORMSon RNTester's generated pod targets. This keeps Xcode from selecting multiple platform variants of the same framework and avoids duplicate Hermes build outputs.The RNTester-specific workaround stays in
packages/rn-tester/Podfile; this PR does not change the shared ReactCommon podspecs or CocoaPods helpers.RCTUIKit
RCTUIKit now lives under
ReactApple/Libraries/RCTUIKit, alongside the other Apple-specific libraries. The CocoaPods package name remainsReact-RCTUIKit, while the canonical CocoaPods/SwiftPM module isRCTUIKit.The canonical import is:
The two existing imports used by React Native and downstream packages remain supported:
The latter is used by Reanimated/Worklets on macOS. Prebuild header staging exposes both the canonical and compatibility paths.
CI
RNTester now builds a static/dynamic linkage matrix for macOS, iOS, and visionOS across both architectures. Static builds remain required. Dynamic pod-install and build steps are nonblocking for now so they can act as a canary while the remaining framework issues are worked through.
Validation