Bump min Xcode to 16.1 (#51762)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/51762

Apple requires Xcode 16 or later to submit to the app store. Let's bump the minimum checked for in build logic as well. https://developer.apple.com/news/upcoming-requirements/?id=02212025

GHA is already only testing against 16.2.0 as of D73924819

Changelog:
[iOS][Breaking] - Bump min Xcode to 16.1

Reviewed By: cipolleschi

Differential Revision: D75835304

fbshipit-source-id: a7ce22f958be3a5448a279439e27b615e9b20a2f
This commit is contained in:
Nick Gerleman authored and Facebook GitHub Bot committed 2025-06-04 14:15:45 -07:00
1 parent 5ce99e7eb2
commit c27a8804a6
4 files changed
+1 -225

No files matched your search

@@ -452,196 +452,6 @@ class UtilsTests < Test::Unit::TestCase
assert_equal(user_project_mock.save_invocation_count, 1)
end
# ================================= #
# Test - Apply Xcode 15 Patch #
# ================================= #
def test_applyXcode15Patch_whenXcodebuild14_correctlyAppliesNecessaryPatch
# Arrange
XcodebuildMock.set_version = "Xcode 14.3"
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_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"
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) -Wl -ld_classic", config.build_settings["OTHER_LDFLAGS"])
end
# User project and Pods project
assert_equal(2, XcodebuildMock.version_invocation_count)
end
def test_applyXcode15Patch_whenXcodebuild14ButProjectHasSettings_correctlyRemovesNecessaryPatch
# Arrange
XcodebuildMock.set_version = "Xcode 14.3"
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)
debug_config = prepare_config("Debug", {"OTHER_LDFLAGS" => "$(inherited) -Wl -ld_classic "})
release_config = prepare_config("Release", {"OTHER_LDFLAGS" => "$(inherited) -Wl -ld_classic "})
user_project_mock = UserProjectMock.new("/a/path", [
debug_config,
release_config,
],
:native_targets => [
first_target,
second_target
]
)
pods_projects_mock = PodsProjectMock.new([debug_config.clone, release_config.clone], {"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_equal("$(inherited) -Wl -ld_classic ", 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
# ==================================== #
# Test - Set build setting #
# ==================================== #
@@ -85,7 +85,7 @@ module Helpers
end
def self.min_xcode_version_supported
return '15.1'
return '16.1'
end
def self.folly_config
@@ -177,27 +177,6 @@ class ReactNativePodsUtils
end
end
def self.apply_xcode_15_patch(installer, xcodebuild_manager: Xcodebuild)
projects = self.extract_projects(installer)
other_ld_flags_key = 'OTHER_LDFLAGS'
xcode15_compatibility_flags = '-Wl -ld_classic '
projects.each do |project|
project.build_configurations.each do |config|
# fix for weak linking
self.safe_init(config, other_ld_flags_key)
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)
end
end
project.save()
end
end
private
def self.add_build_settings_to_pod(installer, settings_name, settings_value, target_pod_name, configuration_type)
@@ -423,16 +402,6 @@ class ReactNativePodsUtils
end
end
def self.is_using_xcode15_0(xcodebuild_manager: Xcodebuild)
xcodebuild_version = xcodebuild_manager.version
if version = self.parse_xcode_version(xcodebuild_version)
return version["major"] == 15 && version["minor"] == 0
end
return false
end
def self.parse_xcode_version(version_string)
# The output of xcodebuild -version is something like
# Xcode 15.0
@@ -444,9 +444,6 @@ def react_native_post_install(
ReactNativePodsUtils.set_build_setting(installer, build_setting: "SWIFT_ACTIVE_COMPILATION_CONDITIONS", value: ['$(inherited)', 'DEBUG'], config_name: "Debug")
ReactNativePodsUtils.set_ccache_compiler_and_linker_build_settings(installer, react_native_path, ccache_enabled)
if Environment.new().ruby_platform().include?('darwin')
ReactNativePodsUtils.apply_xcode_15_patch(installer)
end
ReactNativePodsUtils.updateOSDeploymentTarget(installer)
ReactNativePodsUtils.set_dynamic_frameworks_flags(installer)
ReactNativePodsUtils.add_ndebug_flag_to_pods_in_release(installer)