From 179ff8e1bd51fb554fc8b5212df0ae9d394967a5 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Thu, 3 Sep 2026 01:16:01 -0700 Subject: [PATCH] Cover `react/featureflags` with Stable API guards (#58083) Summary: Classifies `react/featureflags:featureflags` as a public target under the C++ stable API three-tier visibility model and introduces the module umbrella `React/FeatureFlags.h` as its public entry point. This module's headers are generated, so the `UmbrellaGuard.h` include is added to the templates in `scripts/featureflags/templates/common-cxx/` rather than to the headers themselves. `ReactNativeFeatureFlagsOverridesOSSStable.h` is the module's one hand-written header and is edited directly. The umbrella is not generated, and re-exports all eight of the module's headers. The sibling `react/nativemodule/featureflags:featureflags` target is private under the same model. The guards are inert unless a consumer defines `RN_STRICT_API`, so there is no behavior change. Changelog: [General][Added] - Add `` umbrella header as the public entry point for `react/featureflags` Reviewed By: cortinico Differential Revision: D117172757 --- .../ReactAndroid/build.gradle.kts | 1 + .../react/featureflags/CMakeLists.txt | 3 +- .../featureflags/React-featureflags.podspec | 7 +++ .../react/featureflags/React/FeatureFlags.h | 44 +++++++++++++++++++ .../featureflags/ReactNativeFeatureFlags.h | 4 +- .../ReactNativeFeatureFlagsAccessor.h | 4 +- .../ReactNativeFeatureFlagsDefaults.h | 4 +- .../ReactNativeFeatureFlagsDynamicProvider.h | 4 +- ...eactNativeFeatureFlagsOverridesOSSCanary.h | 4 +- ...tiveFeatureFlagsOverridesOSSExperimental.h | 4 +- ...eactNativeFeatureFlagsOverridesOSSStable.h | 2 + .../ReactNativeFeatureFlagsProvider.h | 4 +- .../ReactNativeFeatureFlags.h-template.js | 2 + ...ctNativeFeatureFlagsAccessor.h-template.js | 2 + ...ctNativeFeatureFlagsDefaults.h-template.js | 2 + ...eFeatureFlagsDynamicProvider.h-template.js | 2 + ...tureFlagsOverridesOSS_Stage_.h-template.js | 2 + ...ctNativeFeatureFlagsProvider.h-template.js | 2 + .../scripts/ios-prebuild/headers-config.js | 17 +++++++ 19 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 packages/react-native/ReactCommon/react/featureflags/React/FeatureFlags.h diff --git a/packages/react-native/ReactAndroid/build.gradle.kts b/packages/react-native/ReactAndroid/build.gradle.kts index 3d04af49ff47..54f897845a71 100644 --- a/packages/react-native/ReactAndroid/build.gradle.kts +++ b/packages/react-native/ReactAndroid/build.gradle.kts @@ -115,6 +115,7 @@ val preparePrefab by Pair("../ReactCommon/cxxreact/", "cxxreact/"), // react_featureflags Pair("../ReactCommon/react/featureflags/", "react/featureflags/"), + Pair("../ReactCommon/react/featureflags/React/", "React/"), // react_devtoolsruntimesettings Pair( "../ReactCommon/react/devtoolsruntimesettings/", diff --git a/packages/react-native/ReactCommon/react/featureflags/CMakeLists.txt b/packages/react-native/ReactCommon/react/featureflags/CMakeLists.txt index 110b45d41b06..2b8876355d40 100644 --- a/packages/react-native/ReactCommon/react/featureflags/CMakeLists.txt +++ b/packages/react-native/ReactCommon/react/featureflags/CMakeLists.txt @@ -12,7 +12,8 @@ file(GLOB react_featureflags_SRC CONFIGURE_DEPENDS *.cpp) add_library(react_featureflags OBJECT ${react_featureflags_SRC}) target_include_directories(react_featureflags PUBLIC ${REACT_COMMON_DIR}) +target_include_directories(react_featureflags INTERFACE ${REACT_COMMON_DIR}/react/featureflags) -target_link_libraries(react_featureflags folly_runtime) +target_link_libraries(react_featureflags folly_runtime react_cxxstableapi) target_compile_reactnative_options(react_featureflags PRIVATE) target_compile_options(react_featureflags PRIVATE -Wpedantic) diff --git a/packages/react-native/ReactCommon/react/featureflags/React-featureflags.podspec b/packages/react-native/ReactCommon/react/featureflags/React-featureflags.podspec index 52806c37c732..722f327be12c 100644 --- a/packages/react-native/ReactCommon/react/featureflags/React-featureflags.podspec +++ b/packages/react-native/ReactCommon/react/featureflags/React-featureflags.podspec @@ -39,8 +39,15 @@ Pod::Spec.new do |s| resolve_use_frameworks(s, header_mappings_dir: "../..", module_name: "React_featureflags") + s.dependency "React-cxxstableapi" add_rn_third_party_dependencies(s) add_rncore_dependency(s) + s.subspec "featureflagsUmbrella" do |ss| + ss.source_files = "React/*.h" + ss.header_dir = "" + ss.header_mappings_dir = "." + end + mark_as_react_native_build(s) end diff --git a/packages/react-native/ReactCommon/react/featureflags/React/FeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/React/FeatureFlags.h new file mode 100644 index 000000000000..f7c0591441d5 --- /dev/null +++ b/packages/react-native/ReactCommon/react/featureflags/React/FeatureFlags.h @@ -0,0 +1,44 @@ +/* + * 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/featureflags` 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 headers below are generated from +// `scripts/featureflags/ReactNativeFeatureFlags.config.js`, but this file is +// not - keep it in sync by hand when the set of generated headers in +// `scripts/featureflags/generateCommonCxxModules.js` changes. +// ============================================================================= + +// Marks that the following headers are pulled in through the umbrella, so their +// shared guard () accepts them. The marker +// is saved and restored rather than defined and undefined: the scope ends at +// this block, so later *direct* includes in the same TU are still caught, and +// it nests inside an enclosing umbrella rather than disarming it. +#pragma push_macro("RN_UMBRELLA_CONTEXT") +#undef RN_UMBRELLA_CONTEXT +#define RN_UMBRELLA_CONTEXT 1 + +#include +#include +#include +#include +#include +#include +#include +#include + +#undef RN_UMBRELLA_CONTEXT +#pragma pop_macro("RN_UMBRELLA_CONTEXT") diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index 9fa600171dd6..9ae679bc6177 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<2d59cf5ea42847d6174fc433ba5a6fe4>> + * @generated SignedSource<<414b7a90eeecd2abe9849955131fb122>> */ /** @@ -19,6 +19,8 @@ #pragma once +#include + #include #include #include diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index 4f5d310ebe45..179a6cafc5a7 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<55f19e7a0d7fbbda3aa131a74909ec07>> + * @generated SignedSource<> */ /** @@ -19,6 +19,8 @@ #pragma once +#include + #include #include #include diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index 5e144a271817..7949c5b62064 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<8e00ed57e2faa8e13ae2eb58afd64962>> + * @generated SignedSource<<9e798b7ae2a2f26097359ca37fa99d04>> */ /** @@ -19,6 +19,8 @@ #pragma once +#include + #include namespace facebook::react { diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h index a969aad4ad05..eb90dd2d5145 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<9c0b6df9433a5696f5eacf47713b9040>> + * @generated SignedSource<<3429660cde44d793af0e86ff425b1094>> */ /** @@ -19,6 +19,8 @@ #pragma once +#include + #include #include diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSCanary.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSCanary.h index 0c2f36288d9e..03bc1b4e775d 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSCanary.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSCanary.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<70297dc6230d386e556c82860cbf9985>> + * @generated SignedSource<<650cb266846c66577dde6d7c7a703af1>> */ /** @@ -19,6 +19,8 @@ #pragma once +#include + #include namespace facebook::react { diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSExperimental.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSExperimental.h index dad6dca0ccaf..b19cab84e7d8 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSExperimental.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSExperimental.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<5c7271fe5fcdd90f61a5a07772b820e5>> */ /** @@ -19,6 +19,8 @@ #pragma once +#include + #include namespace facebook::react { diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSStable.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSStable.h index d60006ec86c3..b9585918ed3f 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSStable.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSStable.h @@ -7,6 +7,8 @@ #pragma once +#include + #include namespace facebook::react { diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index d7e20196f597..d4da63764a89 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<51d2bd8d3e88e7848039f845c1709a39>> + * @generated SignedSource<<281f4bad9056734eec71185a3fdd6483>> */ /** @@ -19,6 +19,8 @@ #pragma once +#include + namespace facebook::react { class ReactNativeFeatureFlagsProvider { diff --git a/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlags.h-template.js b/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlags.h-template.js index 9fa9639abffd..299d78dae172 100644 --- a/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlags.h-template.js +++ b/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlags.h-template.js @@ -27,6 +27,8 @@ ${DO_NOT_MODIFY_COMMENT} #pragma once +#include + #include #include #include diff --git a/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsAccessor.h-template.js b/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsAccessor.h-template.js index 86c6cdd7caff..751cb28156f6 100644 --- a/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsAccessor.h-template.js +++ b/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsAccessor.h-template.js @@ -27,6 +27,8 @@ ${DO_NOT_MODIFY_COMMENT} #pragma once +#include + #include #include #include diff --git a/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsDefaults.h-template.js b/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsDefaults.h-template.js index 424808f75887..37abc01c6358 100644 --- a/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsDefaults.h-template.js +++ b/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsDefaults.h-template.js @@ -31,6 +31,8 @@ ${DO_NOT_MODIFY_COMMENT} #pragma once +#include + #include namespace facebook::react { diff --git a/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsDynamicProvider.h-template.js b/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsDynamicProvider.h-template.js index a5db0d14d46e..f590ad15fed1 100644 --- a/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsDynamicProvider.h-template.js +++ b/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsDynamicProvider.h-template.js @@ -31,6 +31,8 @@ ${DO_NOT_MODIFY_COMMENT} #pragma once +#include + #include #include diff --git a/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsOverridesOSS_Stage_.h-template.js b/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsOverridesOSS_Stage_.h-template.js index 6b872737a8d1..a339dda9894b 100644 --- a/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsOverridesOSS_Stage_.h-template.js +++ b/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsOverridesOSS_Stage_.h-template.js @@ -54,6 +54,8 @@ ${DO_NOT_MODIFY_COMMENT} #pragma once +#include + #include namespace facebook::react { diff --git a/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsProvider.h-template.js b/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsProvider.h-template.js index 68689f927faa..53a1755e9fa1 100644 --- a/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsProvider.h-template.js +++ b/packages/react-native/scripts/featureflags/templates/common-cxx/ReactNativeFeatureFlagsProvider.h-template.js @@ -27,6 +27,8 @@ ${DO_NOT_MODIFY_COMMENT} #pragma once +#include + namespace facebook::react { class ReactNativeFeatureFlagsProvider { diff --git a/packages/react-native/scripts/ios-prebuild/headers-config.js b/packages/react-native/scripts/ios-prebuild/headers-config.js index 78e72e95d615..66dccae4ef20 100644 --- a/packages/react-native/scripts/ios-prebuild/headers-config.js +++ b/packages/react-native/scripts/ios-prebuild/headers-config.js @@ -312,6 +312,23 @@ const PodspecExceptions /*: {[key: string]: PodSpecConfiguration} */ = { headerPatterns: ['*.h'], headerDir: 'jsinspector-modern/tracing', }, + 'ReactCommon/react/featureflags/React-featureflags.podspec': { + name: 'React-featureflags', + headerPatterns: [], + headerDir: '', + subSpecs: [ + { + name: 'featureflags', + headerPatterns: ['*.h'], + headerDir: 'react/featureflags', + }, + { + name: 'featureflagsUmbrella', + headerPatterns: ['React/*.h'], + headerDir: 'React', + }, + ], + }, 'React/React-RCTFabric.podspec': { name: 'React-RCTFabric', headerPatterns: ['Fabric/**/*.h'],