From 94eeae6f9486a7c2d960d56e77a23aca9267362b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Fri, 19 Sep 2025 21:47:46 +0200 Subject: [PATCH 1/2] Rename target to triplet --- .github/workflows/check.yml | 4 +- packages/cmake-rn/CHANGELOG.md | 2 +- packages/cmake-rn/src/cli.ts | 131 +++++++++++---------- packages/cmake-rn/src/platforms.test.ts | 24 ++-- packages/cmake-rn/src/platforms.ts | 18 +-- packages/cmake-rn/src/platforms/android.ts | 22 ++-- packages/cmake-rn/src/platforms/apple.ts | 26 ++-- packages/cmake-rn/src/platforms/types.ts | 28 ++--- 8 files changed, 131 insertions(+), 124 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 53c7f734..1cf4f24e 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -98,7 +98,7 @@ jobs: - run: npm ci - run: npm run bootstrap env: - CMAKE_RN_TARGETS: arm64-apple-ios-sim + CMAKE_RN_TRIPLETS: arm64-apple-ios-sim FERRIC_TARGETS: aarch64-apple-ios-sim - run: npm run pod-install working-directory: apps/test-app @@ -129,7 +129,7 @@ jobs: - run: npm ci - run: npm run bootstrap env: - CMAKE_RN_TARGETS: i686-linux-android + CMAKE_RN_TRIPLETS: i686-linux-android FERRIC_TARGETS: i686-linux-android - name: Clone patched Hermes version shell: bash diff --git a/packages/cmake-rn/CHANGELOG.md b/packages/cmake-rn/CHANGELOG.md index 90871c10..fcfd8ab2 100644 --- a/packages/cmake-rn/CHANGELOG.md +++ b/packages/cmake-rn/CHANGELOG.md @@ -22,7 +22,7 @@ ### Minor Changes -- 8557768: Derive default targets from the CMAKE_RN_TARGETS environment variable +- 8557768: Derive default targets from the CMAKE_RN_TRIPLETS environment variable ### Patch Changes diff --git a/packages/cmake-rn/src/cli.ts b/packages/cmake-rn/src/cli.ts index 6c102f74..8a8901ca 100644 --- a/packages/cmake-rn/src/cli.ts +++ b/packages/cmake-rn/src/cli.ts @@ -17,11 +17,11 @@ import { isSupportedTriplet } from "react-native-node-api"; import { getWeakNodeApiVariables } from "./weak-node-api.js"; import { platforms, - allTargets, - findPlatformForTarget, - platformHasTarget, + allTriplets as allTriplets, + findPlatformForTriplet, + platformHasTriplet, } from "./platforms.js"; -import { BaseOpts, TargetContext, Platform } from "./platforms/types.js"; +import { BaseOpts, TripletContext, Platform } from "./platforms/types.js"; // We're attaching a lot of listeners when spawning in parallel EventEmitter.defaultMaxListeners = 100; @@ -43,25 +43,28 @@ const configurationOption = new Option("--configuration ") .choices(["Release", "Debug"] as const) .default("Release"); -// TODO: Derive default targets +// TODO: Derive default build triplets // This is especially important when driving the build from within a React Native app package. -const { CMAKE_RN_TARGETS } = process.env; +const { CMAKE_RN_TRIPLETS } = process.env; -const defaultTargets = CMAKE_RN_TARGETS ? CMAKE_RN_TARGETS.split(",") : []; +const defaultTriplets = CMAKE_RN_TRIPLETS ? CMAKE_RN_TRIPLETS.split(",") : []; -for (const target of defaultTargets) { +for (const triplet of defaultTriplets) { assert( - (allTargets as string[]).includes(target), - `Unexpected target in CMAKE_RN_TARGETS: ${target}`, + (allTriplets as string[]).includes(triplet), + `Unexpected triplet in CMAKE_RN_TRIPLETS: ${triplet}`, ); } -const targetOption = new Option("--target ", "Targets to build for") - .choices(allTargets) +const tripletOption = new Option( + "--triplet ", + "Triplets to build for", +) + .choices(allTriplets) .default( - defaultTargets, - "CMAKE_RN_TARGETS environment variable split by ','", + defaultTriplets, + "CMAKE_RN_TRIPLETS environment variable split by ','", ); const buildPathOption = new Option( @@ -111,7 +114,7 @@ const noWeakNodeApiLinkageOption = new Option( let program = new Command("cmake-rn") .description("Build React Native Node API modules with CMake") - .addOption(targetOption) + .addOption(tripletOption) .addOption(verboseOption) .addOption(sourcePathOption) .addOption(buildPathOption) @@ -132,7 +135,7 @@ for (const platform of platforms) { } program = program.action( - wrapAction(async ({ target: requestedTargets, ...baseOptions }) => { + wrapAction(async ({ triplet: requestedTriplets, ...baseOptions }) => { assertFixable( fs.existsSync(path.join(baseOptions.source, "CMakeLists.txt")), `No CMakeLists.txt found in source directory: ${chalk.dim(baseOptions.source)}`, @@ -145,34 +148,34 @@ program = program.action( if (baseOptions.clean) { await fs.promises.rm(buildPath, { recursive: true, force: true }); } - const targets = new Set(requestedTargets); + const triplets = new Set(requestedTriplets); for (const platform of Object.values(platforms)) { // Forcing the types a bit here, since the platform id option is dynamically added if ((baseOptions as Record)[platform.id]) { - for (const target of platform.targets) { - targets.add(target); + for (const triplet of platform.triplets) { + triplets.add(triplet); } } } - if (targets.size === 0) { + if (triplets.size === 0) { for (const platform of Object.values(platforms)) { if (platform.isSupportedByHost()) { - for (const target of await platform.defaultTargets()) { - targets.add(target); + for (const triplet of await platform.defaultTriplets()) { + triplets.add(triplet); } } } - if (targets.size === 0) { + if (triplets.size === 0) { throw new Error( - "Found no default targets: Install some platform specific build tools", + "Found no default build triplets: Install some platform specific build tools", ); } else { console.error( chalk.yellowBright("ℹ"), - "Using default targets", - chalk.dim("(" + [...targets].join(", ") + ")"), + "Using default build triplets", + chalk.dim("(" + [...triplets].join(", ") + ")"), ); } } @@ -181,30 +184,32 @@ program = program.action( baseOptions.out = path.join(buildPath, baseOptions.configuration); } - const targetContexts = [...targets].map((target) => { - const platform = findPlatformForTarget(target); - const targetBuildPath = getTargetBuildPath(buildPath, target); + const tripletContexts = [...triplets].map((triplet) => { + const platform = findPlatformForTriplet(triplet); + const tripletBuildPath = getTripletBuildPath(buildPath, triplet); return { - target, + triplet, platform, - buildPath: targetBuildPath, - outputPath: path.join(targetBuildPath, "out"), + buildPath: tripletBuildPath, + outputPath: path.join(tripletBuildPath, "out"), options: baseOptions, }; }); // Configure every triplet project - const targetsSummary = chalk.dim(`(${getTargetsSummary(targetContexts)})`); + const tripletsSummary = chalk.dim( + `(${getTripletsSummary(tripletContexts)})`, + ); await oraPromise( Promise.all( - targetContexts.map(({ platform, ...context }) => + tripletContexts.map(({ platform, ...context }) => configureProject(platform, context, baseOptions), ), ), { - text: `Configuring projects ${targetsSummary}`, + text: `Configuring projects ${tripletsSummary}`, isSilent: baseOptions.verbose, - successText: `Configured projects ${targetsSummary}`, + successText: `Configured projects ${tripletsSummary}`, failText: ({ message }) => `Failed to configure projects: ${message}`, }, ); @@ -212,7 +217,7 @@ program = program.action( // Build every triplet project await oraPromise( Promise.all( - targetContexts.map(async ({ platform, ...context }) => { + tripletContexts.map(async ({ platform, ...context }) => { // Delete any stale build artifacts before building // This is important, since we might rename the output files await fs.promises.rm(context.outputPath, { @@ -232,16 +237,16 @@ program = program.action( // Perform post-build steps for each platform in sequence for (const platform of platforms) { - const relevantTargets = targetContexts.filter(({ target }) => - platformHasTarget(platform, target), + const relevantTriplets = tripletContexts.filter(({ triplet }) => + platformHasTriplet(platform, triplet), ); - if (relevantTargets.length == 0) { + if (relevantTriplets.length == 0) { continue; } await platform.postBuild( { outputPath: baseOptions.out || baseOptions.source, - targets: relevantTargets, + triplets: relevantTriplets, }, baseOptions, ); @@ -249,19 +254,19 @@ program = program.action( }), ); -function getTargetsSummary( - targetContexts: { target: string; platform: Platform }[], +function getTripletsSummary( + tripletContexts: { triplet: string; platform: Platform }[], ) { - const targetsPerPlatform: Record = {}; - for (const { target, platform } of targetContexts) { - if (!targetsPerPlatform[platform.id]) { - targetsPerPlatform[platform.id] = []; + const tripletsPerPlatform: Record = {}; + for (const { triplet, platform } of tripletContexts) { + if (!tripletsPerPlatform[platform.id]) { + tripletsPerPlatform[platform.id] = []; } - targetsPerPlatform[platform.id].push(target); + tripletsPerPlatform[platform.id].push(triplet); } - return Object.entries(targetsPerPlatform) - .map(([platformId, targets]) => { - return `${platformId}: ${targets.join(", ")}`; + return Object.entries(tripletsPerPlatform) + .map(([platformId, triplets]) => { + return `${platformId}: ${triplets.join(", ")}`; }) .join(" / "); } @@ -272,24 +277,24 @@ function getBuildPath({ build, source }: BaseOpts) { } /** - * Namespaces the output path with a target name + * Namespaces the output path with a triplet name */ -function getTargetBuildPath(buildPath: string, target: unknown) { - assert(typeof target === "string", "Expected target to be a string"); - return path.join(buildPath, target.replace(/;/g, "_")); +function getTripletBuildPath(buildPath: string, triplet: unknown) { + assert(typeof triplet === "string", "Expected triplet to be a string"); + return path.join(buildPath, triplet.replace(/;/g, "_")); } async function configureProject( platform: Platform>, - context: TargetContext, + context: TripletContext, options: BaseOpts, ) { - const { target, buildPath, outputPath } = context; + const { triplet, buildPath, outputPath } = context; const { verbose, source, weakNodeApiLinkage } = options; const nodeApiDefinitions = - weakNodeApiLinkage && isSupportedTriplet(target) - ? getWeakNodeApiVariables(target) + weakNodeApiLinkage && isSupportedTriplet(triplet) + ? getWeakNodeApiVariables(triplet) : // TODO: Make this a part of the platform definition {}; @@ -311,17 +316,17 @@ async function configureProject( ], { outputMode: verbose ? "inherit" : "buffered", - outputPrefix: verbose ? chalk.dim(`[${target}] `) : undefined, + outputPrefix: verbose ? chalk.dim(`[${triplet}] `) : undefined, }, ); } async function buildProject( platform: Platform>, - context: TargetContext, + context: TripletContext, options: BaseOpts, ) { - const { target, buildPath } = context; + const { triplet, buildPath } = context; const { verbose, configuration } = options; await spawn( "cmake", @@ -335,7 +340,7 @@ async function buildProject( ], { outputMode: verbose ? "inherit" : "buffered", - outputPrefix: verbose ? chalk.dim(`[${target}] `) : undefined, + outputPrefix: verbose ? chalk.dim(`[${triplet}] `) : undefined, }, ); } diff --git a/packages/cmake-rn/src/platforms.test.ts b/packages/cmake-rn/src/platforms.test.ts index 2f8c95f7..1d21c4ef 100644 --- a/packages/cmake-rn/src/platforms.test.ts +++ b/packages/cmake-rn/src/platforms.test.ts @@ -3,28 +3,30 @@ import { describe, it } from "node:test"; import { platforms, - platformHasTarget, - findPlatformForTarget, + platformHasTriplet, + findPlatformForTriplet, } from "./platforms.js"; import { Platform } from "./platforms/types.js"; -const mockPlatform = { targets: ["target1", "target2"] } as unknown as Platform; +const mockPlatform = { + triplets: ["triplet1", "triplet2"], +} as unknown as Platform; -describe("platformHasTarget", () => { - it("returns true when platform has target", () => { - assert.equal(platformHasTarget(mockPlatform, "target1"), true); +describe("platformHasTriplet", () => { + it("returns true when platform has triplet", () => { + assert.equal(platformHasTriplet(mockPlatform, "triplet1"), true); }); - it("returns false when platform doesn't have target", () => { - assert.equal(platformHasTarget(mockPlatform, "target3"), false); + it("returns false when platform doesn't have triplet", () => { + assert.equal(platformHasTriplet(mockPlatform, "triplet3"), false); }); }); -describe("findPlatformForTarget", () => { - it("returns platform when target is found", () => { +describe("findPlatformForTriplet", () => { + it("returns platform when triplet is found", () => { assert(platforms.length >= 2, "Expects at least two platforms"); const [platform1, platform2] = platforms; - const platform = findPlatformForTarget(platform1.targets[0]); + const platform = findPlatformForTriplet(platform1.triplets[0]); assert.equal(platform, platform1); assert.notEqual(platform, platform2); }); diff --git a/packages/cmake-rn/src/platforms.ts b/packages/cmake-rn/src/platforms.ts index cf892263..ed82cabb 100644 --- a/packages/cmake-rn/src/platforms.ts +++ b/packages/cmake-rn/src/platforms.ts @@ -5,23 +5,23 @@ import { platform as apple } from "./platforms/apple.js"; import { Platform } from "./platforms/types.js"; export const platforms: Platform[] = [android, apple] as const; -export const allTargets = [...android.targets, ...apple.targets] as const; +export const allTriplets = [...android.triplets, ...apple.triplets] as const; -export function platformHasTarget

( +export function platformHasTriplet

( platform: P, - target: unknown, -): target is P["targets"][number] { - return (platform.targets as unknown[]).includes(target); + triplet: unknown, +): triplet is P["triplets"][number] { + return (platform.triplets as unknown[]).includes(triplet); } -export function findPlatformForTarget(target: unknown) { +export function findPlatformForTriplet(triplet: unknown) { const platform = Object.values(platforms).find((platform) => - platformHasTarget(platform, target), + platformHasTriplet(platform, triplet), ); assert( platform, - `Unable to determine platform from target: ${ - typeof target === "string" ? target : JSON.stringify(target) + `Unable to determine platform from triplet: ${ + typeof triplet === "string" ? triplet : JSON.stringify(triplet) }`, ); return platform; diff --git a/packages/cmake-rn/src/platforms/android.ts b/packages/cmake-rn/src/platforms/android.ts index ef71afe1..832f806e 100644 --- a/packages/cmake-rn/src/platforms/android.ts +++ b/packages/cmake-rn/src/platforms/android.ts @@ -6,7 +6,7 @@ import { Option, oraPromise, chalk } from "@react-native-node-api/cli-utils"; import { createAndroidLibsDirectory, determineAndroidLibsFilename, - AndroidTriplet as Target, + AndroidTriplet as Triplet, } from "react-native-node-api"; import type { Platform } from "./types.js"; @@ -22,7 +22,7 @@ export const ANDROID_ARCHITECTURES = { "aarch64-linux-android": "arm64-v8a", "i686-linux-android": "x86", "x86_64-linux-android": "x86_64", -} satisfies Record; +} satisfies Record; const ndkVersionOption = new Option( "--ndk-version ", @@ -36,16 +36,16 @@ const androidSdkVersionOption = new Option( type AndroidOpts = { ndkVersion: string; androidSdkVersion: string }; -export const platform: Platform = { +export const platform: Platform = { id: "android", name: "Android", - targets: [ + triplets: [ "aarch64-linux-android", "armv7a-linux-androideabi", "i686-linux-android", "x86_64-linux-android", ], - defaultTargets() { + defaultTriplets() { if (process.arch === "arm64") { return ["aarch64-linux-android"]; } else if (process.arch === "x64") { @@ -59,7 +59,7 @@ export const platform: Platform = { .addOption(ndkVersionOption) .addOption(androidSdkVersionOption); }, - configureArgs({ target }, { ndkVersion, androidSdkVersion }) { + configureArgs({ triplet }, { ndkVersion, androidSdkVersion }) { const { ANDROID_HOME } = process.env; assert( typeof ANDROID_HOME === "string", @@ -80,7 +80,7 @@ export const platform: Platform = { ndkPath, "build/cmake/android.toolchain.cmake", ); - const architecture = ANDROID_ARCHITECTURES[target]; + const architecture = ANDROID_ARCHITECTURES[triplet]; return [ "-G", @@ -121,11 +121,11 @@ export const platform: Platform = { const { ANDROID_HOME } = process.env; return typeof ANDROID_HOME === "string" && fs.existsSync(ANDROID_HOME); }, - async postBuild({ outputPath, targets }, { autoLink }) { + async postBuild({ outputPath, triplets }, { autoLink }) { // TODO: Include `configuration` in the output path const libraryPathByTriplet = Object.fromEntries( await Promise.all( - targets.map(async ({ target, outputPath }) => { + triplets.map(async ({ triplet, outputPath }) => { assert( fs.existsSync(outputPath), `Expected a directory at ${outputPath}`, @@ -142,10 +142,10 @@ export const platform: Platform = { ) .map((dirent) => path.join(dirent.parentPath, dirent.name)); assert.equal(result.length, 1, "Expected exactly one library file"); - return [target, result[0]] as const; + return [triplet, result[0]] as const; }), ), - ) as Record; + ) as Record; const androidLibsFilename = determineAndroidLibsFilename( Object.values(libraryPathByTriplet), ); diff --git a/packages/cmake-rn/src/platforms/apple.ts b/packages/cmake-rn/src/platforms/apple.ts index c92c5b9c..00e21c72 100644 --- a/packages/cmake-rn/src/platforms/apple.ts +++ b/packages/cmake-rn/src/platforms/apple.ts @@ -4,7 +4,7 @@ import fs from "node:fs"; import { Option, oraPromise, chalk } from "@react-native-node-api/cli-utils"; import { - AppleTriplet as Target, + AppleTriplet as Triplet, createAppleFramework, createXCframework, determineXCFrameworkFilename, @@ -33,7 +33,7 @@ const XCODE_SDK_NAMES = { "arm64-apple-tvos-sim": "appletvsimulator", "arm64-apple-visionos": "xros", "arm64-apple-visionos-sim": "xrsimulator", -} satisfies Record; +} satisfies Record; type CMakeSystemName = "Darwin" | "iOS" | "tvOS" | "watchOS" | "visionOS"; @@ -48,7 +48,7 @@ const CMAKE_SYSTEM_NAMES = { "arm64-apple-tvos-sim": "tvOS", "arm64-apple-visionos": "visionOS", "arm64-apple-visionos-sim": "visionOS", -} satisfies Record; +} satisfies Record; type AppleArchitecture = "arm64" | "x86_64" | "arm64;x86_64"; @@ -63,7 +63,7 @@ export const APPLE_ARCHITECTURES = { "arm64-apple-tvos-sim": "arm64", "arm64-apple-visionos": "arm64", "arm64-apple-visionos-sim": "arm64", -} satisfies Record; +} satisfies Record; export function createPlistContent(values: Record) { return [ @@ -94,10 +94,10 @@ type AppleOpts = { xcframeworkExtension: boolean; }; -export const platform: Platform = { +export const platform: Platform = { id: "apple", name: "Apple", - targets: [ + triplets: [ "arm64;x86_64-apple-darwin", "arm64-apple-ios", "arm64-apple-ios-sim", @@ -106,22 +106,22 @@ export const platform: Platform = { "arm64-apple-visionos", "arm64-apple-visionos-sim", ], - defaultTargets() { + defaultTriplets() { return process.arch === "arm64" ? ["arm64-apple-ios-sim"] : []; }, amendCommand(command) { return command.addOption(xcframeworkExtensionOption); }, - configureArgs({ target }) { + configureArgs({ triplet }) { return [ "-G", "Xcode", "-D", - `CMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAMES[target]}`, + `CMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAMES[triplet]}`, "-D", - `CMAKE_OSX_SYSROOT=${XCODE_SDK_NAMES[target]}`, + `CMAKE_OSX_SYSROOT=${XCODE_SDK_NAMES[triplet]}`, "-D", - `CMAKE_OSX_ARCHITECTURES=${APPLE_ARCHITECTURES[target]}`, + `CMAKE_OSX_ARCHITECTURES=${APPLE_ARCHITECTURES[triplet]}`, ]; }, buildArgs() { @@ -132,11 +132,11 @@ export const platform: Platform = { return process.platform === "darwin"; }, async postBuild( - { outputPath, targets }, + { outputPath, triplets }, { configuration, autoLink, xcframeworkExtension }, ) { const libraryPaths = await Promise.all( - targets.map(async ({ outputPath }) => { + triplets.map(async ({ outputPath }) => { const configSpecificPath = path.join(outputPath, configuration); assert( fs.existsSync(configSpecificPath), diff --git a/packages/cmake-rn/src/platforms/types.ts b/packages/cmake-rn/src/platforms/types.ts index bd3e06a2..7f4a78da 100644 --- a/packages/cmake-rn/src/platforms/types.ts +++ b/packages/cmake-rn/src/platforms/types.ts @@ -13,16 +13,16 @@ type ExtendedCommand = cli.Command< Record // Global opts are not supported >; -export type BaseOpts = Omit, "target">; +export type BaseOpts = Omit, "triplet">; -export type TargetContext = { - target: Target; +export type TripletContext = { + triplet: Triplet; buildPath: string; outputPath: string; }; export type Platform< - Targets extends string[] = string[], + Triplets extends string[] = string[], Opts extends cli.OptionValues = Record, Command = ExtendedCommand, > = { @@ -35,13 +35,13 @@ export type Platform< */ name: string; /** - * All the targets supported by this platform. + * All the triplets supported by this platform. */ - targets: Readonly; + triplets: Readonly; /** - * Get the limited subset of targets that should be built by default for this platform, to support a development workflow. + * Get the limited subset of triplets that should be built by default for this platform, to support a development workflow. */ - defaultTargets(): Targets[number][] | Promise; + defaultTriplets(): Triplets[number][] | Promise; /** * Implement this to add any platform specific options to the command. */ @@ -51,21 +51,21 @@ export type Platform< */ isSupportedByHost(): boolean | Promise; /** - * Platform specific arguments passed to CMake to configure a target project. + * Platform specific arguments passed to CMake to configure a triplet project. */ configureArgs( - context: TargetContext, + context: TripletContext, options: BaseOpts & Opts, ): string[]; /** - * Platform specific arguments passed to CMake to build a target project. + * Platform specific arguments passed to CMake to build a triplet project. */ buildArgs( - context: TargetContext, + context: TripletContext, options: BaseOpts & Opts, ): string[]; /** - * Called to combine multiple targets into a single prebuilt artefact. + * Called to combine multiple triplets into a single prebuilt artefact. */ postBuild( context: { @@ -73,7 +73,7 @@ export type Platform< * Location of the final prebuilt artefact. */ outputPath: string; - targets: TargetContext[]; + triplets: TripletContext[]; }, options: BaseOpts & Opts, ): Promise; From 3839c3a5f431835019bb1fdf3b03848eab9a1278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Fri, 19 Sep 2025 21:54:20 +0200 Subject: [PATCH 2/2] Add changeset --- .changeset/rotten-melons-brush.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/rotten-melons-brush.md diff --git a/.changeset/rotten-melons-brush.md b/.changeset/rotten-melons-brush.md new file mode 100644 index 00000000..cb313de4 --- /dev/null +++ b/.changeset/rotten-melons-brush.md @@ -0,0 +1,5 @@ +--- +"cmake-rn": minor +--- + +Breaking: Renamed --target to --triplet to free up --target for passing CMake targets