From b28aa4f7664e8124c3f502742cf1a4fc5ef2932f Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Thu, 27 Aug 2026 23:16:19 -0700 Subject: [PATCH 1/2] Add stable public CallInvoker C++ entry point (#58159) Summary: Add `` as the canonical public C++ entry point for `CallInvoker`, `NativeMethodCallInvoker`, and `SchedulerPriority`. Guard direct leaf-header inclusion for strict API consumers while preserving existing React Native builds and legacy include paths. Export and stage the umbrella consistently through Buck, CMake, Android Prefab, CocoaPods, and the Apple prebuilt-header inventory. SwiftPM needs no change, since its header mapping for this module already preserves the directory structure. The `ios-prebuild` header configuration needs an explicit entry here: the generic podspec parser only reads the first `header_dir`, so it would have flattened the umbrella into `ReactCommon/` and collided with the existing leaf header of the same basename. Changelog: [Internal] Reviewed By: cipolleschi Differential Revision: D116921026 --- .../ReactAndroid/build.gradle.kts | 1 + .../ReactCommon/callinvoker/CMakeLists.txt | 1 + .../callinvoker/React-callinvoker.podspec | 16 +++++++++++ .../callinvoker/React/CallInvoker.h | 27 +++++++++++++++++++ .../callinvoker/ReactCommon/CallInvoker.h | 2 ++ .../ReactCommon/SchedulerPriority.h | 2 ++ .../scripts/ios-prebuild/headers-config.js | 13 +++++++++ 7 files changed, 62 insertions(+) create mode 100644 packages/react-native/ReactCommon/callinvoker/React/CallInvoker.h diff --git a/packages/react-native/ReactAndroid/build.gradle.kts b/packages/react-native/ReactAndroid/build.gradle.kts index 3385ae79cfde..fd146f8025e8 100644 --- a/packages/react-native/ReactAndroid/build.gradle.kts +++ b/packages/react-native/ReactAndroid/build.gradle.kts @@ -233,6 +233,7 @@ val preparePrefab by Pair(File(buildDir, "third-party-ndk/folly/").absolutePath, ""), Pair(File(buildDir, "third-party-ndk/glog/exported/").absolutePath, ""), Pair("../ReactCommon/callinvoker/", ""), + Pair("../ReactCommon/callinvoker/React/", "React/"), Pair("../ReactCommon/cxxreact/", "cxxreact/"), // Exported because the public cxxreact/ErrorUtils.h includes it Pair("../ReactCommon/jserrorhandler/", "jserrorhandler/"), diff --git a/packages/react-native/ReactCommon/callinvoker/CMakeLists.txt b/packages/react-native/ReactCommon/callinvoker/CMakeLists.txt index 5ad2b05c563a..9e03b804fdc7 100644 --- a/packages/react-native/ReactCommon/callinvoker/CMakeLists.txt +++ b/packages/react-native/ReactCommon/callinvoker/CMakeLists.txt @@ -11,5 +11,6 @@ include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake) add_library(callinvoker INTERFACE) target_include_directories(callinvoker INTERFACE .) +target_link_libraries(callinvoker INTERFACE react_cxxstableapi) target_compile_reactnative_options(callinvoker INTERFACE) target_compile_options(callinvoker INTERFACE -Wpedantic) diff --git a/packages/react-native/ReactCommon/callinvoker/React-callinvoker.podspec b/packages/react-native/ReactCommon/callinvoker/React-callinvoker.podspec index 6290d9867e6d..aac5db20478e 100644 --- a/packages/react-native/ReactCommon/callinvoker/React-callinvoker.podspec +++ b/packages/react-native/ReactCommon/callinvoker/React-callinvoker.podspec @@ -16,6 +16,12 @@ else source[:tag] = "v#{version}" end +header_search_paths = [] + +if ENV['USE_FRAMEWORKS'] + header_search_paths << "\"$(PODS_TARGET_SRCROOT)/..\"" # ReactCommon, for +end + Pod::Spec.new do |s| s.name = "React-callinvoker" s.version = version @@ -26,7 +32,17 @@ Pod::Spec.new do |s| s.platforms = min_supported_versions s.source = source s.source_files = podspec_sources("**/*.{cpp,h}", "**/*.h") + s.exclude_files = "React" + s.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => header_search_paths.join(' ') } s.header_dir = "ReactCommon" + s.subspec "CallInvokerUmbrella" do |ss| + ss.source_files = "React/*.h" + ss.header_dir = "React" + ss.header_mappings_dir = "React" + end + + s.dependency "React-cxxstableapi" + mark_as_react_native_build(s) end diff --git a/packages/react-native/ReactCommon/callinvoker/React/CallInvoker.h b/packages/react-native/ReactCommon/callinvoker/React/CallInvoker.h new file mode 100644 index 000000000000..e8bf92e95dae --- /dev/null +++ b/packages/react-native/ReactCommon/callinvoker/React/CallInvoker.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +// ============================================================================= +// Umbrella header for the `callinvoker` module - public entry point. +// +// #include +// +// Re-exports the module's public interface headers. React Native's own code +// should keep using the fine-grained `` includes; only outside +// consumers use this umbrella. +// ============================================================================= + +// Marks that the following headers are pulled in through the umbrella, so their +// shared guard () accepts them. +#define RN_UMBRELLA_CONTEXT + +#include +#include + +#undef RN_UMBRELLA_CONTEXT diff --git a/packages/react-native/ReactCommon/callinvoker/ReactCommon/CallInvoker.h b/packages/react-native/ReactCommon/callinvoker/ReactCommon/CallInvoker.h index 452493c27e3e..1c6fc0302dc9 100644 --- a/packages/react-native/ReactCommon/callinvoker/ReactCommon/CallInvoker.h +++ b/packages/react-native/ReactCommon/callinvoker/ReactCommon/CallInvoker.h @@ -7,6 +7,8 @@ #pragma once +#include + #include "SchedulerPriority.h" #include diff --git a/packages/react-native/ReactCommon/callinvoker/ReactCommon/SchedulerPriority.h b/packages/react-native/ReactCommon/callinvoker/ReactCommon/SchedulerPriority.h index 2027d95c7668..44b8dcc973bb 100644 --- a/packages/react-native/ReactCommon/callinvoker/ReactCommon/SchedulerPriority.h +++ b/packages/react-native/ReactCommon/callinvoker/ReactCommon/SchedulerPriority.h @@ -7,6 +7,8 @@ #pragma once +#include + namespace facebook::react { enum class SchedulerPriority : int { diff --git a/packages/react-native/scripts/ios-prebuild/headers-config.js b/packages/react-native/scripts/ios-prebuild/headers-config.js index 8689316ff74c..e7ceae9dc6f9 100644 --- a/packages/react-native/scripts/ios-prebuild/headers-config.js +++ b/packages/react-native/scripts/ios-prebuild/headers-config.js @@ -513,6 +513,19 @@ const PodspecExceptions /*: {[key: string]: PodSpecConfiguration} */ = { }, ], }, + 'ReactCommon/callinvoker/React-callinvoker.podspec': { + name: 'React-callinvoker', + headerPatterns: ['**/*.h'], + excludePatterns: ['React/**'], + headerDir: 'ReactCommon', + subSpecs: [ + { + name: 'CallInvokerUmbrella', + headerPatterns: ['React/*.h'], + headerDir: 'React', + }, + ], + }, 'React-Core.podspec': { name: 'React-Core', headerPatterns: [], From abd40671ea5ca3486f8a4ccd25cc860c1f3df0b5 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Thu, 27 Aug 2026 23:16:19 -0700 Subject: [PATCH 2/2] Add stable public Debug C++ entry point (#58160) Summary: Add `` as the canonical public C++ entry point for React Native's debug assertion macros: `react_native_assert`, `react_native_expect`, and the `REACT_NATIVE_DEBUG` / `REACT_NATIVE_PRODUCTION` flags. Guard direct leaf-header inclusion for strict API consumers while preserving existing React Native builds and legacy include paths. Classify the `redbox/` headers as private instead. They live in namespace `unstable_redbox`, have no consumers outside React Native, and are reachable only from three dev-menu `.mm` files, so they are fenced off with the private guard and deliberately left out of the umbrella. Changelog: [Internal] Reviewed By: cipolleschi Differential Revision: D116930195 --- .../ReactAndroid/build.gradle.kts | 2 ++ .../ReactCommon/react/debug/CMakeLists.txt | 2 +- .../react/debug/React-debug.podspec | 17 +++++++++- .../ReactCommon/react/debug/React/Debug.h | 31 +++++++++++++++++++ .../ReactCommon/react/debug/flags.h | 2 ++ .../react/debug/react_native_assert.h | 2 ++ .../react/debug/react_native_expect.h | 2 ++ .../react/debug/redbox/AnsiParser.h | 2 ++ .../react/debug/redbox/JscSafeUrl.h | 2 ++ .../react/debug/redbox/RedBoxErrorParser.h | 2 ++ .../scripts/ios-prebuild/headers-config.js | 17 ++++++++++ 11 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 packages/react-native/ReactCommon/react/debug/React/Debug.h diff --git a/packages/react-native/ReactAndroid/build.gradle.kts b/packages/react-native/ReactAndroid/build.gradle.kts index fd146f8025e8..314fc497d781 100644 --- a/packages/react-native/ReactAndroid/build.gradle.kts +++ b/packages/react-native/ReactAndroid/build.gradle.kts @@ -144,6 +144,7 @@ val preparePrefab by Pair("../ReactCommon/react/renderer/css/", "react/renderer/css/"), // react_debug Pair("../ReactCommon/react/debug/", "react/debug/"), + Pair("../ReactCommon/react/debug/React/", "React/"), // react_renderer_debug Pair("../ReactCommon/react/renderer/debug/", "react/renderer/debug/"), // react_renderer_graphics @@ -265,6 +266,7 @@ val preparePrefab by Pair("../ReactCommon/react/renderer/telemetry/", "react/renderer/telemetry/"), Pair("../ReactCommon/react/renderer/uimanager/", "react/renderer/uimanager/"), Pair("../ReactCommon/react/debug/", "react/debug/"), + Pair("../ReactCommon/react/debug/React/", "React/"), Pair("../ReactCommon/react/cxxstableapi/", "react/cxxstableapi/"), Pair("../ReactCommon/react/utils/", "react/utils/"), Pair("src/main/jni/react/jni", "react/jni/"), diff --git a/packages/react-native/ReactCommon/react/debug/CMakeLists.txt b/packages/react-native/ReactCommon/react/debug/CMakeLists.txt index 5cbe24ff6029..9e0376561144 100644 --- a/packages/react-native/ReactCommon/react/debug/CMakeLists.txt +++ b/packages/react-native/ReactCommon/react/debug/CMakeLists.txt @@ -14,7 +14,7 @@ add_library(react_debug OBJECT ${react_debug_SRC} ${react_debug_redbox_SRC}) target_include_directories(react_debug PUBLIC ${REACT_COMMON_DIR}) -target_link_libraries(react_debug folly_runtime) +target_link_libraries(react_debug folly_runtime react_cxxstableapi) if(ANDROID) target_link_libraries(react_debug log) diff --git a/packages/react-native/ReactCommon/react/debug/React-debug.podspec b/packages/react-native/ReactCommon/react/debug/React-debug.podspec index b2ec229a73cf..591f5798504b 100644 --- a/packages/react-native/ReactCommon/react/debug/React-debug.podspec +++ b/packages/react-native/ReactCommon/react/debug/React-debug.podspec @@ -16,6 +16,12 @@ else source[:tag] = "v#{version}" end +header_search_paths = [] + +if ENV['USE_FRAMEWORKS'] + header_search_paths << "\"$(PODS_TARGET_SRCROOT)/../..\"" # ReactCommon, for +end + Pod::Spec.new do |s| s.name = "React-debug" s.version = version @@ -28,15 +34,24 @@ Pod::Spec.new do |s| s.source_files = podspec_sources("*.{cpp,h}", "*.h") s.header_dir = "react/debug" s.pod_target_xcconfig = { "CLANG_CXX_LANGUAGE_STANDARD" => rct_cxx_language_standard(), - "DEFINES_MODULE" => "YES" } + "DEFINES_MODULE" => "YES", + "HEADER_SEARCH_PATHS" => header_search_paths.join(' ') } resolve_use_frameworks(s, header_mappings_dir: "../..", module_name: "React_debug") + s.subspec "DebugUmbrella" do |ss| + ss.source_files = "React/*.h" + ss.header_dir = "React" + ss.header_mappings_dir = "React" + end + s.subspec "redbox" do |ss| ss.source_files = podspec_sources("redbox/*.{cpp,h}", "redbox/*.h") ss.exclude_files = "redbox/tests/**/*.{cpp,h}" ss.header_dir = "react/debug/redbox" end + s.dependency "React-cxxstableapi" + mark_as_react_native_build(s) end diff --git a/packages/react-native/ReactCommon/react/debug/React/Debug.h b/packages/react-native/ReactCommon/react/debug/React/Debug.h new file mode 100644 index 000000000000..8ba388a6e3a4 --- /dev/null +++ b/packages/react-native/ReactCommon/react/debug/React/Debug.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +// ============================================================================= +// Umbrella header for the `react/debug` module - public entry point. +// +// #include +// +// Re-exports the module's public interface headers. React Native's own code +// should keep using the fine-grained `` includes; only outside +// consumers use this umbrella. +// +// The `redbox/` headers are deliberately absent: they are implementation +// details of the dev-menu red box and carry no stability guarantee. +// ============================================================================= + +// Marks that the following headers are pulled in through the umbrella, so their +// shared guard () accepts them. +#define RN_UMBRELLA_CONTEXT + +#include +#include +#include + +#undef RN_UMBRELLA_CONTEXT diff --git a/packages/react-native/ReactCommon/react/debug/flags.h b/packages/react-native/ReactCommon/react/debug/flags.h index 1ccc1a2817df..61c107c455ca 100644 --- a/packages/react-native/ReactCommon/react/debug/flags.h +++ b/packages/react-native/ReactCommon/react/debug/flags.h @@ -7,6 +7,8 @@ #pragma once +#include + // // Preprocessor flags which control whether code meant for debugging the // internals of React Native is included in the build. E.g. debug assertions. diff --git a/packages/react-native/ReactCommon/react/debug/react_native_assert.h b/packages/react-native/ReactCommon/react/debug/react_native_assert.h index d209e0041bb8..70c53aa414e9 100644 --- a/packages/react-native/ReactCommon/react/debug/react_native_assert.h +++ b/packages/react-native/ReactCommon/react/debug/react_native_assert.h @@ -20,6 +20,8 @@ #pragma once +#include + #include "flags.h" #undef react_native_assert diff --git a/packages/react-native/ReactCommon/react/debug/react_native_expect.h b/packages/react-native/ReactCommon/react/debug/react_native_expect.h index cfc4d66f8da8..18cf5d242955 100644 --- a/packages/react-native/ReactCommon/react/debug/react_native_expect.h +++ b/packages/react-native/ReactCommon/react/debug/react_native_expect.h @@ -22,6 +22,8 @@ #pragma once +#include + #include "flags.h" #undef react_native_expect diff --git a/packages/react-native/ReactCommon/react/debug/redbox/AnsiParser.h b/packages/react-native/ReactCommon/react/debug/redbox/AnsiParser.h index 89f2aa8eda26..1211132fad7a 100644 --- a/packages/react-native/ReactCommon/react/debug/redbox/AnsiParser.h +++ b/packages/react-native/ReactCommon/react/debug/redbox/AnsiParser.h @@ -7,6 +7,8 @@ #pragma once +#include + #include #include #include diff --git a/packages/react-native/ReactCommon/react/debug/redbox/JscSafeUrl.h b/packages/react-native/ReactCommon/react/debug/redbox/JscSafeUrl.h index 39417d1b06b2..7d29d6e8599c 100644 --- a/packages/react-native/ReactCommon/react/debug/redbox/JscSafeUrl.h +++ b/packages/react-native/ReactCommon/react/debug/redbox/JscSafeUrl.h @@ -7,6 +7,8 @@ #pragma once +#include + #include #include diff --git a/packages/react-native/ReactCommon/react/debug/redbox/RedBoxErrorParser.h b/packages/react-native/ReactCommon/react/debug/redbox/RedBoxErrorParser.h index b8aaf6d85b3b..dc8deb5136ff 100644 --- a/packages/react-native/ReactCommon/react/debug/redbox/RedBoxErrorParser.h +++ b/packages/react-native/ReactCommon/react/debug/redbox/RedBoxErrorParser.h @@ -7,6 +7,8 @@ #pragma once +#include + #include #include diff --git a/packages/react-native/scripts/ios-prebuild/headers-config.js b/packages/react-native/scripts/ios-prebuild/headers-config.js index e7ceae9dc6f9..86f0430e842c 100644 --- a/packages/react-native/scripts/ios-prebuild/headers-config.js +++ b/packages/react-native/scripts/ios-prebuild/headers-config.js @@ -526,6 +526,23 @@ const PodspecExceptions /*: {[key: string]: PodSpecConfiguration} */ = { }, ], }, + 'ReactCommon/react/debug/React-debug.podspec': { + name: 'React-debug', + headerPatterns: ['*.h'], + headerDir: 'react/debug', + subSpecs: [ + { + name: 'DebugUmbrella', + headerPatterns: ['React/*.h'], + headerDir: 'React', + }, + { + name: 'redbox', + headerPatterns: ['redbox/*.h'], + headerDir: 'react/debug/redbox', + }, + ], + }, 'React-Core.podspec': { name: 'React-Core', headerPatterns: [],