Skip to content

Commit 9180d70

Browse files
committed
Add --weak-node-api option to gyp-to-cmake
1 parent a9b3ccc commit 9180d70

File tree

3 files changed

+101
-48
lines changed

3 files changed

+101
-48
lines changed

.changeset/cold-symbols-refuse.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"gyp-to-cmake": minor
3+
---
4+
5+
Add --weak-node-api option to emit CMake configuration for use with cmake-rn's default way of Node-API linkage.

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

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -62,25 +62,38 @@ export const program = new Command("gyp-to-cmake")
6262
"--no-path-transforms",
6363
"Don't transform output from command expansions (replacing '\\' with '/')",
6464
)
65+
.option("--weak-node-api", "Link against the weak-node-api library", false)
66+
.option("--define-napi-version", "Define NAPI_VERSION for all targets", false)
67+
.option("--cpp <version>", "C++ standard version", "17")
6568
.argument(
6669
"[path]",
6770
"Path to the binding.gyp file or directory to traverse recursively",
6871
process.cwd(),
6972
)
7073
.action(
71-
wrapAction((targetPath: string, { pathTransforms }) => {
72-
const options: TransformOptions = {
73-
unsupportedBehaviour: "throw",
74-
disallowUnknownProperties: false,
75-
transformWinPathsToPosix: pathTransforms,
76-
};
77-
const stat = fs.statSync(targetPath);
78-
if (stat.isFile()) {
79-
transformBindingGypFile(targetPath, options);
80-
} else if (stat.isDirectory()) {
81-
transformBindingGypsRecursively(targetPath, options);
82-
} else {
83-
throw new Error(`Expected either a file or a directory: ${targetPath}`);
84-
}
85-
}),
74+
wrapAction(
75+
(
76+
targetPath: string,
77+
{ pathTransforms, cpp, defineNapiVersion, weakNodeApi },
78+
) => {
79+
const options: TransformOptions = {
80+
unsupportedBehaviour: "throw",
81+
disallowUnknownProperties: false,
82+
transformWinPathsToPosix: pathTransforms,
83+
compileFeatures: cpp ? [`cxx_std_${cpp}`] : [],
84+
defineNapiVersion,
85+
weakNodeApi,
86+
};
87+
const stat = fs.statSync(targetPath);
88+
if (stat.isFile()) {
89+
transformBindingGypFile(targetPath, options);
90+
} else if (stat.isDirectory()) {
91+
transformBindingGypsRecursively(targetPath, options);
92+
} else {
93+
throw new Error(
94+
`Expected either a file or a directory: ${targetPath}`,
95+
);
96+
}
97+
},
98+
),
8699
);

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

Lines changed: 68 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ export type GypToCmakeListsOptions = {
1212
executeCmdExpansions?: boolean;
1313
unsupportedBehaviour?: "skip" | "warn" | "throw";
1414
transformWinPathsToPosix?: boolean;
15+
compileFeatures?: string[];
16+
defineNapiVersion?: boolean;
17+
weakNodeApi?: boolean;
1518
};
1619

1720
function isCmdExpansion(value: string) {
@@ -34,6 +37,9 @@ export function bindingGypToCmakeLists({
3437
executeCmdExpansions = true,
3538
unsupportedBehaviour = "skip",
3639
transformWinPathsToPosix = true,
40+
defineNapiVersion = true,
41+
weakNodeApi = false,
42+
compileFeatures = [],
3743
}: GypToCmakeListsOptions): string {
3844
function mapExpansion(value: string): string[] {
3945
if (!isCmdExpansion(value)) {
@@ -60,65 +66,94 @@ export function bindingGypToCmakeLists({
6066
}
6167

6268
const lines: string[] = [
63-
"cmake_minimum_required(VERSION 3.15)",
69+
"cmake_minimum_required(VERSION 3.15...3.31)",
6470
//"cmake_policy(SET CMP0091 NEW)",
6571
//"cmake_policy(SET CMP0042 NEW)",
6672
`project(${projectName})`,
6773
"",
6874
// Declaring a project-wide NAPI_VERSION as a fallback for targets that don't explicitly set it
69-
`add_compile_definitions(NAPI_VERSION=${napiVersion})`,
75+
// This is only needed when using cmake-js, as this is injected by cmake-rn
76+
...(defineNapiVersion
77+
? [`add_compile_definitions(NAPI_VERSION=${napiVersion})`]
78+
: []),
7079
];
7180

81+
if (weakNodeApi) {
82+
lines.push(`include(\${WEAK_NODE_API_CONFIG})`, "");
83+
}
84+
7285
for (const target of gyp.targets) {
73-
const { target_name: targetName } = target;
86+
const { target_name: targetName, defines = [] } = target;
7487

7588
// TODO: Handle "conditions"
7689
// TODO: Handle "cflags"
7790
// TODO: Handle "ldflags"
7891

79-
const escapedJoinedSources = target.sources
92+
const escapedSources = target.sources
8093
.flatMap(mapExpansion)
8194
.map(transformPath)
82-
.map(escapeSpaces)
83-
.join(" ");
95+
.map(escapeSpaces);
8496

85-
const escapedJoinedIncludes = (target.include_dirs || [])
97+
const escapedIncludes = (target.include_dirs || [])
8698
.flatMap(mapExpansion)
8799
.map(transformPath)
88-
.map(escapeSpaces)
89-
.join(" ");
100+
.map(escapeSpaces);
90101

91-
const escapedJoinedDefines = (target.defines || [])
102+
const escapedDefines = defines
92103
.flatMap(mapExpansion)
93104
.map(transformPath)
94-
.map(escapeSpaces)
95-
.join(" ");
105+
.map(escapeSpaces);
106+
107+
const libraries = [];
108+
if (weakNodeApi) {
109+
libraries.push("weak-node-api");
110+
} else {
111+
libraries.push("${CMAKE_JS_LIB}");
112+
escapedSources.push("${CMAKE_JS_SRC}");
113+
escapedIncludes.push("${CMAKE_JS_INC}");
114+
}
115+
116+
lines.push(`add_library(${targetName} SHARED ${escapedSources.join(" ")})`);
117+
118+
if (libraries.length > 0) {
119+
lines.push(
120+
`target_link_libraries(${targetName} PRIVATE ${libraries.join(" ")})`,
121+
);
122+
}
123+
124+
if (escapedIncludes.length > 0) {
125+
lines.push(
126+
`target_include_directories(${targetName} PRIVATE ${escapedIncludes.join(
127+
" ",
128+
)})`,
129+
);
130+
}
131+
132+
if (escapedDefines.length > 0) {
133+
lines.push(
134+
`target_compile_definitions(${targetName} PRIVATE ${escapedDefines.join(" ")})`,
135+
);
136+
}
137+
138+
if (compileFeatures.length > 0) {
139+
lines.push(
140+
`target_compile_features(${targetName} PRIVATE ${compileFeatures.join(" ")})`,
141+
);
142+
}
96143

144+
// `set_target_properties(${targetName} PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED YES CXX_EXTENSIONS NO)`,
145+
}
146+
147+
if (!weakNodeApi) {
148+
// This is required by cmake-js to generate the import library for node.lib on Windows
97149
lines.push(
98150
"",
99-
`add_library(${targetName} SHARED ${escapedJoinedSources} \${CMAKE_JS_SRC})`,
100-
`set_target_properties(${targetName} PROPERTIES PREFIX "" SUFFIX ".node")`,
101-
`target_include_directories(${targetName} PRIVATE ${escapedJoinedIncludes} \${CMAKE_JS_INC})`,
102-
`target_link_libraries(${targetName} PRIVATE \${CMAKE_JS_LIB})`,
103-
`target_compile_features(${targetName} PRIVATE cxx_std_17)`,
104-
...(escapedJoinedDefines
105-
? [
106-
`target_compile_definitions(${targetName} PRIVATE ${escapedJoinedDefines})`,
107-
]
108-
: []),
109-
// or
110-
// `set_target_properties(${targetName} PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED YES CXX_EXTENSIONS NO)`,
151+
"if(MSVC AND CMAKE_JS_NODELIB_DEF AND CMAKE_JS_NODELIB_TARGET)",
152+
" # Generate node.lib",
153+
" execute_process(COMMAND ${CMAKE_AR} /def:${CMAKE_JS_NODELIB_DEF} /out:${CMAKE_JS_NODELIB_TARGET} ${CMAKE_STATIC_LINKER_FLAGS})",
154+
"endif()",
111155
);
112156
}
113157

114-
// Adding this post-amble from the template, although not used by react-native-node-api
115-
lines.push(
116-
"",
117-
"if(MSVC AND CMAKE_JS_NODELIB_DEF AND CMAKE_JS_NODELIB_TARGET)",
118-
" # Generate node.lib",
119-
" execute_process(COMMAND ${CMAKE_AR} /def:${CMAKE_JS_NODELIB_DEF} /out:${CMAKE_JS_NODELIB_TARGET} ${CMAKE_STATIC_LINKER_FLAGS})",
120-
"endif()",
121-
);
122-
123158
return lines.join("\n");
124159
}

0 commit comments

Comments
 (0)