Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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 .changeset/bright-parts-roll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"cmake-rn": patch
"react-native-node-api": patch
---

Add x86_64 and universal simulator triplets
4 changes: 2 additions & 2 deletions packages/cmake-rn/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ program = program.action(
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<string, unknown>)[platform.id]) {
for (const triplet of platform.triplets) {
for (const triplet of await platform.defaultTriplets("release")) {
triplets.add(triplet);
}
}
Expand All @@ -196,7 +196,7 @@ program = program.action(
if (triplets.size === 0) {
for (const platform of Object.values(platforms)) {
if (platform.isSupportedByHost()) {
for (const triplet of await platform.defaultTriplets()) {
for (const triplet of await platform.defaultTriplets("development")) {
triplets.add(triplet);
}
}
Expand Down
6 changes: 4 additions & 2 deletions packages/cmake-rn/src/platforms/android.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,10 @@ export const platform: Platform<Triplet[], AndroidOpts> = {
"i686-linux-android",
"x86_64-linux-android",
],
defaultTriplets() {
if (process.arch === "arm64") {
defaultTriplets(purpose) {
if (purpose === "release") {
return this.triplets;
} else if (process.arch === "arm64") {
return ["aarch64-linux-android"];
} else if (process.arch === "x64") {
return ["x86_64-linux-android"];
Expand Down
98 changes: 74 additions & 24 deletions packages/cmake-rn/src/platforms/apple.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,22 @@ const XCODE_SDK_NAMES = {
"x86_64-apple-darwin": "macosx",
"arm64-apple-darwin": "macosx",
"arm64;x86_64-apple-darwin": "macosx",

"arm64-apple-ios": "iphoneos",
"arm64-apple-ios-sim": "iphonesimulator",
"arm64-apple-tvos": "appletvos",
"x86_64-apple-ios-sim": "iphonesimulator",
"arm64;x86_64-apple-ios-sim": "iphonesimulator",

// "x86_64-apple-tvos": "appletvos",
"arm64-apple-tvos": "appletvos",
"x86_64-apple-tvos-sim": "appletvsimulator",
"arm64-apple-tvos-sim": "appletvsimulator",
"arm64;x86_64-apple-tvos-sim": "appletvsimulator",

"arm64-apple-visionos": "xros",
"arm64-apple-visionos-sim": "xrsimulator",
"x86_64-apple-visionos-sim": "xrsimulator",
"arm64;x86_64-apple-visionos-sim": "xrsimulator",
} satisfies Record<Triplet, XcodeSDKName>;

type CMakeSystemName = "Darwin" | "iOS" | "tvOS" | "watchOS" | "visionOS";
Expand All @@ -77,27 +86,44 @@ const CMAKE_SYSTEM_NAMES = {
"x86_64-apple-darwin": "Darwin",
"arm64-apple-darwin": "Darwin",
"arm64;x86_64-apple-darwin": "Darwin",

"arm64-apple-ios": "iOS",
"arm64-apple-ios-sim": "iOS",
"arm64-apple-tvos": "tvOS",
"x86_64-apple-ios-sim": "iOS",
"arm64;x86_64-apple-ios-sim": "iOS",

// "x86_64-apple-tvos": "appletvos",
"arm64-apple-tvos": "tvOS",
"arm64-apple-tvos-sim": "tvOS",
"x86_64-apple-tvos-sim": "tvOS",
"arm64;x86_64-apple-tvos-sim": "tvOS",

"arm64-apple-visionos": "visionOS",
"x86_64-apple-visionos-sim": "visionOS",
"arm64-apple-visionos-sim": "visionOS",
"arm64;x86_64-apple-visionos-sim": "visionOS",
} satisfies Record<Triplet, CMakeSystemName>;

const DESTINATION_BY_TRIPLET = {
"x86_64-apple-darwin": "generic/platform=macOS",
"arm64-apple-darwin": "generic/platform=macOS",
"arm64;x86_64-apple-darwin": "generic/platform=macOS",

"arm64-apple-ios": "generic/platform=iOS",
"arm64-apple-ios-sim": "generic/platform=iOS Simulator",
"x86_64-apple-ios-sim": "generic/platform=iOS Simulator",
"arm64;x86_64-apple-ios-sim": "generic/platform=iOS Simulator",

"arm64-apple-tvos": "generic/platform=tvOS",
// "x86_64-apple-tvos": "generic/platform=tvOS",
"x86_64-apple-tvos-sim": "generic/platform=tvOS Simulator",
"arm64-apple-tvos-sim": "generic/platform=tvOS Simulator",
"arm64;x86_64-apple-tvos-sim": "generic/platform=tvOS Simulator",

"arm64-apple-visionos": "generic/platform=visionOS",
"arm64-apple-visionos-sim": "generic/platform=visionOS Simulator",
// TODO: Verify that the three following destinations are correct and actually work
"x86_64-apple-darwin": "generic/platform=macOS,arch=x86_64",
"arm64-apple-darwin": "generic/platform=macOS,arch=arm64",
"arm64;x86_64-apple-darwin": "generic/platform=macOS",
"x86_64-apple-visionos-sim": "generic/platform=visionOS Simulator",
"arm64;x86_64-apple-visionos-sim": "generic/platform=visionOS Simulator",
} satisfies Record<Triplet, string>;

type AppleArchitecture = "arm64" | "x86_64" | "arm64;x86_64";
Expand All @@ -106,30 +132,24 @@ export const APPLE_ARCHITECTURES = {
"x86_64-apple-darwin": "x86_64",
"arm64-apple-darwin": "arm64",
"arm64;x86_64-apple-darwin": "arm64;x86_64",

"arm64-apple-ios": "arm64",
"arm64-apple-ios-sim": "arm64",
"arm64-apple-tvos": "arm64",
"x86_64-apple-ios-sim": "x86_64",
"arm64;x86_64-apple-ios-sim": "arm64;x86_64",

// "x86_64-apple-tvos": "x86_64",
"arm64-apple-tvos": "arm64",
"arm64-apple-tvos-sim": "arm64",
"x86_64-apple-tvos-sim": "x86_64",
"arm64;x86_64-apple-tvos-sim": "arm64;x86_64",

"arm64-apple-visionos": "arm64",
"x86_64-apple-visionos-sim": "x86_64",
"arm64-apple-visionos-sim": "arm64",
"arm64;x86_64-apple-visionos-sim": "arm64;x86_64",
} satisfies Record<Triplet, AppleArchitecture>;

export function createPlistContent(values: Record<string, string>) {
return [
'<?xml version="1.0" encoding="UTF-8"?>',
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
'<plist version="1.0">',
"<dict>",
...Object.entries(values).flatMap(([key, value]) => [
`<key>${key}</key>`,
`<string>${value}</string>`,
]),
"</dict>",
"</plist>",
].join("\n");
}

const xcframeworkExtensionOption = new Option(
"--xcframework-extension",
"Don't rename the xcframework to .apple.node",
Expand Down Expand Up @@ -171,16 +191,46 @@ export const platform: Platform<Triplet[], AppleOpts> = {
id: "apple",
name: "Apple",
triplets: [
"arm64-apple-darwin",
"x86_64-apple-darwin",
"arm64;x86_64-apple-darwin",

"arm64-apple-ios",
"arm64-apple-ios-sim",
"x86_64-apple-ios-sim",
"arm64;x86_64-apple-ios-sim",

"arm64-apple-tvos",
"x86_64-apple-tvos-sim",
"arm64-apple-tvos-sim",
"arm64;x86_64-apple-tvos-sim",

"arm64-apple-visionos",
"x86_64-apple-visionos-sim",
"arm64-apple-visionos-sim",
"arm64;x86_64-apple-visionos-sim",
],
defaultTriplets() {
return process.arch === "arm64" ? ["arm64-apple-ios-sim"] : [];
defaultTriplets(purpose) {
if (purpose === "release") {
return [
"arm64;x86_64-apple-darwin",

"arm64-apple-ios",
"arm64;x86_64-apple-ios-sim",

"arm64-apple-tvos",
"arm64;x86_64-apple-tvos-sim",

"arm64-apple-visionos",
"arm64;x86_64-apple-visionos-sim",
];
} else if (process.arch === "arm64") {
return ["arm64-apple-ios-sim"];
} else if (process.arch === "x64") {
return ["x86_64-apple-ios-sim"];
} else {
return [];
Copy link

Copilot AI Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] For development mode, consider returning universal simulator slices (arm64;x86_64) instead of architecture-specific ones when possible. This would provide better compatibility across different simulators without requiring architecture-specific builds, aligning with the PR's goal of prioritizing universal slices.

Suggested change
} else if (process.arch === "arm64") {
return ["arm64-apple-ios-sim"];
} else if (process.arch === "x64") {
return ["x86_64-apple-ios-sim"];
} else {
return [];
} else {
// For development, prefer universal simulator slice for best compatibility
return ["arm64;x86_64-apple-ios-sim"];

Copilot uses AI. Check for mistakes.
}
},
amendCommand(command) {
return command.addOption(xcframeworkExtensionOption);
Expand Down
14 changes: 9 additions & 5 deletions packages/cmake-rn/src/platforms/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export type Platform<
Triplets extends string[] = string[],
Opts extends cli.OptionValues = Record<string, unknown>,
Command = ExtendedCommand<Opts>,
Triplet extends string = Triplets[number],
> = {
/**
* Used to identify the platform in the CLI.
Expand All @@ -47,9 +48,12 @@ export type Platform<
*/
triplets: Readonly<Triplets>;
/**
* Get the limited subset of triplets 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.
*
*/
defaultTriplets(): Triplets[number][] | Promise<Triplets[number][]>;
defaultTriplets(
purpose: "development" | "release",
Copy link
Collaborator

@shirakaba shirakaba Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ bikeshedding - feel free to solve more important problems instead!

Xcode uses the terminology build configuration (which you can name "orange" | "banana" if you wish, but defaults to Debug and Release when creating new projects).

They confusingly use the term Development for codesigning for local deployment.

From an Apple point of view, I'd go with:

- purpose: "development" | "release",
+ configuration: "Debug" | "Release",

On the other hand, Android uses build variants:

- purpose: "development" | "release",
+ variant: "debug" | "release",

So uhhh I guess we can't win. 🤔

But either way, "debug" is probably more consistent than "development"?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This value isn't encoding the build configuration "Release" vs "Debug" that you're referring to. What I'm trying to capture here (which might be total overkill BTW) is that a library want to build only for some triplets when they're in the process of iterating their library, to match simulators of a specific architecture for example. To speed things up while iterating locally, the don't want to produce pre-builds for all possible triplets.

Copy link
Collaborator

@shirakaba shirakaba Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right. Then surely this should be changed to onlyBuildActiveArchitecture: boolean or something? As "active architecture" I believe is terminology commonly used across various IDEs and build systems.

Or buildAllArchitectures: boolean.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree - it's the same concept as the activeArchOnly option passable to the React Native CLI: src/commands/buildAndroid/index.ts#L58-L77 where it's actually probing ADB. We might be able to do the same or something similar to figure out what simulators and emulators are actively booted 🤔

That being said, I don't know if it's worth it though investing too much into this feature: We're running all of the builds of triplets in parallel so the increase in build-time doesn't scale linearly with the amount of triplets.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll leave it to you! Just driving by 😄

Copy link
Collaborator Author

@kraenhansen kraenhansen Oct 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot what do you think? What would be a good name for this parameter and supported values?

(don't know if tagging it here will work the same way it does in agent tasks 🙈)

): Readonly<Triplets> | Promise<Readonly<Triplets>>;
Copy link

Copilot AI Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return type should be Triplet[] | Promise<Triplet[]> instead of Readonly<Triplets> | Promise<Readonly<Triplets>>. The Readonly wrapper is unnecessary here since arrays are already passed by reference, and the caller doesn't need the full Triplets type constraint - they just need an array of triplet strings.

Suggested change
): Readonly<Triplets> | Promise<Readonly<Triplets>>;
): Triplet[] | Promise<Triplet[]>;

Copilot uses AI. Check for mistakes.
/**
* Implement this to add any platform specific options to the command.
*/
Expand All @@ -62,15 +66,15 @@ export type Platform<
* Configure all projects for this platform.
*/
configure(
triplets: TripletContext<Triplets[number]>[],
triplets: TripletContext<Triplet>[],
options: BaseOpts & Opts,
spawn: Spawn,
): Promise<void>;
/**
* Platform specific command to build a triplet project.
*/
build(
context: TripletContext<Triplets[number]>,
context: TripletContext<Triplet>,
options: BaseOpts & Opts,
): Promise<void>;
/**
Expand All @@ -81,7 +85,7 @@ export type Platform<
* Location of the final prebuilt artefact.
*/
outputPath: string,
triplets: TripletContext<Triplets[number]>[],
triplets: TripletContext<Triplet>[],
options: BaseOpts & Opts,
): Promise<void>;
};
16 changes: 0 additions & 16 deletions packages/host/src/node/prebuilds/apple.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,8 @@ import os from "node:os";
import plist from "@expo/plist";
import { spawn } from "@react-native-node-api/cli-utils";

import { AppleTriplet } from "./triplets.js";
import { determineLibraryBasename } from "../path-utils.js";

type AppleArchitecture = "arm64" | "x86_64" | "arm64;x86_64";

export const APPLE_ARCHITECTURES = {
"x86_64-apple-darwin": "x86_64",
"arm64-apple-darwin": "arm64",
"arm64;x86_64-apple-darwin": "arm64;x86_64",
"arm64-apple-ios": "arm64",
"arm64-apple-ios-sim": "arm64",
"arm64-apple-tvos": "arm64",
// "x86_64-apple-tvos": "x86_64",
"arm64-apple-tvos-sim": "arm64",
"arm64-apple-visionos": "arm64",
"arm64-apple-visionos-sim": "arm64",
} satisfies Record<AppleTriplet, AppleArchitecture>;

type XCframeworkOptions = {
frameworkPaths: string[];
outputPath: string;
Expand Down
13 changes: 11 additions & 2 deletions packages/host/src/node/prebuilds/triplets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,25 @@ export const ANDROID_TRIPLETS = [
export type AndroidTriplet = (typeof ANDROID_TRIPLETS)[number];

export const APPLE_TRIPLETS = [
"arm64;x86_64-apple-darwin",
"x86_64-apple-darwin",
"arm64-apple-darwin",
"arm64;x86_64-apple-darwin",

"arm64-apple-ios",
"x86_64-apple-ios-sim",
"arm64-apple-ios-sim",
"arm64;x86_64-apple-ios-sim",

"arm64-apple-tvos",
"arm64-apple-tvos-sim",
// "x86_64-apple-tvos",
"x86_64-apple-tvos-sim",
"arm64-apple-tvos-sim",
"arm64;x86_64-apple-tvos-sim",

"arm64-apple-visionos",
"x86_64-apple-visionos-sim",
"arm64-apple-visionos-sim",
"arm64;x86_64-apple-visionos-sim",
] as const;

export type AppleTriplet = (typeof APPLE_TRIPLETS)[number];
Expand Down
Loading