Skip to content

Detect and use Ccache in cmake-rn #139

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ jobs:
with:
packages: tools platform-tools ndk;${{ env.NDK_VERSION }}
- run: rustup target add x86_64-linux-android aarch64-linux-android armv7-linux-androideabi i686-linux-android aarch64-apple-ios-sim
- name: ccache
uses: hendrikmuhs/[email protected]
- run: npm ci
- run: npm run bootstrap
- run: npm test
Expand All @@ -73,6 +75,8 @@ jobs:
with:
packages: tools platform-tools ndk;${{ env.NDK_VERSION }}
- run: rustup target add x86_64-linux-android aarch64-linux-android armv7-linux-androideabi i686-linux-android aarch64-apple-ios-sim
- name: ccache
uses: hendrikmuhs/[email protected]
- run: npm ci
- run: npm run bootstrap
- run: npm run pod-install
Expand Down Expand Up @@ -101,6 +105,8 @@ jobs:
with:
packages: tools platform-tools ndk;${{ env.NDK_VERSION }}
- run: rustup target add x86_64-linux-android aarch64-linux-android armv7-linux-androideabi i686-linux-android aarch64-apple-ios-sim
- name: ccache
uses: hendrikmuhs/[email protected]
- run: npm ci
- run: npm run bootstrap
- name: Clone patched Hermes version
Expand Down
9 changes: 9 additions & 0 deletions apps/test-app/ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,13 @@ ws_dir = ws_dir.parent until
ws_dir.expand_path.to_s == '/'
require "#{ws_dir}/node_modules/react-native-test-app/test_app.rb"

# Disabling ccache for now, as I'm getting lots of warnings:
# Explicit modules is enabled but the compiler was not recognized; disable explicit modules with CLANG_ENABLE_EXPLICIT_MODULES=NO, or use C_COMPILER_LAUNCHER with CLANG_ENABLE_EXPLICIT_MODULES_WITH_COMPILER_LAUNCHER=YES if using a compatible launcher
# I could get this working by patching React Native's utils.rb to set
# config.build_settings["CLANG_ENABLE_EXPLICIT_MODULES"] = "NO"
# config.build_settings["COMPILER_INDEX_STORE_ENABLE"] = "NO"
# but I'm still seeing compiler errors after that.

# ENV['USE_CCACHE'] = ENV['USE_CCACHE'] || Pod::Executable::which('ccache') ? '1' : '0'

use_test_app! :hermes_enabled => true, :fabric_enabled => true, :bridgeless_enabled => true
16 changes: 16 additions & 0 deletions packages/cmake-rn/scripts/ccache-clang++.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/sh

# reference for xcode specific cacche settings: reactnative docs and ccache manpage
# https://reactnative.dev/docs/build-speed#xcode-specific-setup
# https://ccache.dev/manual/4.3.html

export CCACHE_MAXSIZE=10G
export CCACHE_CPP2=true
export CCACHE_DIRECT=true
export CCACHE_DEPEND=true
export CCACHE_HARDLINK=true
export CCACHE_FILECLONE=true
export CCACHE_INODECACHE=true
export CCACHE_SLOPPINESS=file_macro,time_macros,include_file_mtime,include_file_ctime,file_stat_matches,modules,ivfsoverlay,pch_defines,system_headers

exec ccache clang++ "$@"
16 changes: 16 additions & 0 deletions packages/cmake-rn/scripts/ccache-clang.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/sh

# reference for xcode specific cacche settings: reactnative docs and ccache manpage
# https://reactnative.dev/docs/build-speed#xcode-specific-setup
# https://ccache.dev/manual/4.3.html

export CCACHE_MAXSIZE=10G
export CCACHE_CPP2=true
export CCACHE_DIRECT=true
export CCACHE_DEPEND=true
export CCACHE_HARDLINK=true
export CCACHE_FILECLONE=true
export CCACHE_INODECACHE=true
export CCACHE_SLOPPINESS=file_macro,time_macros,include_file_mtime,include_file_ctime,file_stat_matches,modules,ivfsoverlay,pch_defines,system_headers

exec ccache clang "$@"
14 changes: 10 additions & 4 deletions packages/cmake-rn/src/android.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ type AndroidConfigureOptions = {
triplet: AndroidTriplet;
ndkVersion: string;
sdkVersion: string;
ccache: boolean;
};

export function getAndroidConfigureCmakeArgs({
triplet,
ndkVersion,
sdkVersion,
ccache,
}: AndroidConfigureOptions) {
const { ANDROID_HOME } = process.env;
assert(typeof ANDROID_HOME === "string", "Missing env variable ANDROID_HOME");
Expand Down Expand Up @@ -72,10 +74,14 @@ export function getAndroidConfigureCmakeArgs({
// `CMAKE_BUILD_TYPE=${configuration}`,
"-D",
"CMAKE_MAKE_PROGRAM=ninja",
// "-D",
// "CMAKE_C_COMPILER_LAUNCHER=ccache",
// "-D",
// "CMAKE_CXX_COMPILER_LAUNCHER=ccache",
...(ccache
? [
"-D",
"CMAKE_C_COMPILER_LAUNCHER=ccache",
"-D",
"CMAKE_CXX_COMPILER_LAUNCHER=ccache",
]
: []),
"-D",
`ANDROID_NDK=${ndkPath}`,
"-D",
Expand Down
23 changes: 22 additions & 1 deletion packages/cmake-rn/src/apple.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import assert from "node:assert/strict";
import path from "node:path";

import { AppleTriplet, isAppleTriplet } from "react-native-node-api";

const scriptsPath = path.join(import.meta.dirname, "..", "scripts");
const ccacheClangPath = path.join(scriptsPath, "ccache-clang.sh");
const ccacheClangPPPath = path.join(scriptsPath, "ccache-clang++.sh");

export const DEFAULT_APPLE_TRIPLETS = [
"arm64;x86_64-apple-darwin",
"arm64-apple-ios",
Expand Down Expand Up @@ -82,9 +87,13 @@ export function createPlistContent(values: Record<string, string>) {

type AppleConfigureOptions = {
triplet: AppleTriplet;
ccache: boolean;
};

export function getAppleConfigureCmakeArgs({ triplet }: AppleConfigureOptions) {
export function getAppleConfigureCmakeArgs({
triplet,
ccache,
}: AppleConfigureOptions) {
assert(isAppleTriplet(triplet));
const systemName = CMAKE_SYSTEM_NAMES[triplet];

Expand All @@ -100,6 +109,18 @@ export function getAppleConfigureCmakeArgs({ triplet }: AppleConfigureOptions) {
// Set the target architecture
"-D",
`CMAKE_OSX_ARCHITECTURES=${APPLE_ARCHITECTURES[triplet]}`,
...(ccache
? [
"-D",
`CMAKE_XCODE_ATTRIBUTE_CC=${ccacheClangPath}`,
"-D",
`CMAKE_XCODE_ATTRIBUTE_CXX=${ccacheClangPPPath}`,
"-D",
`CMAKE_XCODE_ATTRIBUTE_LD=${ccacheClangPath}`,
"-D",
`CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS=${ccacheClangPPPath}`,
]
: []),
];
}

Expand Down
10 changes: 10 additions & 0 deletions packages/cmake-rn/src/ccache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import cp from "node:child_process";

export function getCcacheVersion(): string | undefined {
const { status, stdout } = cp.spawnSync("ccache", ["--print-version"], {
encoding: "utf8",
});
if (status === 0) {
return stdout.trim();
}
}
25 changes: 23 additions & 2 deletions packages/cmake-rn/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
createXCframework,
determineXCFrameworkFilename,
} from "react-native-node-api";
import { getCcacheVersion } from "./ccache.js";

// We're attaching a lot of listeners when spawning in parallel
EventEmitter.defaultMaxListeners = 100;
Expand Down Expand Up @@ -109,6 +110,11 @@ const xcframeworkExtensionOption = new Option(
"Don't rename the xcframework to .apple.node"
).default(false);

const noCcacheOption = new Option(
"--no-ccache",
"Don't detect and use ccache to speed up builds"
);

export const program = new Command("cmake-rn")
.description("Build React Native Node API modules with CMake")
.addOption(verboseOption)
Expand All @@ -120,13 +126,24 @@ export const program = new Command("cmake-rn")
.addOption(buildPathOption)
.addOption(outPathOption)
.addOption(cleanOption)
.addOption(noCcacheOption)
.addOption(ndkVersionOption)
.addOption(androidSdkVersionOption)
.addOption(noAutoLinkOption)
.addOption(noWeakNodeApiLinkageOption)
.addOption(xcframeworkExtensionOption)
.action(async ({ triplet: tripletValues, ...globalContext }) => {
try {
const ccacheVersion = globalContext.ccache
? getCcacheVersion()
: undefined;
if (ccacheVersion) {
console.log("⚡️Using ccache", chalk.dim(`(${ccacheVersion})`));
} else {
// Disable ccache if not found
globalContext.ccache = false;
}

const buildPath = getBuildPath(globalContext);
if (globalContext.clean) {
await fs.promises.rm(buildPath, { recursive: true, force: true });
Expand Down Expand Up @@ -364,19 +381,21 @@ function getTripletConfigureCmakeArgs(
{
ndkVersion,
androidSdkVersion,
ccache,
}: Pick<
GlobalContext,
"ndkVersion" | "androidSdkVersion" | "weakNodeApiLinkage"
"ndkVersion" | "androidSdkVersion" | "weakNodeApiLinkage" | "ccache"
>
) {
if (isAndroidTriplet(triplet)) {
return getAndroidConfigureCmakeArgs({
triplet,
ndkVersion,
sdkVersion: androidSdkVersion,
ccache,
});
} else if (isAppleTriplet(triplet)) {
return getAppleConfigureCmakeArgs({ triplet });
return getAppleConfigureCmakeArgs({ triplet, ccache });
} else {
throw new Error(`Support for '${triplet}' is not implemented yet`);
}
Expand All @@ -398,6 +417,7 @@ async function configureProject(context: TripletScopedContext) {
triplet,
tripletBuildPath,
source,
ccache,
ndkVersion,
androidSdkVersion,
weakNodeApiLinkage,
Expand All @@ -411,6 +431,7 @@ async function configureProject(context: TripletScopedContext) {
tripletBuildPath,
...getVariablesArgs(getVariables(context)),
...getTripletConfigureCmakeArgs(triplet, {
ccache,
ndkVersion,
weakNodeApiLinkage,
androidSdkVersion,
Expand Down
Loading