diff --git a/packages/react-native/ReactCommon/React-Fabric.podspec b/packages/react-native/ReactCommon/React-Fabric.podspec index 7a13eb84ef36..0a2f1795efd6 100644 --- a/packages/react-native/ReactCommon/React-Fabric.podspec +++ b/packages/react-native/ReactCommon/React-Fabric.podspec @@ -18,6 +18,27 @@ end react_native_path = ".." +header_search_path = [ + "\"$(PODS_TARGET_SRCROOT)/ReactCommon\"", + "\"$(PODS_ROOT)/Headers/Private/Yoga\"", + "\"$(PODS_TARGET_SRCROOT)\"" +] + +if ENV['USE_FRAMEWORKS'] + header_search_path = header_search_path + [ + "\"$(PODS_TARGET_SRCROOT)/react/renderer/textlayoutmanager/platform/ios\"", + "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/scrollview/platform/cxx\"", + "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/scrollview/platform/ios\"", + "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/legacyviewmanagerinterop/platform/ios\"", + "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/text/platform/cxx\"", + "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/textinput/platform/ios\"", + "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/view/platform/cxx\"", + "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/view\"", + "\"$(PODS_TARGET_SRCROOT)/react/renderer/core\"", + "\"$(PODS_TARGET_SRCROOT)/react/renderer/debug\"", + ] +end + Pod::Spec.new do |s| s.name = "React-Fabric" s.version = version @@ -30,7 +51,8 @@ Pod::Spec.new do |s| s.source_files = podspec_sources("dummyFile.cpp", "") s.pod_target_xcconfig = { "USE_HEADERMAP" => "YES", "CLANG_CXX_LANGUAGE_STANDARD" => rct_cxx_language_standard(), - "DEFINES_MODULE" => "YES" } + "DEFINES_MODULE" => "YES", + "HEADER_SEARCH_PATHS" => header_search_path.join(" ") } resolve_use_frameworks(s, header_mappings_dir: "./", module_name: "React_Fabric") @@ -89,32 +111,9 @@ Pod::Spec.new do |s| end s.subspec "core" do |ss| - header_search_path = [ - "\"$(PODS_TARGET_SRCROOT)/ReactCommon\"", - "\"$(PODS_ROOT)/Headers/Private/Yoga\"", - "\"$(PODS_TARGET_SRCROOT)\"" - ] - - if ENV['USE_FRAMEWORKS'] - header_search_path = header_search_path + [ - "\"$(PODS_TARGET_SRCROOT)/react/renderer/textlayoutmanager/platform/ios\"", - "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/scrollview/platform/cxx\"", - "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/scrollview/platform/ios\"", - "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/legacyviewmanagerinterop/platform/ios\"", - "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/text/platform/cxx\"", - "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/textinput/platform/ios\"", - "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/view/platform/cxx\"", - "\"$(PODS_TARGET_SRCROOT)/react/renderer/core\"", - "\"$(PODS_TARGET_SRCROOT)/react/renderer/debug\"", - ] - end - ss.source_files = podspec_sources("react/renderer/core/**/*.{m,mm,cpp,h}", "react/renderer/core/**/*.{h}") ss.exclude_files = ["react/renderer/core/tests", "react/renderer/core/React"] ss.header_dir = "react/renderer/core" - ss.pod_target_xcconfig = { - "HEADER_SEARCH_PATHS" => header_search_path.join(" ") - } end s.subspec "coreUmbrella" do |ss| @@ -141,6 +140,8 @@ Pod::Spec.new do |s| s.subspec "components" do |ss| ss.subspec "root" do |sss| + sss.dependency "React-Fabric/coreUmbrella" + sss.dependency "React-Fabric/components/viewUmbrella" sss.source_files = podspec_sources("react/renderer/components/root/**/*.{m,mm,cpp,h}", "react/renderer/components/root/**/*.{h}") sss.exclude_files = "react/renderer/components/root/tests" sss.header_dir = "react/renderer/components/root" diff --git a/packages/react-native/ReactCommon/react/renderer/components/root/RootComponentDescriptor.h b/packages/react-native/ReactCommon/react/renderer/components/root/RootComponentDescriptor.h index 07309a87af5d..91868c76ce77 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/root/RootComponentDescriptor.h +++ b/packages/react-native/ReactCommon/react/renderer/components/root/RootComponentDescriptor.h @@ -9,8 +9,8 @@ #include +#include #include -#include namespace facebook::react { diff --git a/packages/react-native/ReactCommon/react/renderer/components/root/RootProps.h b/packages/react-native/ReactCommon/react/renderer/components/root/RootProps.h index 5a43e19ac606..9914e3b9839f 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/root/RootProps.h +++ b/packages/react-native/ReactCommon/react/renderer/components/root/RootProps.h @@ -9,12 +9,8 @@ #include -#include - -#include -#include -#include -#include +#include +#include namespace facebook::react { diff --git a/packages/react-native/ReactCommon/react/renderer/components/root/RootShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/root/RootShadowNode.h index fa980b713d23..e3dc6d0b7eab 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/root/RootShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/components/root/RootShadowNode.h @@ -11,10 +11,9 @@ #include +#include +#include #include -#include -#include -#include namespace facebook::react { diff --git a/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb b/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb index 445a2455e0aa..952e9229db32 100644 --- a/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb +++ b/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb @@ -732,7 +732,12 @@ def test_updateSearchPaths_whenUseFrameworks_addsSearchPaths second_target ] ) - pods_projects_mock = PodsProjectMock.new([third_target], {"hermes-engine" => {}}) + pods_projects_mock = PodsProjectMock.new( + [third_target], + {"hermes-engine" => {}}, + "test/path-pod.xcodeproj", + [prepare_config("Debug"), prepare_config("Release")] + ) installer = InstallerMock.new(pods_projects_mock, [ AggregatedProjectMock.new(user_project_mock) ]) @@ -743,10 +748,15 @@ def test_updateSearchPaths_whenUseFrameworks_addsSearchPaths # Assert user_project_mock.build_configurations.each do |config| received_search_path = config.build_settings["HEADER_SEARCH_PATHS"] - expected_search_path = "$(inherited) ${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core ${PODS_CONFIGURATION_BUILD_DIR}/React-runtimeexecutor/React_runtimeexecutor.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-runtimeexecutor/React_runtimeexecutor.framework/Headers/platform/ios ${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios ${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx ${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-debug/React_debug.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-rendererdebug/React_rendererdebug.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-timing/React_timing.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-utils/React_utils.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios ${PODS_CONFIGURATION_BUILD_DIR}/React-featureflags/React_featureflags.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-renderercss/React_renderercss.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-cxxstableapi/React_cxxstableapi.framework/Headers" + expected_search_path = "$(inherited) ${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core ${PODS_CONFIGURATION_BUILD_DIR}/React-runtimeexecutor/React_runtimeexecutor.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-runtimeexecutor/React_runtimeexecutor.framework/Headers/platform/ios ${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios ${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx ${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/scrollview/platform/cxx ${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/scrollview/platform/ios ${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-debug/React_debug.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-rendererdebug/React_rendererdebug.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-timing/React_timing.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-utils/React_utils.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-FabricComponents/React_FabricComponents.framework/Headers/react/renderer/textlayoutmanager/platform/ios ${PODS_CONFIGURATION_BUILD_DIR}/React-FabricComponents/React_FabricComponents.framework/Headers/react/renderer/components/text/platform/cxx ${PODS_CONFIGURATION_BUILD_DIR}/React-FabricComponents/React_FabricComponents.framework/Headers/react/renderer/components/textinput/platform/ios ${PODS_CONFIGURATION_BUILD_DIR}/React-FabricComponents/React_FabricComponents.framework/Headers/react/renderer/components/switch/iosswitch ${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-bridging/React_bridging.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios ${PODS_CONFIGURATION_BUILD_DIR}/React-featureflags/React_featureflags.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-renderercss/React_renderercss.framework/Headers ${PODS_CONFIGURATION_BUILD_DIR}/React-cxxstableapi/React_cxxstableapi.framework/Headers" assert_equal(expected_search_path, received_search_path) end + pods_projects_mock.build_configurations.each do |config| + received_search_paths = Shellwords.shellsplit(config.build_settings["HEADER_SEARCH_PATHS"]) + assert_false(received_search_paths.include?("${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers")) + end + installer.target_installation_results.pod_target_installation_results.each do |pod_name, target_installation_result| if pod_name == "SecondTarget" target_installation_result.native_target.build_configurations.each do |config| @@ -808,6 +818,20 @@ def test_add_search_path_if_not_included_does_not_add_existing_path_to_string assert_equal("/path/to/headers /another/path", result) end + def test_add_search_path_if_not_included_adds_path_that_is_prefix_of_existing_path + current_paths = "/path/to/headers/platform/ios" + new_path = "/path/to/headers" + result = ReactNativePodsUtils.add_search_path_if_not_included(current_paths, new_path) + assert_equal("/path/to/headers/platform/ios /path/to/headers", result) + end + + def test_add_search_path_if_not_included_does_not_duplicate_quoted_path_with_spaces + current_paths = '"/path/with spaces/headers" /another/path' + new_path = '"/path/with spaces/headers"' + result = ReactNativePodsUtils.add_search_path_if_not_included(current_paths, new_path) + assert_equal(current_paths, result) + end + def test_add_search_path_if_not_included_does_not_add_existing_path_with_leading_space_to_string current_paths = " /path/with/leading/space /another/path" new_path = "/path/with/leading/space" @@ -943,6 +967,68 @@ def test_createHeaderSearchPathsForStableUmbrellas_whenUsingPrebuiltCore_addsNot assert_equal([], result) end + def test_setStableUmbrellaSearchPaths_addsOwningFrameworkPathToDependentTarget + target = prepare_target("Consumer", nil, [DependencyMock.new("React-Fabric")]) + target_installation_result = TargetInstallationResultMock.new(target, target) + + ReactNativePodsUtils.set_stable_umbrella_search_paths(target_installation_result) + + target.build_configurations.each do |config| + assert_equal( + '$(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers"', + config.build_settings["HEADER_SEARCH_PATHS"] + ) + end + end + + def test_setStableUmbrellaSearchPaths_addsOwningFrameworkPathToTransitivelyDependentTarget + dependency = Struct.new(:name, :target) + fabric_target = prepare_target("React-Fabric") + intermediate_target = prepare_target( + "Intermediate", + nil, + [dependency.new("React-Fabric", fabric_target)] + ) + consumer_target = prepare_target( + "Consumer", + nil, + [dependency.new("Intermediate", intermediate_target)] + ) + target_installation_result = TargetInstallationResultMock.new(consumer_target, consumer_target) + + ReactNativePodsUtils.set_stable_umbrella_search_paths(target_installation_result) + + consumer_target.build_configurations.each do |config| + assert_equal( + '$(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers"', + config.build_settings["HEADER_SEARCH_PATHS"] + ) + end + end + + def test_setStableUmbrellaSearchPaths_doesNotAddOwningFrameworkPathToUnrelatedTarget + target = prepare_target("React-Fabric") + target_installation_result = TargetInstallationResultMock.new(target, target) + + ReactNativePodsUtils.set_stable_umbrella_search_paths(target_installation_result) + + target.build_configurations.each do |config| + assert_nil(config.build_settings["HEADER_SEARCH_PATHS"]) + end + end + + def test_setStableUmbrellaSearchPaths_whenUsingPrebuiltCore_addsNothing + ReactNativeCoreUtils.class_variable_set(:@@build_from_source, false) + target = prepare_target("Consumer", nil, [DependencyMock.new("React-Fabric")]) + target_installation_result = TargetInstallationResultMock.new(target, target) + + ReactNativePodsUtils.set_stable_umbrella_search_paths(target_installation_result) + + target.build_configurations.each do |config| + assert_nil(config.build_settings["HEADER_SEARCH_PATHS"]) + end + end + # ================================= # # TEST - Add RN_BUILDING definition # # ================================= # diff --git a/packages/react-native/scripts/cocoapods/utils.rb b/packages/react-native/scripts/cocoapods/utils.rb index 9a2326e38cad..b12553917d88 100644 --- a/packages/react-native/scripts/cocoapods/utils.rb +++ b/packages/react-native/scripts/cocoapods/utils.rb @@ -358,15 +358,19 @@ def self.create_header_search_path_for_frameworks(base_folder, pod_name, framewo def self.create_header_search_paths_for_stable_umbrellas(base_folder) return [] unless ReactNativeCoreUtils.build_rncore_from_source() + self.stable_umbrella_frameworks.flat_map { |pod_name, framework_name| + self.create_header_search_path_for_frameworks(base_folder, pod_name, framework_name, []) + } + end + + def self.stable_umbrella_frameworks [ ["React-Fabric", "React_Fabric"], ["React-debug", "React_debug"], ["React-rendererdebug", "React_rendererdebug"], ["React-timing", "React_timing"], ["React-utils", "React_utils"], - ].flat_map { |pod_name, framework_name| - self.create_header_search_path_for_frameworks(base_folder, pod_name, framework_name, []) - } + ] end # Add a new dependency to an existing spec, configuring also the headers search paths @@ -399,6 +403,9 @@ def self.update_search_paths(installer) projects = self.extract_projects(installer) projects.each do |project| + stable_umbrella_search_paths = project == installer.pods_project ? + [] : ReactNativePodsUtils.create_header_search_paths_for_stable_umbrellas("PODS_CONFIGURATION_BUILD_DIR") + project.build_configurations.each do |config| header_search_paths = config.build_settings["HEADER_SEARCH_PATHS"] ||= "$(inherited)" @@ -411,7 +418,7 @@ def self.update_search_paths(installer) "react/renderer/components/scrollview/platform/cxx", "react/renderer/components/scrollview/platform/ios", ], false)) - .concat(ReactNativePodsUtils.create_header_search_paths_for_stable_umbrellas("PODS_CONFIGURATION_BUILD_DIR")) + .concat(stable_umbrella_search_paths) .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-FabricComponents", "React_FabricComponents", [ "react/renderer/textlayoutmanager/platform/ios", "react/renderer/components/text/platform/cxx", @@ -436,6 +443,8 @@ def self.update_search_paths(installer) end installer.target_installation_results.pod_target_installation_results.each do |pod_name, target_installation_result| + self.set_stable_umbrella_search_paths(target_installation_result) + if self.react_native_pods.include?(pod_name) || pod_name.include?("Pod") || pod_name.include?("Tests") next end @@ -649,7 +658,9 @@ def self.add_search_path_if_not_included(current_search_paths, new_search_path) if current_search_paths.is_a?(String) current_search_paths = current_search_paths.strip - return "#{current_search_paths} #{new_search_path}" unless current_search_paths.include?(new_search_path) + current_paths = Shellwords.shellsplit(current_search_paths) + normalized_new_path = Shellwords.shellsplit(new_search_path).first + return "#{current_search_paths} #{new_search_path}" unless current_paths.include?(normalized_new_path) end if current_search_paths.is_a?(Array) @@ -660,10 +671,29 @@ def self.add_search_path_if_not_included(current_search_paths, new_search_path) current_search_paths end - def self.update_header_paths_if_depends_on(target_installation_result, dependency_name, header_paths) - depends_on_framework = target_installation_result.native_target.dependencies.any? { |d| d.name == dependency_name } + def self.target_depends_on?(target, dependency_name, visited_targets = {}) + return false if target == nil + + target_identifier = target.respond_to?(:uuid) ? target.uuid : target.object_id + target_identifier ||= target.object_id + return false if visited_targets[target_identifier] + + visited_targets[target_identifier] = true + target.dependencies.any? do |dependency| + dependency.name == dependency_name || + (dependency.respond_to?(:target) && self.target_depends_on?(dependency.target, dependency_name, visited_targets)) + end + end + + def self.update_header_paths_if_depends_on(target_installation_result, dependency_name, header_paths, include_transitive_dependencies: false) + native_target = target_installation_result.native_target + depends_on_framework = if include_transitive_dependencies + self.target_depends_on?(native_target, dependency_name) + else + native_target.dependencies.any? { |d| d.name == dependency_name } + end if depends_on_framework - target_installation_result.native_target.build_configurations.each do |config| + native_target.build_configurations.each do |config| header_search_path = config.build_settings["HEADER_SEARCH_PATHS"] != nil ? config.build_settings["HEADER_SEARCH_PATHS"] : "$(inherited)" header_paths.each { |header| header_search_path = ReactNativePodsUtils.add_search_path_if_not_included(header_search_path, header) } config.build_settings["HEADER_SEARCH_PATHS"] = header_search_path @@ -671,6 +701,25 @@ def self.update_header_paths_if_depends_on(target_installation_result, dependenc end end + def self.set_stable_umbrella_search_paths(target_installation_result) + return unless ReactNativeCoreUtils.build_rncore_from_source() + + ReactNativePodsUtils.stable_umbrella_frameworks.each do |pod_name, framework_name| + header_search_paths = ReactNativePodsUtils.create_header_search_path_for_frameworks( + "PODS_CONFIGURATION_BUILD_DIR", + pod_name, + framework_name, + [] + ).map { |search_path| "\"#{search_path}\"" } + ReactNativePodsUtils.update_header_paths_if_depends_on( + target_installation_result, + pod_name, + header_search_paths, + include_transitive_dependencies: true + ) + end + end + def self.set_rctfolly_search_paths(target_installation_result) ReactNativePodsUtils.update_header_paths_if_depends_on(target_installation_result, "RCT-Folly", [ "\"$(PODS_ROOT)/RCT-Folly\"", diff --git a/packages/react-native/scripts/ios-prebuild/headers-config.js b/packages/react-native/scripts/ios-prebuild/headers-config.js index de50c9938788..bd4f5fa955f0 100644 --- a/packages/react-native/scripts/ios-prebuild/headers-config.js +++ b/packages/react-native/scripts/ios-prebuild/headers-config.js @@ -185,7 +185,10 @@ const PodspecExceptions /*: {[key: string]: PodSpecConfiguration} */ = { { name: 'imagemanager', - headerPatterns: ['react/renderer/imagemanager/*.h'], + headerPatterns: [ + 'react/renderer/imagemanager/*.h', + 'react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/ImageRequestParams.h', + ], headerDir: 'react/renderer/imagemanager', },