Skip to content

Commit

Permalink
Fix symbol not found _jump_fcontext with use_frameworks! (#42230)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #42230

While developing Xcode 15, Apple reimplemented the linker.
In Xcode 15.0, the linker was making old iOS (< 15) crash when they were built using Xcode 15.

To fix that, we make Apple create new compiler flags (`-ld_classic`) to have a backward compatible linker.

In Xcode 15.1, Apple fixed that behavior, so the flags should not be required anymore.
But now, if we pass `-ld_classic` to the linker and we have an app that is using `use_framworks!`, that app crashes at startup.

This change remove the flags if the Xcode that is used is 15.1 or greater.

*Note:* The previous change added the flags to Hermes as well. I tested this fix in a configuration where Hermes has the flags and React Native does not, and it works. So we are removing the flags only from React Native.

This Fixes #39945

## Changelog:
[Internal] - Do not add the `-ld_classic` flag if the app is built with Xcode 15.1 or greater.

Reviewed By: cortinico

Differential Revision: D52658197

fbshipit-source-id: 37d6bc895921c0fc3661f301870477191e7e42b3
  • Loading branch information
cipolleschi authored and pull[bot] committed Aug 15, 2024
1 parent 6e59693 commit 8341154
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 9 deletions.
57 changes: 51 additions & 6 deletions packages/react-native/scripts/cocoapods/__tests__/utils-test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,52 @@ def test_applyXcode15Patch_whenXcodebuild14_correctlyAppliesNecessaryPatch
assert_equal(2, XcodebuildMock.version_invocation_count)
end

def test_applyXcode15Patch_whenXcodebuild15_1_does_not_apply_patch
# Arrange
XcodebuildMock.set_version = "Xcode 15.1"
first_target = prepare_target("FirstTarget")
second_target = prepare_target("SecondTarget")
third_target = TargetMock.new("ThirdTarget", [
BuildConfigurationMock.new("Debug", {
"GCC_PREPROCESSOR_DEFINITIONS" => '$(inherited) "SomeFlag=1" '
}),
BuildConfigurationMock.new("Release", {
"GCC_PREPROCESSOR_DEFINITIONS" => '$(inherited) "SomeFlag=1" '
}),
], nil)

user_project_mock = UserProjectMock.new("/a/path", [
prepare_config("Debug"),
prepare_config("Release"),
],
:native_targets => [
first_target,
second_target
]
)
pods_projects_mock = PodsProjectMock.new([], {"hermes-engine" => {}}, :native_targets => [
third_target
])
installer = InstallerMock.new(pods_projects_mock, [
AggregatedProjectMock.new(user_project_mock)
])

# Act
user_project_mock.build_configurations.each do |config|
assert_nil(config.build_settings["OTHER_LDFLAGS"])
end

ReactNativePodsUtils.apply_xcode_15_patch(installer, :xcodebuild_manager => XcodebuildMock)

# Assert
user_project_mock.build_configurations.each do |config|
assert_equal("$(inherited) ", config.build_settings["OTHER_LDFLAGS"])
end

# User project and Pods project
assert_equal(2, XcodebuildMock.version_invocation_count)
end

def test_applyXcode15Patch_whenXcodebuild15_correctlyAppliesNecessaryPatch
# Arrange
XcodebuildMock.set_version = "Xcode 15.0"
Expand Down Expand Up @@ -1018,13 +1064,13 @@ def test_add_flag_to_map_with_inheritance_whenUsedWithBuildConfigBuildSettings
})
twiceProcessed_config = BuildConfigurationMock.new("TwiceProcessedConfig");
test_flag = " -DTEST_FLAG=1"

# Act
ReactNativePodsUtils.add_flag_to_map_with_inheritance(empty_config.build_settings, "OTHER_CPLUSPLUSFLAGS", test_flag)
ReactNativePodsUtils.add_flag_to_map_with_inheritance(initialized_config.build_settings, "OTHER_CPLUSPLUSFLAGS", test_flag)
ReactNativePodsUtils.add_flag_to_map_with_inheritance(twiceProcessed_config.build_settings, "OTHER_CPLUSPLUSFLAGS", test_flag)
ReactNativePodsUtils.add_flag_to_map_with_inheritance(twiceProcessed_config.build_settings, "OTHER_CPLUSPLUSFLAGS", test_flag)

# Assert
assert_equal("$(inherited)" + test_flag, empty_config.build_settings["OTHER_CPLUSPLUSFLAGS"])
assert_equal("$(inherited) INIT_FLAG" + test_flag, initialized_config.build_settings["OTHER_CPLUSPLUSFLAGS"])
Expand All @@ -1051,7 +1097,7 @@ def test_add_flag_to_map_with_inheritance_whenUsedWithXCConfigAttributes
assert_equal("$(inherited) INIT_FLAG" + test_flag, initialized_xcconfig.attributes["OTHER_CPLUSPLUSFLAGS"])
assert_equal("$(inherited)" + test_flag, twiceProcessed_xcconfig.attributes["OTHER_CPLUSPLUSFLAGS"])
end

def test_add_ndebug_flag_to_pods_in_release
# Arrange
xcconfig = XCConfigMock.new("Config")
Expand All @@ -1061,7 +1107,7 @@ def test_add_ndebug_flag_to_pods_in_release
custom_debug_config2 = BuildConfigurationMock.new("Custom")
custom_release_config1 = BuildConfigurationMock.new("CustomRelease")
custom_release_config2 = BuildConfigurationMock.new("Production")

installer = prepare_installer_for_cpp_flags(
[ xcconfig ],
{
Expand All @@ -1072,7 +1118,7 @@ def test_add_ndebug_flag_to_pods_in_release
)
# Act
ReactNativePodsUtils.add_ndebug_flag_to_pods_in_release(installer)

# Assert
assert_equal(nil, default_debug_config.build_settings["OTHER_CPLUSPLUSFLAGS"])
assert_equal("$(inherited) -DNDEBUG", default_release_config.build_settings["OTHER_CPLUSPLUSFLAGS"])
Expand Down Expand Up @@ -1150,4 +1196,3 @@ def prepare_installer_for_cpp_flags(xcconfigs, build_configs)
:pod_target_installation_results => pod_target_installation_results_map
)
end

7 changes: 4 additions & 3 deletions packages/react-native/scripts/cocoapods/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def self.apply_xcode_15_patch(installer, xcodebuild_manager: Xcodebuild)
project.build_configurations.each do |config|
# fix for weak linking
self.safe_init(config, other_ld_flags_key)
if self.is_using_xcode15_or_greater(:xcodebuild_manager => xcodebuild_manager)
if self.is_using_xcode15_0(:xcodebuild_manager => xcodebuild_manager)
self.add_value_to_setting_if_missing(config, other_ld_flags_key, xcode15_compatibility_flags)
else
self.remove_value_from_setting_if_present(config, other_ld_flags_key, xcode15_compatibility_flags)
Expand Down Expand Up @@ -404,7 +404,7 @@ def self.remove_value_from_setting_if_present(config, setting_name, value)
end
end

def self.is_using_xcode15_or_greater(xcodebuild_manager: Xcodebuild)
def self.is_using_xcode15_0(xcodebuild_manager: Xcodebuild)
xcodebuild_version = xcodebuild_manager.version

# The output of xcodebuild -version is something like
Expand All @@ -415,7 +415,8 @@ def self.is_using_xcode15_or_greater(xcodebuild_manager: Xcodebuild)
regex = /(\d+)\.(\d+)(?:\.(\d+))?/
if match_data = xcodebuild_version.match(regex)
major = match_data[1].to_i
return major >= 15
minor = match_data[2].to_i
return major == 15 && minor == 0
end

return false
Expand Down

0 comments on commit 8341154

Please sign in to comment.