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 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); diff --git a/packages/cmake-rn/src/platforms/android.ts b/packages/cmake-rn/src/platforms/android.ts index 479fdc92..f058802a 100644 --- a/packages/cmake-rn/src/platforms/android.ts +++ b/packages/cmake-rn/src/platforms/android.ts @@ -49,6 +49,44 @@ 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; +} + +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", @@ -85,26 +123,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, @@ -174,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( @@ -210,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, }); } 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,