Skip to content

Commit 9411a8c

Browse files
authored
Ferric x86 iOS simulator (#292)
* Make the build command default * Refactor creation of universal apple libraries and add support for ios libraries too * Assert weak node api framework before passing it to Rust * Assert paths passed when creating a universal library * Add the x86_64-apple-ios target * Add changesets
1 parent 07ea9dc commit 9411a8c

File tree

7 files changed

+64
-20
lines changed

7 files changed

+64
-20
lines changed

.changeset/better-pets-help.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"ferric-cli": patch
3+
---
4+
5+
Add x86_64 ios simulator target and output universal libraries for iOS simulators.

.changeset/large-hornets-burn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"ferric-cli": patch
3+
---
4+
5+
It's no longer required to pass "build" to ferric, as this is default now

packages/ferric/src/build.ts

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -311,34 +311,54 @@ export const buildCommand = new Command("build")
311311
),
312312
);
313313

314+
async function createUniversalAppleLibraries(libraryPathGroups: string[][]) {
315+
const result = await oraPromise(
316+
Promise.all(
317+
libraryPathGroups.map(async (libraryPaths) => {
318+
if (libraryPaths.length === 0) {
319+
return [];
320+
} else if (libraryPaths.length === 1) {
321+
return libraryPaths;
322+
} else {
323+
return [await createUniversalAppleLibrary(libraryPaths)];
324+
}
325+
}),
326+
),
327+
{
328+
text: "Combining arch-specific libraries into universal libraries",
329+
successText: "Combined arch-specific libraries into universal libraries",
330+
failText: (error) =>
331+
`Failed to combine arch-specific libraries: ${error.message}`,
332+
},
333+
);
334+
return result.flat();
335+
}
336+
314337
async function combineLibraries(
315338
libraries: Readonly<[AppleTargetName, string]>[],
316339
): Promise<string[]> {
317340
const result = [];
318341
const darwinLibraries = [];
342+
const iosSimulatorLibraries = [];
319343
for (const [target, libraryPath] of libraries) {
320344
if (target.endsWith("-darwin")) {
321345
darwinLibraries.push(libraryPath);
346+
} else if (
347+
target === "aarch64-apple-ios-sim" ||
348+
target === "x86_64-apple-ios" // Simulator despite name missing -sim suffix
349+
) {
350+
iosSimulatorLibraries.push(libraryPath);
322351
} else {
323352
result.push(libraryPath);
324353
}
325354
}
326-
if (darwinLibraries.length === 0) {
327-
return result;
328-
} else if (darwinLibraries.length === 1) {
329-
return [...result, darwinLibraries[0]];
330-
} else {
331-
const universalPath = await oraPromise(
332-
createUniversalAppleLibrary(darwinLibraries),
333-
{
334-
text: "Combining Darwin libraries into a universal library",
335-
successText: "Combined Darwin libraries into a universal library",
336-
failText: (error) =>
337-
`Failed to combine Darwin libraries: ${error.message}`,
338-
},
339-
);
340-
return [...result, universalPath];
341-
}
355+
356+
const combinedLibraryPaths = await createUniversalAppleLibraries([
357+
darwinLibraries,
358+
iosSimulatorLibraries,
359+
]);
360+
361+
return [...result, ...combinedLibraryPaths];
342362
}
343363

344364
export function isAndroidSupported() {

packages/ferric/src/cargo.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ import {
2121
const APPLE_XCFRAMEWORK_CHILDS_PER_TARGET: Record<AppleTargetName, string> = {
2222
"aarch64-apple-darwin": "macos-arm64_x86_64", // Universal
2323
"x86_64-apple-darwin": "macos-arm64_x86_64", // Universal
24+
2425
"aarch64-apple-ios": "ios-arm64",
2526
"aarch64-apple-ios-sim": "ios-arm64_x86_64-simulator", // Universal
27+
"x86_64-apple-ios": "ios-arm64_x86_64-simulator", // Universal
28+
2629
// "aarch64-apple-ios-macabi": "", // Catalyst
27-
// "x86_64-apple-ios": "ios-x86_64",
2830
// "x86_64-apple-ios-macabi": "ios-x86_64-simulator",
2931
// "aarch64-apple-tvos": "tvos-arm64",
3032
// "aarch64-apple-tvos-sim": "tvos-arm64-simulator",
@@ -216,6 +218,10 @@ export function getTargetEnvironmentVariables({
216218
};
217219
} else if (isAppleTarget(target)) {
218220
const weakNodeApiFrameworkPath = getWeakNodeApiFrameworkPath(target);
221+
assert(
222+
fs.existsSync(weakNodeApiFrameworkPath),
223+
`Expected weak-node-api framework at ${weakNodeApiFrameworkPath}`,
224+
);
219225
return {
220226
CARGO_ENCODED_RUSTFLAGS: [
221227
"-L",

packages/ferric/src/program.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ import { buildCommand } from "./build.js";
66
export const program = new Command("ferric")
77
.hook("preAction", () => printBanner())
88
.description("Rust Node-API Modules for React Native")
9-
.addCommand(buildCommand);
9+
.addCommand(buildCommand, { isDefault: true });

packages/ferric/src/targets.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ export type AndroidTargetName = (typeof ANDROID_TARGETS)[number];
1616
export const APPLE_TARGETS = [
1717
"aarch64-apple-darwin",
1818
"x86_64-apple-darwin",
19+
1920
"aarch64-apple-ios",
2021
"aarch64-apple-ios-sim",
22+
"x86_64-apple-ios", // Simulator (despite the missing -sim suffix)
23+
2124
// "aarch64-apple-ios-macabi", // Catalyst
22-
// "x86_64-apple-ios",
2325
// "x86_64-apple-ios-macabi", // Catalyst
2426

2527
// TODO: Re-enabled these when we know how to install them 🙈

packages/host/src/node/prebuilds/apple.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,17 @@ export function determineXCFrameworkFilename(
131131
}
132132

133133
export async function createUniversalAppleLibrary(libraryPaths: string[]) {
134+
assert(
135+
libraryPaths.length > 0,
136+
"Expected at least one library to create a universal library",
137+
);
134138
// Determine the output path
135139
const filenames = new Set(libraryPaths.map((p) => path.basename(p)));
136140
assert(
137141
filenames.size === 1,
138-
"Expected all darwin libraries to have the same name",
142+
`Expected libraries to have the same name, but got: ${[...filenames].join(
143+
", ",
144+
)}`,
139145
);
140146
const [filename] = filenames;
141147
const lipoParentPath = fs.realpathSync(

0 commit comments

Comments
 (0)