Skip to content

Commit e85d51c

Browse files
kraenhansenfacebook-github-bot
authored andcommitted
Detect ccache and provide a default configuration (#42051)
Summary: Building native modules from source, may take a long time. Xcode already helps bring this down, by providing incremental builds, as long as the user doesn't delete their `ios/build` directory. But in some situations, i.e. when iterating the native code of an app or library or when the developer need to delete that `ios/build` directory, it's advantageous to use a compiler cache, such as ccache. This is already outlined in our ["Speeding up your Build phase"](https://reactnative.dev/docs/build-speed#xcode-specific-setup) guide. But setting up an Xcode project to use Ccache with the correct configuration, isn't trivial in a way that doesn't require symlinking `clang` and `clang++` or passing configuration via environment variables on every `npm run ios` invokation. This PR takes its inspiration from the existing guide on [setting up Ccache for Xcode](https://reactnative.dev/docs/build-speed#xcode-specific-setup), but applies the build settings only if an installation of `ccache` is detected and the feature is explicitly opted into via an argument to the `react_native_post_install` function or a `USE_CCACHE` environment variable. It uses two shell scripts to wrap the call to `ccache`, which both injects a default `CCACHE_CONFIGPATH` environment variable (i.e. it won't override this if already provided, to allow for customisations on CI), pointing to a `ccache.config` which works well with React Native projects (it has the same values as the guide mentions). For context, I posted about this change in the ios channel of the contributors Discord server, where I discussed it with cipolleschi and saadnajmi ### Additional output printed when running `pod install` #### When `ccache_available and ccache_enabled` ``` [Ccache]: Ccache found at /opt/homebrew/bin/ccache [Ccache]: Setting CC, LD, CXX & LDPLUSPLUS build settings ``` #### When `ccache_available and !ccache_enabled` ``` [Ccache]: Ccache found at /opt/homebrew/bin/ccache [Ccache]: Pass ':ccache_enabled => true' to 'react_native_post_install' in your Podfile or set environment variable 'USE_CCACHE=1' to increase the speed of subsequent builds ``` #### When `!ccache_available and ccache_enabled` ``` [!] [Ccache]: Install ccache or ensure your neither passing ':ccache_enabled => true' nor setting environment variable 'USE_CCACHE=1' ``` #### Otherwise If the user doesn't have ccache installed and doesn't explicitly opt into this feature, nothing will be printed. bypass-github-export-checks ## Changelog: [IOS] [ADDED] - Added better support for `ccache`, to speed up subsequent builds of native code. After installing `ccache` and running `pod install`, the Xcode project is injected with compiler and linker build settings pointing scripts that loads a default Ccache configuration and invokes the `ccache` executable. Pull Request resolved: #42051 Test Plan: I've tested this manually - would love some inspiration on how to automate this, if the reviewer deem it needed. To test this locally: 1. Install Ccache and make sure the `ccache` executable is in your `PATH` (verify by running `ccache --version`) 2. Create a new template app instance and apply the changes of this PR to the `node_modules/react-native` package. 3. Set the `USE_CCACHE` environment variable using `export USE_CCACHE=1`. 4. Run `pod install` in the `ios` directory. 5. Check the stats of Ccache (running `ccache -s`). 6. Run `npm run ios` or build the project from Xcode. 7. Check the Ccache stats again to verify ccache is intercepting compilation ("Cacheable calls" should ideally be 100%). 8. To check the speed gain: a. Delete the `ios/builds` directory b. Zero out the ccache stats (by running `ccache -z`) c. Run `pod install` again (only needed if you ran the initial `pod install` with new architecture enabled `RCT_NEW_ARCH_ENABLED=1`). d. Run `npm run ios` or build the project from Xcode. e. This last step should be significantly faster and you should see "Hits" under "Local storage" in the ccache stats approach 100%. Reviewed By: huntie Differential Revision: D52431507 Pulled By: cipolleschi fbshipit-source-id: 6cfe39acd6250fae03959f0ee74d1f2fc46b0827
1 parent e25a9b4 commit e85d51c

File tree

6 files changed

+80
-2
lines changed

6 files changed

+80
-2
lines changed

packages/react-native/scripts/cocoapods/utils.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,42 @@ def self.set_node_modules_user_settings(installer, react_native_path)
8686
end
8787
end
8888

89+
def self.set_ccache_compiler_and_linker_build_settings(installer, react_native_path, ccache_enabled)
90+
projects = self.extract_projects(installer)
91+
92+
ccache_path = `command -v ccache`.strip
93+
ccache_available = !ccache_path.empty?
94+
95+
message_prefix = "[Ccache]"
96+
97+
if ccache_available
98+
Pod::UI.puts("#{message_prefix}: Ccache found at #{ccache_path}")
99+
end
100+
101+
if ccache_available and ccache_enabled
102+
Pod::UI.puts("#{message_prefix}: Setting CC, LD, CXX & LDPLUSPLUS build settings")
103+
# Using scripts wrapping the ccache executable, to allow injection of configurations
104+
ccache_clang_sh = File.join("$(REACT_NATIVE_PATH)", 'scripts', 'xcode', 'ccache-clang.sh')
105+
ccache_clangpp_sh = File.join("$(REACT_NATIVE_PATH)", 'scripts', 'xcode', 'ccache-clang++.sh')
106+
107+
projects.each do |project|
108+
project.build_configurations.each do |config|
109+
# Using the un-qualified names means you can swap in different implementations, for example ccache
110+
config.build_settings["CC"] = ccache_clang_sh
111+
config.build_settings["LD"] = ccache_clang_sh
112+
config.build_settings["CXX"] = ccache_clangpp_sh
113+
config.build_settings["LDPLUSPLUS"] = ccache_clangpp_sh
114+
end
115+
116+
project.save()
117+
end
118+
elsif ccache_available and !ccache_enabled
119+
Pod::UI.puts("#{message_prefix}: Pass ':ccache_enabled => true' to 'react_native_post_install' in your Podfile or set environment variable 'USE_CCACHE=1' to increase the speed of subsequent builds")
120+
elsif !ccache_available and ccache_enabled
121+
Pod::UI.warn("#{message_prefix}: Install ccache or ensure your neither passing ':ccache_enabled => true' nor setting environment variable 'USE_CCACHE=1'")
122+
end
123+
end
124+
89125
def self.fix_library_search_paths(installer)
90126
projects = self.extract_projects(installer)
91127

packages/react-native/scripts/react_native_pods.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@ def get_default_flags()
259259
def react_native_post_install(
260260
installer,
261261
react_native_path = "../node_modules/react-native",
262-
mac_catalyst_enabled: false
262+
mac_catalyst_enabled: false,
263+
ccache_enabled: ENV['USE_CCACHE'] == '1'
263264
)
264265
ReactNativePodsUtils.turn_off_resource_bundle_react_core(installer)
265266

@@ -276,6 +277,7 @@ def react_native_post_install(
276277
ReactNativePodsUtils.update_search_paths(installer)
277278
ReactNativePodsUtils.set_use_hermes_build_setting(installer, hermes_enabled)
278279
ReactNativePodsUtils.set_node_modules_user_settings(installer, react_native_path)
280+
ReactNativePodsUtils.set_ccache_compiler_and_linker_build_settings(installer, react_native_path, ccache_enabled)
279281
ReactNativePodsUtils.apply_xcode_15_patch(installer)
280282
ReactNativePodsUtils.apply_ats_config(installer)
281283
ReactNativePodsUtils.updateOSDeploymentTarget(installer)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/sh
2+
# Copyright (c) Meta Platforms, Inc. and affiliates.
3+
#
4+
# This source code is licensed under the MIT license found in the
5+
# LICENSE file in the root directory of this source tree.
6+
7+
# Get the absolute path of this script
8+
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
9+
10+
REACT_NATIVE_CCACHE_CONFIGPATH=$SCRIPT_DIR/ccache.conf
11+
# Provide our config file if none is already provided
12+
export CCACHE_CONFIGPATH="${CCACHE_CONFIGPATH:-$REACT_NATIVE_CCACHE_CONFIGPATH}"
13+
14+
exec ccache clang++ "$@"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/sh
2+
# Copyright (c) Meta Platforms, Inc. and affiliates.
3+
#
4+
# This source code is licensed under the MIT license found in the
5+
# LICENSE file in the root directory of this source tree.
6+
7+
# Get the absolute path of this script
8+
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
9+
10+
REACT_NATIVE_CCACHE_CONFIGPATH=$SCRIPT_DIR/ccache.conf
11+
# Provide our config file if none is already provided
12+
export CCACHE_CONFIGPATH="${CCACHE_CONFIGPATH:-$REACT_NATIVE_CCACHE_CONFIGPATH}"
13+
14+
exec ccache clang "$@"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
#
3+
# This source code is licensed under the MIT license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
# See https://ccache.dev/manual/4.3.html#_configuration_options for details and available options
7+
8+
sloppiness = clang_index_store,file_stat_matches,include_file_ctime,include_file_mtime,ivfsoverlay,pch_defines,modules,system_headers,time_macros
9+
file_clone = true
10+
depend_mode = true
11+
inode_cache = true

packages/react-native/template/ios/Podfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ target 'HelloWorld' do
3333
react_native_post_install(
3434
installer,
3535
config[:reactNativePath],
36-
:mac_catalyst_enabled => false
36+
:mac_catalyst_enabled => false,
37+
# :ccache_enabled => true
3738
)
3839
end
3940
end

0 commit comments

Comments
 (0)