Skip to content

Commit dd51acd

Browse files
committed
Detect and use ccache in cmake-rn
1 parent f264163 commit dd51acd

File tree

6 files changed

+97
-7
lines changed

6 files changed

+97
-7
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/sh
2+
3+
# reference for xcode specific cacche settings: reactnative docs and ccache manpage
4+
# https://reactnative.dev/docs/build-speed#xcode-specific-setup
5+
# https://ccache.dev/manual/4.3.html
6+
7+
export CCACHE_MAXSIZE=10G
8+
export CCACHE_CPP2=true
9+
export CCACHE_DIRECT=true
10+
export CCACHE_DEPEND=true
11+
export CCACHE_HARDLINK=true
12+
export CCACHE_FILECLONE=true
13+
export CCACHE_INODECACHE=true
14+
export CCACHE_SLOPPINESS=file_macro,time_macros,include_file_mtime,include_file_ctime,file_stat_matches,modules,ivfsoverlay,pch_defines,system_headers
15+
16+
exec ccache clang++ "$@"
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/sh
2+
3+
# reference for xcode specific cacche settings: reactnative docs and ccache manpage
4+
# https://reactnative.dev/docs/build-speed#xcode-specific-setup
5+
# https://ccache.dev/manual/4.3.html
6+
7+
export CCACHE_MAXSIZE=10G
8+
export CCACHE_CPP2=true
9+
export CCACHE_DIRECT=true
10+
export CCACHE_DEPEND=true
11+
export CCACHE_HARDLINK=true
12+
export CCACHE_FILECLONE=true
13+
export CCACHE_INODECACHE=true
14+
export CCACHE_SLOPPINESS=file_macro,time_macros,include_file_mtime,include_file_ctime,file_stat_matches,modules,ivfsoverlay,pch_defines,system_headers
15+
16+
exec ccache clang "$@"

packages/cmake-rn/src/android.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ type AndroidConfigureOptions = {
2424
triplet: AndroidTriplet;
2525
ndkVersion: string;
2626
sdkVersion: string;
27+
ccache: boolean;
2728
};
2829

2930
export function getAndroidConfigureCmakeArgs({
3031
triplet,
3132
ndkVersion,
3233
sdkVersion,
34+
ccache,
3335
}: AndroidConfigureOptions) {
3436
const { ANDROID_HOME } = process.env;
3537
assert(typeof ANDROID_HOME === "string", "Missing env variable ANDROID_HOME");
@@ -72,10 +74,14 @@ export function getAndroidConfigureCmakeArgs({
7274
// `CMAKE_BUILD_TYPE=${configuration}`,
7375
"-D",
7476
"CMAKE_MAKE_PROGRAM=ninja",
75-
// "-D",
76-
// "CMAKE_C_COMPILER_LAUNCHER=ccache",
77-
// "-D",
78-
// "CMAKE_CXX_COMPILER_LAUNCHER=ccache",
77+
...(ccache
78+
? [
79+
"-D",
80+
"CMAKE_C_COMPILER_LAUNCHER=ccache",
81+
"-D",
82+
"CMAKE_CXX_COMPILER_LAUNCHER=ccache",
83+
]
84+
: []),
7985
"-D",
8086
`ANDROID_NDK=${ndkPath}`,
8187
"-D",

packages/cmake-rn/src/apple.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import assert from "node:assert/strict";
2+
import path from "node:path";
23

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

6+
const scriptsPath = path.join(import.meta.dirname, "..", "scripts");
7+
const ccacheClangPath = path.join(scriptsPath, "ccache-clang.sh");
8+
const ccacheClangPPPath = path.join(scriptsPath, "ccache-clang++.sh");
9+
510
export const DEFAULT_APPLE_TRIPLETS = [
611
"arm64;x86_64-apple-darwin",
712
"arm64-apple-ios",
@@ -82,9 +87,13 @@ export function createPlistContent(values: Record<string, string>) {
8287

8388
type AppleConfigureOptions = {
8489
triplet: AppleTriplet;
90+
ccache: boolean;
8591
};
8692

87-
export function getAppleConfigureCmakeArgs({ triplet }: AppleConfigureOptions) {
93+
export function getAppleConfigureCmakeArgs({
94+
triplet,
95+
ccache,
96+
}: AppleConfigureOptions) {
8897
assert(isAppleTriplet(triplet));
8998
const systemName = CMAKE_SYSTEM_NAMES[triplet];
9099

@@ -100,6 +109,18 @@ export function getAppleConfigureCmakeArgs({ triplet }: AppleConfigureOptions) {
100109
// Set the target architecture
101110
"-D",
102111
`CMAKE_OSX_ARCHITECTURES=${APPLE_ARCHITECTURES[triplet]}`,
112+
...(ccache
113+
? [
114+
"-D",
115+
`CMAKE_XCODE_ATTRIBUTE_CC=${ccacheClangPath}`,
116+
"-D",
117+
`CMAKE_XCODE_ATTRIBUTE_CXX=${ccacheClangPPPath}`,
118+
"-D",
119+
`CMAKE_XCODE_ATTRIBUTE_LD=${ccacheClangPath}`,
120+
"-D",
121+
`CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS=${ccacheClangPPPath}`,
122+
]
123+
: []),
103124
];
104125
}
105126

packages/cmake-rn/src/ccache.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import cp from "node:child_process";
2+
3+
export function getCcacheVersion(): string | undefined {
4+
const { status, stdout } = cp.spawnSync("ccache", ["--print-version"], {
5+
encoding: "utf8",
6+
});
7+
if (status === 0) {
8+
return stdout.trim();
9+
}
10+
}

packages/cmake-rn/src/cli.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
createXCframework,
3434
determineXCFrameworkFilename,
3535
} from "react-native-node-api";
36+
import { getCcacheVersion } from "./ccache.js";
3637

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

113+
const noCcacheOption = new Option(
114+
"--no-ccache",
115+
"Don't detect and use ccache to speed up builds"
116+
);
117+
112118
export const program = new Command("cmake-rn")
113119
.description("Build React Native Node API modules with CMake")
114120
.addOption(verboseOption)
@@ -120,13 +126,24 @@ export const program = new Command("cmake-rn")
120126
.addOption(buildPathOption)
121127
.addOption(outPathOption)
122128
.addOption(cleanOption)
129+
.addOption(noCcacheOption)
123130
.addOption(ndkVersionOption)
124131
.addOption(androidSdkVersionOption)
125132
.addOption(noAutoLinkOption)
126133
.addOption(noWeakNodeApiLinkageOption)
127134
.addOption(xcframeworkExtensionOption)
128135
.action(async ({ triplet: tripletValues, ...globalContext }) => {
129136
try {
137+
const ccacheVersion = globalContext.ccache
138+
? getCcacheVersion()
139+
: undefined;
140+
if (ccacheVersion) {
141+
console.log("⚡️Using ccache", chalk.dim(`(${ccacheVersion})`));
142+
} else {
143+
// Disable ccache if not found
144+
globalContext.ccache = false;
145+
}
146+
130147
const buildPath = getBuildPath(globalContext);
131148
if (globalContext.clean) {
132149
await fs.promises.rm(buildPath, { recursive: true, force: true });
@@ -364,19 +381,21 @@ function getTripletConfigureCmakeArgs(
364381
{
365382
ndkVersion,
366383
androidSdkVersion,
384+
ccache,
367385
}: Pick<
368386
GlobalContext,
369-
"ndkVersion" | "androidSdkVersion" | "weakNodeApiLinkage"
387+
"ndkVersion" | "androidSdkVersion" | "weakNodeApiLinkage" | "ccache"
370388
>
371389
) {
372390
if (isAndroidTriplet(triplet)) {
373391
return getAndroidConfigureCmakeArgs({
374392
triplet,
375393
ndkVersion,
376394
sdkVersion: androidSdkVersion,
395+
ccache,
377396
});
378397
} else if (isAppleTriplet(triplet)) {
379-
return getAppleConfigureCmakeArgs({ triplet });
398+
return getAppleConfigureCmakeArgs({ triplet, ccache });
380399
} else {
381400
throw new Error(`Support for '${triplet}' is not implemented yet`);
382401
}
@@ -398,6 +417,7 @@ async function configureProject(context: TripletScopedContext) {
398417
triplet,
399418
tripletBuildPath,
400419
source,
420+
ccache,
401421
ndkVersion,
402422
androidSdkVersion,
403423
weakNodeApiLinkage,
@@ -411,6 +431,7 @@ async function configureProject(context: TripletScopedContext) {
411431
tripletBuildPath,
412432
...getVariablesArgs(getVariables(context)),
413433
...getTripletConfigureCmakeArgs(triplet, {
434+
ccache,
414435
ndkVersion,
415436
weakNodeApiLinkage,
416437
androidSdkVersion,

0 commit comments

Comments
 (0)