From 14bbbbb1e7313a0594a40f85b14214100ddb0f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Thu, 23 Oct 2025 15:02:20 +0200 Subject: [PATCH 1/5] Refactored getting the NDK path and CMake toolchain into functions --- packages/cmake-rn/src/platforms/android.ts | 50 +++++++++++++--------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/packages/cmake-rn/src/platforms/android.ts b/packages/cmake-rn/src/platforms/android.ts index 479fdc92..75182d58 100644 --- a/packages/cmake-rn/src/platforms/android.ts +++ b/packages/cmake-rn/src/platforms/android.ts @@ -49,6 +49,34 @@ function getBuildPath(baseBuildPath: string, triplet: Triplet) { return path.join(baseBuildPath, triplet); } +function getNdkPath(ndkVersion: string) { + const { ANDROID_HOME } = process.env; + assert(typeof ANDROID_HOME === "string", "Missing env variable ANDROID_HOME"); + assert( + fs.existsSync(ANDROID_HOME), + `Expected the Android SDK at ${ANDROID_HOME}`, + ); + const installNdkCommand = `sdkmanager --install "ndk;${ndkVersion}"`; + const ndkPath = path.resolve(ANDROID_HOME, "ndk", ndkVersion); + assert( + fs.existsSync(ndkPath), + `Missing Android NDK v${ndkVersion} (at ${ndkPath}) - run: ${installNdkCommand}`, + ); + return ndkPath; +} + +function getNdkToolchainPath(ndkPath: string) { + const toolchainPath = path.join( + ndkPath, + "build/cmake/android.toolchain.cmake", + ); + assert( + fs.existsSync(toolchainPath), + `No CMake toolchain found in ${toolchainPath}`, + ); + return toolchainPath; +} + export const platform: Platform = { id: "android", name: "Android", @@ -85,26 +113,8 @@ export const platform: Platform = { cmakeJs, }, ) { - const { ANDROID_HOME } = process.env; - assert( - typeof ANDROID_HOME === "string", - "Missing env variable ANDROID_HOME", - ); - assert( - fs.existsSync(ANDROID_HOME), - `Expected the Android SDK at ${ANDROID_HOME}`, - ); - const installNdkCommand = `sdkmanager --install "ndk;${ndkVersion}"`; - const ndkPath = path.resolve(ANDROID_HOME, "ndk", ndkVersion); - assert( - fs.existsSync(ndkPath), - `Missing Android NDK v${ndkVersion} (at ${ndkPath}) - run: ${installNdkCommand}`, - ); - - const toolchainPath = path.join( - ndkPath, - "build/cmake/android.toolchain.cmake", - ); + const ndkPath = getNdkPath(ndkVersion); + const toolchainPath = getNdkToolchainPath(ndkPath); const commonDefinitions = [ ...define, From 8ec3f418594ca9b9f4bab66eaeb19726efcc5c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Thu, 23 Oct 2025 15:09:47 +0200 Subject: [PATCH 2/5] Add strip option to cmake-rn --- packages/cmake-rn/src/cli.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/cmake-rn/src/cli.ts b/packages/cmake-rn/src/cli.ts index 2639c13d..f2e45f47 100644 --- a/packages/cmake-rn/src/cli.ts +++ b/packages/cmake-rn/src/cli.ts @@ -106,6 +106,11 @@ const targetOption = new Option( "CMake targets to build", ).default([] as string[], "Build all targets of the CMake project"); +const stripOption = new Option( + "--strip", + "Strip debug symbols from the final binaries", +).default(false); + const noAutoLinkOption = new Option( "--no-auto-link", "Don't mark the output as auto-linkable by react-native-node-api", @@ -132,6 +137,7 @@ let program = new Command("cmake-rn") .addOption(defineOption) .addOption(cleanOption) .addOption(targetOption) + .addOption(stripOption) .addOption(noAutoLinkOption) .addOption(noWeakNodeApiLinkageOption) .addOption(cmakeJsOption); From f60086617ab21df890708d6152697c275b03d11e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Thu, 23 Oct 2025 15:10:28 +0200 Subject: [PATCH 3/5] Locate and call NDK strip tool on Android libraries --- packages/cmake-rn/src/platforms/android.ts | 31 +++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/cmake-rn/src/platforms/android.ts b/packages/cmake-rn/src/platforms/android.ts index 75182d58..f058802a 100644 --- a/packages/cmake-rn/src/platforms/android.ts +++ b/packages/cmake-rn/src/platforms/android.ts @@ -77,6 +77,16 @@ function getNdkToolchainPath(ndkPath: string) { return toolchainPath; } +function getNdkLlvmBinPath(ndkPath: string) { + const prebuiltPath = path.join(ndkPath, "toolchains/llvm/prebuilt"); + const platforms = fs.readdirSync(prebuiltPath); + assert( + platforms.length === 1, + `Expected a single llvm prebuilt toolchain in ${prebuiltPath}`, + ); + return path.join(prebuiltPath, platforms[0], "bin"); +} + export const platform: Platform = { id: "android", name: "Android", @@ -184,14 +194,14 @@ export const platform: Platform = { async postBuild( outputPath, triplets, - { autoLink, configuration, target, build }, + { autoLink, configuration, target, build, strip, ndkVersion }, ) { const prebuilds: Record< string, { triplet: Triplet; libraryPath: string }[] > = {}; - for (const { triplet } of triplets) { + for (const { spawn, triplet } of triplets) { const buildPath = getBuildPath(build, triplet); assert(fs.existsSync(buildPath), `Expected a directory at ${buildPath}`); const targets = await cmakeFileApi.readCurrentTargetsDeep( @@ -220,9 +230,24 @@ export const platform: Platform = { if (!(sharedLibrary.name in prebuilds)) { prebuilds[sharedLibrary.name] = []; } + const libraryPath = path.join(buildPath, artifact.path); + assert( + fs.existsSync(libraryPath), + `Expected built library at ${libraryPath}`, + ); + + if (strip) { + const llvmBinPath = getNdkLlvmBinPath(getNdkPath(ndkVersion)); + const stripToolPath = path.join(llvmBinPath, `llvm-strip`); + assert( + fs.existsSync(stripToolPath), + `Expected llvm-strip to exist at ${stripToolPath}`, + ); + await spawn(stripToolPath, [libraryPath]); + } prebuilds[sharedLibrary.name].push({ triplet, - libraryPath: path.join(buildPath, artifact.path), + libraryPath, }); } From 4204f5d1d384272c2bc54cddab9835c64ba5fd33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Thu, 23 Oct 2025 15:19:09 +0200 Subject: [PATCH 4/5] Add stripping to Apple libraries --- packages/cmake-rn/src/platforms/apple.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/cmake-rn/src/platforms/apple.ts b/packages/cmake-rn/src/platforms/apple.ts index 6edc6065..3c09ab18 100644 --- a/packages/cmake-rn/src/platforms/apple.ts +++ b/packages/cmake-rn/src/platforms/apple.ts @@ -330,11 +330,11 @@ export const platform: Platform = { async postBuild( outputPath, triplets, - { configuration, autoLink, xcframeworkExtension, target, build }, + { configuration, autoLink, xcframeworkExtension, target, build, strip }, ) { const libraryNames = new Set(); const frameworkPaths: string[] = []; - for (const { triplet } of triplets) { + for (const { spawn, triplet } of triplets) { const buildPath = getBuildPath(build, triplet); assert(fs.existsSync(buildPath), `Expected a directory at ${buildPath}`); const sharedLibrary = await readCmakeSharedLibraryTarget( @@ -348,10 +348,21 @@ export const platform: Platform = { "Expected exactly one artifact", ); const [artifact] = artifacts; + + const artifactPath = path.join(buildPath, artifact.path); + + if (strip) { + // -r: All relocation entries. + // -S: All symbol table entries. + // -T: All text relocation entries. + // -x: All local symbols. + await spawn("strip", ["-rSTx", artifactPath]); + } + libraryNames.add(sharedLibrary.name); // Locate the path of the framework, if a free dynamic library was built if (artifact.path.includes(".framework/")) { - frameworkPaths.push(path.dirname(path.join(buildPath, artifact.path))); + frameworkPaths.push(path.dirname(artifactPath)); } else { const libraryName = path.basename( artifact.path, From 22952b9290ef3215871368ea2f4890e4a93398ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Thu, 23 Oct 2025 15:23:58 +0200 Subject: [PATCH 5/5] Add changeset --- .changeset/great-kings-clean.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/great-kings-clean.md diff --git a/.changeset/great-kings-clean.md b/.changeset/great-kings-clean.md new file mode 100644 index 00000000..d8f7fb75 --- /dev/null +++ b/.changeset/great-kings-clean.md @@ -0,0 +1,5 @@ +--- +"cmake-rn": patch +--- + +Add `--strip` option to strip debug symbols from outputs