Skip to content

Commit 7a97be9

Browse files
authored
Expansion support in gyp-to-cmake (#9)
* Add expansion support to gyp-to-cmake * Add more examples
1 parent 93e288b commit 7a97be9

File tree

7 files changed

+46
-29
lines changed

7 files changed

+46
-29
lines changed

package-lock.json

Lines changed: 8 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/gyp-to-cmake/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
},
1515
"dependencies": {
1616
"@commander-js/extra-typings": "^13.1.0",
17-
"commander": "^13.1.0"
17+
"commander": "^13.1.0",
18+
"gyp-parser": "^1.0.4"
1819
}
1920
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
declare module "gyp-parser" {
2+
export function parse(input: string): unknown;
3+
}

packages/gyp-to-cmake/src/gyp.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import assert from "node:assert/strict";
22
import fs from "node:fs";
33

4+
import { parse } from "gyp-parser";
5+
46
export type GypTarget = {
57
target_name: string;
68
sources: string[];
@@ -73,8 +75,7 @@ export function readBindingFile(
7375
): GypBinding {
7476
try {
7577
const contents = fs.readFileSync(path, "utf-8");
76-
// TODO: Use a loose json parser to allow single quotes (and comments)
77-
const json = JSON.parse(contents);
78+
const json = parse(contents);
7879
assertBinding(json, disallowUnknownProperties);
7980
return json;
8081
} catch (err) {

packages/gyp-to-cmake/src/transformer.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import cp from "node:child_process";
2+
13
import type { GypBinding } from "./gyp.js";
24

35
const DEFAULT_NAPI_VERSION = 8;
@@ -6,6 +8,7 @@ export type GypToCmakeListsOptions = {
68
gyp: GypBinding;
79
projectName: string;
810
napiVersion?: number;
11+
executeCmdExpansions?: boolean;
912
unsupportedBehaviour?: "skip" | "warn" | "throw";
1013
};
1114

@@ -26,17 +29,23 @@ export function bindingGypToCmakeLists({
2629
gyp,
2730
projectName,
2831
napiVersion = DEFAULT_NAPI_VERSION,
32+
executeCmdExpansions = true,
2933
unsupportedBehaviour = "skip",
3034
}: GypToCmakeListsOptions): string {
31-
function filterExpansion(value: string) {
35+
function mapExpansion(value: string): string[] {
3236
if (!isCmdExpansion(value)) {
33-
return true;
37+
return [value];
38+
} else if (executeCmdExpansions) {
39+
const cmd = value.trim().replace(/^<!@?/, "");
40+
const output = cp.execSync(cmd, { encoding: "utf-8" }).trim();
41+
// Split on whitespace, if the expansion starts with "<!@"
42+
return value.trim().startsWith("<!@") ? output.split(/\s/) : [output];
3443
} else if (unsupportedBehaviour === "throw") {
3544
throw new Error(`Unsupported command expansion: ${value}`);
3645
} else if (unsupportedBehaviour === "warn") {
3746
console.warn(`Unsupported command expansion: ${value}`);
3847
}
39-
return false;
48+
return [value];
4049
}
4150

4251
const lines: string[] = [
@@ -57,12 +66,12 @@ export function bindingGypToCmakeLists({
5766
// TODO: Handle "ldflags"
5867

5968
const escapedJoinedSources = target.sources
60-
.filter(filterExpansion)
69+
.flatMap(mapExpansion)
6170
.map(escapePath)
6271
.join(" ");
6372

6473
const escapedJoinedIncludes = (target.include_dirs || [])
65-
.filter(filterExpansion)
74+
.flatMap(mapExpansion)
6675
.map(escapePath)
6776
.join(" ");
6877

@@ -71,9 +80,8 @@ export function bindingGypToCmakeLists({
7180
`add_library(${targetName} SHARED ${escapedJoinedSources} \${CMAKE_JS_SRC})`,
7281
`set_target_properties(${targetName} PROPERTIES PREFIX "" SUFFIX ".node")`,
7382
`target_include_directories(${targetName} PRIVATE ${escapedJoinedIncludes} \${CMAKE_JS_INC})`,
74-
`target_link_libraries(${targetName} PRIVATE \${CMAKE_JS_LIB})`
75-
// TODO: Consider declaring the C++ standard version
76-
// `target_compile_features(${targetName} PRIVATE cxx_std_17)`
83+
`target_link_libraries(${targetName} PRIVATE \${CMAKE_JS_LIB})`,
84+
`target_compile_features(${targetName} PRIVATE cxx_std_17)`
7785
// or
7886
// `set_target_properties(${targetName} PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED YES CXX_EXTENSIONS NO)`,
7987
);

packages/node-addon-examples/index.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
module.exports = {
22
"1-getting-started": {
3-
"1_hello_world": () => require("./examples/1-getting-started/1_hello_world/napi/hello.js"),
4-
"2_function_arguments": () => require("./examples/1-getting-started/2_function_arguments/napi/addon.js"),
5-
"3_callbacks": () => require("./examples/1-getting-started/3_callbacks/napi/addon.js"),
6-
"4_object_factory": () => require("./examples/1-getting-started/4_object_factory/napi/addon.js"),
3+
"1_hello_world/napi": () => require("./examples/1-getting-started/1_hello_world/napi/hello.js"),
4+
"1_hello_world/node-addon-api": () => require("./examples/1-getting-started/1_hello_world/node-addon-api/hello.js"),
5+
"1_hello_world/node-addon-api-addon-class": () => require("./examples/1-getting-started/1_hello_world/node-addon-api-addon-class/hello.js"),
6+
"2_function_arguments/napi": () => require("./examples/1-getting-started/2_function_arguments/napi/addon.js"),
7+
"2_function_arguments/node-addon-api": () => require("./examples/1-getting-started/2_function_arguments/node-addon-api/addon.js"),
8+
"3_callbacks/napi": () => require("./examples/1-getting-started/3_callbacks/napi/addon.js"),
9+
"3_callbacks/node-addon-api": () => require("./examples/1-getting-started/3_callbacks/node-addon-api/addon.js"),
10+
"4_object_factory/napi": () => require("./examples/1-getting-started/4_object_factory/napi/addon.js"),
11+
"4_object_factory/node-addon-api": () => require("./examples/1-getting-started/4_object_factory/node-addon-api/addon.js"),
712
"5_function_factory": () => require("./examples/1-getting-started/5_function_factory/napi/addon.js"),
813
},
914
"5-async-work": {

packages/node-addon-examples/scripts/copy-examples.mts

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ import { EXAMPLES_DIR } from "./cmake-projects.mjs";
66

77
const ALLOW_LIST = [
88
"1-getting-started/1_hello_world/napi/",
9-
// "1-getting-started/1_hello_world/node-addon-api/"
10-
// "1-getting-started/1_hello_world/node-addon-api-addon-class/"
9+
"1-getting-started/1_hello_world/node-addon-api/",
10+
"1-getting-started/1_hello_world/node-addon-api-addon-class/",
1111
"1-getting-started/2_function_arguments/napi/",
12-
// "1-getting-started/2_function_arguments/node-addon-api/",
12+
"1-getting-started/2_function_arguments/node-addon-api/",
1313
"1-getting-started/3_callbacks/napi/",
14-
// "1-getting-started/3_callbacks/node-addon-api/",
14+
"1-getting-started/3_callbacks/node-addon-api/",
1515
"1-getting-started/4_object_factory/napi/",
16-
// "1-getting-started/4_object_factory/node-addon-api/",
16+
"1-getting-started/4_object_factory/node-addon-api/",
1717
"1-getting-started/5_function_factory/napi/",
1818
// "1-getting-started/5_function_factory/node-addon-api/",
1919
// "1-getting-started/6_object_wrap/napi/", // TODO: Fix C++ support to allow lambda functions
@@ -66,12 +66,4 @@ for (const src of ALLOW_LIST) {
6666
const destPath = path.join(EXAMPLES_DIR, src);
6767
console.log("Copying from", srcPath, "to", destPath);
6868
fs.cpSync(srcPath, destPath, { recursive: true });
69-
// Patch binding.gyp files
70-
// TODO: Make the gyp-to-cmake tool handle single quotes in binding.gyp files
71-
const bindingGypPath = path.join(destPath, "binding.gyp");
72-
if (fs.existsSync(bindingGypPath)) {
73-
const contents = fs.readFileSync(bindingGypPath, "utf-8");
74-
const patchedContents = contents.replaceAll("'", '"');
75-
fs.writeFileSync(bindingGypPath, patchedContents, "utf-8");
76-
}
7769
}

0 commit comments

Comments
 (0)