Skip to content

Commit

Permalink
Create script to automatically set CLANG_CXX_LANGUAGE_STANDARD on the…
Browse files Browse the repository at this point in the history
… client project (#33863)

Summary:
Currently this [section](https://reactnative.dev/docs/next/new-architecture-app-intro#ios-enable-c17-language-feature-support) of the Playbook tells us to set CLANG_CXX_LANGUAGE_STANDARD = "c++17" in the main app target for the new architecture to work.
Would be nice to be able to automate that instead

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[iOS] [Added] - Cocoapods function to add the `CLANG_CXX_LANGUAGE_STANDARD` to all the targets if needed

Pull Request resolved: #33863

Test Plan:
I've created some unit tests for the newly added function.
I've executed pod install and the ruby tests locally.

Reviewed By: cipolleschi

Differential Revision: D36484366

Pulled By: f-meloni

fbshipit-source-id: 553b092e747bef11d82195619ae1058985fdc325
  • Loading branch information
f-meloni authored and facebook-github-bot committed May 19, 2022
1 parent baada4e commit ca8174e
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 4 deletions.
2 changes: 1 addition & 1 deletion React-Core.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Pod::Spec.new do |s|
s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags
s.header_dir = "React"
s.framework = "JavaScriptCore"
s.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/RCT-Folly\" \"${PODS_ROOT}/Headers/Public/React-hermes\" \"${PODS_ROOT}/Headers/Public/hermes-engine\" \"${PODS_ROOT}/Headers/Public/FlipperKit\" \"$(PODS_ROOT)/Headers/Public/ReactCommon\" \"$(PODS_ROOT)/Headers/Public/React-RCTFabric\"", "DEFINES_MODULE" => "YES", "GCC_PREPROCESSOR_DEFINITIONS" => "RCT_METRO_PORT=${RCT_METRO_PORT}" }
s.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/RCT-Folly\" \"${PODS_ROOT}/Headers/Public/React-hermes\" \"${PODS_ROOT}/Headers/Public/hermes-engine\" \"${PODS_ROOT}/Headers/Public/FlipperKit\" \"$(PODS_ROOT)/Headers/Public/ReactCommon\" \"$(PODS_ROOT)/Headers/Public/React-RCTFabric\"", "DEFINES_MODULE" => "YES", "GCC_PREPROCESSOR_DEFINITIONS" => "RCT_METRO_PORT=${RCT_METRO_PORT}", "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" }
s.user_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/Headers/Private/React-Core\""}
s.default_subspec = "Default"

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"scripts/cocoapods/codegen.rb",
"scripts/cocoapods/fabric.rb",
"scripts/cocoapods/flipper.rb",
"scripts/cocoapods/new_architecture.rb",
"scripts/react-native-xcode.sh",
"sdks/hermes-engine",
"sdks/hermesc",
Expand Down
2 changes: 2 additions & 0 deletions packages/rn-tester/Podfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require_relative '../../scripts/react_native_pods'
require_relative '../../scripts/cocoapods/new_architecture'

source 'https://cdn.cocoapods.org/'
platform :ios, '12.4'
Expand Down Expand Up @@ -65,4 +66,5 @@ end
post_install do |installer|
react_native_post_install(installer, @prefix_path)
__apply_Xcode_12_5_M1_post_install_workaround(installer)
set_clang_cxx_language_standard_if_needed(installer)
end
6 changes: 4 additions & 2 deletions packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
Expand Down Expand Up @@ -913,6 +913,7 @@
"-ObjC",
"-lc++",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../..";
SDKROOT = iphoneos;
WARNING_CFLAGS = (
"-Wextra",
Expand All @@ -927,7 +928,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
Expand Down Expand Up @@ -989,6 +990,7 @@
"-ObjC",
"-lc++",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../..";
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
WARNING_CFLAGS = (
Expand Down
133 changes: 133 additions & 0 deletions scripts/cocoapods/__tests__/new_architecture-test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# 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.

require "test/unit"
require_relative "../new_architecture.rb"
require_relative "./test_utils/InstallerMock.rb"
require_relative "./test_utils/PodMock.rb"

class NewArchitectureTests < Test::Unit::TestCase
def setup
File.enable_testing_mode!
end

def teardown
Pod::UI.reset()
end


def test_setClangCxxLanguageStandardIfNeeded_whenReactCoreIsPresent
installer = prepare_mocked_installer_with_react_core
set_clang_cxx_language_standard_if_needed(installer)

assert_equal(installer.aggregate_targets[0].user_project.build_configurations[0].build_settings["CLANG_CXX_LANGUAGE_STANDARD"], "c++17")
assert_equal(installer.aggregate_targets[1].user_project.build_configurations[0].build_settings["CLANG_CXX_LANGUAGE_STANDARD"], "c++17")
assert_equal(installer.pods_project.targets[1].received_resolved_build_setting_parameters, [ReceivedCommonResolvedBuildSettings.new("CLANG_CXX_LANGUAGE_STANDARD", true)])
assert_equal(Pod::UI.collected_messages, ["Setting CLANG_CXX_LANGUAGE_STANDARD to c++17 on /test/path.xcproj", "Setting CLANG_CXX_LANGUAGE_STANDARD to c++17 on /test/path2.xcproj"])
end

def test_setClangCxxLanguageStandardIfNeeded_whenReactCoreIsNotPresent
installer = prepare_mocked_installer_without_react_core
set_clang_cxx_language_standard_if_needed(installer)

assert_equal(installer.aggregate_targets[0].user_project.build_configurations[0].build_settings["CLANG_CXX_LANGUAGE_STANDARD"], nil)
assert_equal(installer.aggregate_targets[1].user_project.build_configurations[0].build_settings["CLANG_CXX_LANGUAGE_STANDARD"], nil)
assert_equal(installer.pods_project.targets[0].received_resolved_build_setting_parameters, [])
assert_equal(Pod::UI.collected_messages, [])
end

def test_setClangCxxLanguageStandardIfNeeded_whenThereAreDifferentValuesForLanguageStandard_takesTheFirstValue
installer = prepare_mocked_installer_with_react_core_and_different_language_standards
set_clang_cxx_language_standard_if_needed(installer)

assert_equal(installer.aggregate_targets[0].user_project.build_configurations[0].build_settings["CLANG_CXX_LANGUAGE_STANDARD"], "c++17")
assert_equal(installer.aggregate_targets[1].user_project.build_configurations[0].build_settings["CLANG_CXX_LANGUAGE_STANDARD"], "c++17")
assert_equal(installer.pods_project.targets[1].received_resolved_build_setting_parameters, [ReceivedCommonResolvedBuildSettings.new("CLANG_CXX_LANGUAGE_STANDARD", true)])
assert_equal(Pod::UI.collected_messages, ["Setting CLANG_CXX_LANGUAGE_STANDARD to c++17 on /test/path.xcproj", "Setting CLANG_CXX_LANGUAGE_STANDARD to c++17 on /test/path2.xcproj"])
end
end

def prepare_mocked_installer_with_react_core
return InstallerMock.new(
PodsProjectMock.new([
TargetMock.new(
"YogaKit",
[
BuildConfigurationMock.new("Debug"),
BuildConfigurationMock.new("Release"),
]
),
TargetMock.new(
"React-Core",
[
BuildConfigurationMock.new("Debug", { "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" }),
BuildConfigurationMock.new("Release", { "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" }),
]
)
]
),
[
AggregatedProjectMock.new(
UserProjectMock.new("/test/path.xcproj", [BuildConfigurationMock.new("Debug")])
),
AggregatedProjectMock.new(
UserProjectMock.new("/test/path2.xcproj", [BuildConfigurationMock.new("Debug")])
),
]
)
end

def prepare_mocked_installer_with_react_core_and_different_language_standards
return InstallerMock.new(
PodsProjectMock.new([
TargetMock.new(
"YogaKit",
[
BuildConfigurationMock.new("Debug"),
BuildConfigurationMock.new("Release"),
]
),
TargetMock.new(
"React-Core",
[
BuildConfigurationMock.new("Debug", { "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" }),
BuildConfigurationMock.new("Release", { "CLANG_CXX_LANGUAGE_STANDARD" => "new" }),
]
)
]
),
[
AggregatedProjectMock.new(
UserProjectMock.new("/test/path.xcproj", [BuildConfigurationMock.new("Debug")])
),
AggregatedProjectMock.new(
UserProjectMock.new("/test/path2.xcproj", [BuildConfigurationMock.new("Debug")])
),
]
)
end

def prepare_mocked_installer_without_react_core
return InstallerMock.new(
PodsProjectMock.new([
TargetMock.new(
"YogaKit",
[
BuildConfigurationMock.new("Debug"),
BuildConfigurationMock.new("Release"),
]
)
]
),
[
AggregatedProjectMock.new(
UserProjectMock.new("/test/path.xcproj", [BuildConfigurationMock.new("Debug")])
),
AggregatedProjectMock.new(
UserProjectMock.new("/test/path2.xcproj", [BuildConfigurationMock.new("Debug")])
),
]
)
end
36 changes: 35 additions & 1 deletion scripts/cocoapods/__tests__/test_utils/InstallerMock.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@

class InstallerMock
attr_reader :pods_project
attr_reader :aggregate_targets

def initialize(pods_project = PodsProjectMock.new)
def initialize(pods_project = PodsProjectMock.new, aggregate_targets = [AggregatedProjectMock.new])
@pods_project = pods_project
@aggregate_targets = aggregate_targets
end

def target_with_name(name)
Expand All @@ -58,13 +60,45 @@ def initialize(targets = [])
end
end

class AggregatedProjectMock
attr_reader :user_project

def initialize(user_project = UserProjectMock.new)
@user_project = user_project
end
end

class UserProjectMock
attr_reader :path
attr_reader :build_configurations

def initialize(path = "/test/path.xcproj", build_configurations = [])
@path = path
@build_configurations = build_configurations
end

def save()
end
end

ReceivedCommonResolvedBuildSettings = Struct.new(:key, :resolve_against_xcconfig)

class TargetMock
attr_reader :name
attr_reader :build_configurations

attr_reader :received_resolved_build_setting_parameters

def initialize(name, build_configurations = [])
@name = name
@build_configurations = build_configurations
@received_resolved_build_setting_parameters = []
end

def resolved_build_setting(key, resolve_against_xcconfig: false)
received_resolved_build_setting_parameters.append(ReceivedCommonResolvedBuildSettings.new(key, resolve_against_xcconfig))

return {name: build_configurations[0].build_settings[key]}
end
end

Expand Down
30 changes: 30 additions & 0 deletions scripts/cocoapods/new_architecture.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# 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.

def set_clang_cxx_language_standard_if_needed(installer)
language_standard = nil

installer.pods_project.targets.each do |target|
if target.name == 'React-Core'
language_standard = target.resolved_build_setting("CLANG_CXX_LANGUAGE_STANDARD", resolve_against_xcconfig: true).values[0]
end
end

unless language_standard.nil?
projects = installer.aggregate_targets
.map{ |t| t.user_project }
.uniq{ |p| p.path }

projects.each do |project|
Pod::UI.puts("Setting CLANG_CXX_LANGUAGE_STANDARD to #{ language_standard } on #{ project.path }")

project.build_configurations.each do |config|
config.build_settings["CLANG_CXX_LANGUAGE_STANDARD"] = language_standard
end

project.save()
end
end
end

0 comments on commit ca8174e

Please sign in to comment.