Skip to content

Commit b3f853f

Browse files
committed
Add node.js platform
1 parent d935b58 commit b3f853f

File tree

2 files changed

+129
-2
lines changed

2 files changed

+129
-2
lines changed

packages/cmake-rn/src/platforms.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@ import assert from "node:assert/strict";
22

33
import { platform as android } from "./platforms/android.js";
44
import { platform as apple } from "./platforms/apple.js";
5+
import { platform as node } from "./platforms/node.js";
56
import { Platform } from "./platforms/types.js";
67

7-
export const platforms: Platform[] = [android, apple] as const;
8-
export const allTargets = [...android.targets, ...apple.targets] as const;
8+
export const platforms: Platform[] = [android, apple, node] as const;
9+
export const allTargets = [
10+
...android.targets,
11+
...apple.targets,
12+
...node.targets,
13+
] as const;
914

1015
export function platformHasTarget<P extends Platform>(
1116
platform: P,
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import assert from "node:assert/strict";
2+
import fs from "node:fs";
3+
import path from "node:path";
4+
import { oraPromise } from "ora";
5+
import chalk from "chalk";
6+
7+
import {
8+
createNodeLibsDirectory,
9+
determineNodeLibsFilename,
10+
NodeTriplet as Target,
11+
} from "react-native-node-api";
12+
13+
import type { Platform } from "./types.js";
14+
import { toDeclarationArguments } from "../cmake.js";
15+
import { getNodeApiIncludeDirectories } from "../headers.js";
16+
17+
type NodeOpts = Record<string, unknown>;
18+
19+
function getLinkerFlags(target: Target): string {
20+
if (
21+
target === "arm64-apple-darwin" ||
22+
target === "x86_64-apple-darwin" ||
23+
target === "arm64;x86_64-apple-darwin"
24+
) {
25+
return "-undefined dynamic_lookup";
26+
} else if (
27+
target === "linux" // TODO: Use the right triplet for Linux
28+
) {
29+
return "-Wl,--unresolved-symbols=ignore-in-object-files";
30+
} else {
31+
throw new Error(
32+
`Determining linker flags for target ${target as string} is not implemented`,
33+
);
34+
}
35+
}
36+
37+
export const platform: Platform<Target[], NodeOpts> = {
38+
id: "nodejs",
39+
name: "Node.js",
40+
targets: [
41+
"arm64-apple-darwin",
42+
"x86_64-apple-darwin",
43+
"arm64;x86_64-apple-darwin",
44+
],
45+
defaultTargets() {
46+
if (process.platform === "darwin") {
47+
if (process.arch === "arm64") {
48+
return ["arm64-apple-darwin"];
49+
} else if (process.arch === "x64") {
50+
return ["x86_64-apple-darwin"];
51+
}
52+
}
53+
return [];
54+
},
55+
amendCommand(command) {
56+
return command;
57+
},
58+
configureArgs({ target }) {
59+
return [
60+
"-G",
61+
"Ninja",
62+
...toDeclarationArguments({
63+
// TODO: Make this names less "cmake-js" specific with an option to use the CMAKE_JS prefix
64+
CMAKE_JS_INC: getNodeApiIncludeDirectories(),
65+
CMAKE_SHARED_LINKER_FLAGS: getLinkerFlags(target),
66+
}),
67+
];
68+
},
69+
buildArgs() {
70+
return [];
71+
},
72+
isSupportedByHost() {
73+
const { ANDROID_HOME } = process.env;
74+
return typeof ANDROID_HOME === "string" && fs.existsSync(ANDROID_HOME);
75+
},
76+
async postBuild({ outputPath, targets }, { autoLink }) {
77+
// TODO: Include `configuration` in the output path
78+
const libraryPathByTriplet = Object.fromEntries(
79+
await Promise.all(
80+
targets.map(async ({ target, outputPath }) => {
81+
assert(
82+
fs.existsSync(outputPath),
83+
`Expected a directory at ${outputPath}`,
84+
);
85+
// Expect binary file(s), either .node or .so
86+
const dirents = await fs.promises.readdir(outputPath, {
87+
withFileTypes: true,
88+
});
89+
const result = dirents
90+
.filter(
91+
(dirent) =>
92+
dirent.isFile() &&
93+
(dirent.name.endsWith(".so") || dirent.name.endsWith(".node")),
94+
)
95+
.map((dirent) => path.join(dirent.parentPath, dirent.name));
96+
assert.equal(result.length, 1, "Expected exactly one library file");
97+
return [target, result[0]] as const;
98+
}),
99+
),
100+
) as Record<Target, string>;
101+
const nodeLibsFilename = determineNodeLibsFilename(
102+
Object.values(libraryPathByTriplet),
103+
);
104+
const nodeLibsOutputPath = path.resolve(outputPath, nodeLibsFilename);
105+
106+
await oraPromise(
107+
createNodeLibsDirectory({
108+
outputPath: nodeLibsOutputPath,
109+
libraryPathByTriplet,
110+
autoLink,
111+
}),
112+
{
113+
text: "Assembling Node.js libs directory",
114+
successText: `Node.js libs directory assembled into ${chalk.dim(
115+
path.relative(process.cwd(), nodeLibsOutputPath),
116+
)}`,
117+
failText: ({ message }) =>
118+
`Failed to assemble Node.js libs directory: ${message}`,
119+
},
120+
);
121+
},
122+
};

0 commit comments

Comments
 (0)