feat: add support for dynamic frameworks#2943
Draft
Saadnajmi wants to merge 6 commits into
Draft
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>
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
Improve support for building RNTester with dynamic frameworks (
USE_FRAMEWORKS=dynamic), and add CI coverage that exercises it without blocking (matching upstream).The core fix (folly)
Add
folly/memory/SanitizeLeak.cpptoRCT-Folly.podspec'ssource_files. The file ships in the Folly source tree (fetched by CocoaPods) but was never compiled, soannotate_object_leaked_impl/annotate_object_collected_impl(declared inSanitizeLeak.h, referenced fromsmall_vector.h) were undefined. With static libraries the linker drops them; with dynamic frameworks every symbol must resolve, so the build fails at link time. This is also an upstream bug — facebook/react-native marks itstest_ios_rntester_dynamic_frameworksjobcontinue-on-errorfor the same reason.RCTUIKit: give it its own module namespace
RCTUIKit lives in the separate
React-RCTUIKitpod (moduleReact_RCTUIKit) but is imported everywhere as<React/RCTUIKit.h>. In static builds both React-Core and React-RCTUIKit useheader_dir "React", so their headers pool into onePods/Headers/Public/Reactdir and the include resolves. Underuse_frameworks!each pod builds its own framework module, that shared dir vanishes, and<React/RCTUIKit.h>can't resolve.React-RCTUIKitnow usesheader_dir "React_RCTUIKit"; its internal sibling imports become<React_RCTUIKit/...>(which also breaks aReact → React_RCTUIKit → Reactmodule cycle under frameworks).<React/RCTUI*.h>forwarding headers that#import <React_RCTUIKit/...>— so all ~195 existing<React/RCTUIKit.h>imports keep working, with no consumer changes and no-Wnon-modular-includeerror.React_RCTUIKittoo (in addition toReact), so the new imports resolve there as well.Additional dynamic-frameworks build fixes
SUPPORTED_PLATFORMSper pod target (fromSDKROOT) — without it the per-platform framework targets collide with hermes-engine's "Multiple commands produce".$RN_PLATFORMSbefore podspec evaluation soadd_dependency()generates per-platform-suffixed framework header search paths (React-debug-iOSvsReact-debug-macOS).React_featureflags.frameworkpath that pointed at theReact-debugdir).react/renderer/components/view/platform/macoson React-Fabric's framework header search paths (fork compiles those macOS view files on all platforms; they includeKeyEvent.h).CI
Add a
linkage: [static, dynamic]dimension to the RNTester build matrix (macOS/iOS/visionOS × oldarch/newarch). Dynamic-frameworks jobs arecontinue-on-error(upstream-aligned) — they report status without blocking; static builds stay required.Verified locally
Remaining (tracked, non-blocking on the dynamic canary)
A few dynamic-only header-search-path gaps (folly/dynamic.h, RCTFabricSurface, ComponentDescriptors) and a genuinely macOS issue (
HostPlatformViewEventEmitter.cppuses AppKit-onlyMouseEventtypes while compiling on iOS). These keep the dynamic jobs red, which is why they'recontinue-on-error.Test plan