Skip to content

Commit 6318d2b

Browse files
authored
feat: support rebuild and build for cross-compiling Node-API module to wasm on Windows (#2974)
1 parent ea99fea commit 6318d2b

File tree

9 files changed

+392
-17
lines changed

9 files changed

+392
-17
lines changed

.github/workflows/tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ jobs:
135135
FULL_TEST: ${{ (matrix.node == '20.x' && matrix.python == '3.12') && '1' || '0' }}
136136
- name: Run Tests (Windows)
137137
if: startsWith(matrix.os, 'windows')
138-
shell: pwsh
139-
run: npm run test --python="${env:pythonLocation}\\python.exe"
138+
shell: bash # Building wasm on Windows requires using make generator, it only works in bash
139+
run: npm run test --python="${pythonLocation}\\python.exe"
140140
env:
141141
FULL_TEST: ${{ (matrix.node == '20.x' && matrix.python == '3.12') && '1' || '0' }}

lib/build.js

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict'
22

3-
const fs = require('graceful-fs').promises
3+
const gracefulFs = require('graceful-fs')
4+
const fs = gracefulFs.promises
45
const path = require('path')
56
const { glob } = require('glob')
67
const log = require('./log')
@@ -85,59 +86,65 @@ async function build (gyp, argv) {
8586
async function findSolutionFile () {
8687
const files = await glob('build/*.sln')
8788
if (files.length === 0) {
88-
throw new Error('Could not find *.sln file. Did you run "configure"?')
89+
if (gracefulFs.existsSync('build/Makefile') || (await glob('build/*.mk')).length !== 0) {
90+
command = makeCommand
91+
await doWhich(false)
92+
return
93+
} else {
94+
throw new Error('Could not find *.sln file or Makefile. Did you run "configure"?')
95+
}
8996
}
9097
guessedSolution = files[0]
9198
log.verbose('found first Solution file', guessedSolution)
92-
await doWhich()
99+
await doWhich(true)
93100
}
94101

95102
/**
96103
* Uses node-which to locate the msbuild / make executable.
97104
*/
98105

99-
async function doWhich () {
106+
async function doWhich (msvs) {
100107
// On Windows use msbuild provided by node-gyp configure
101-
if (win) {
108+
if (msvs) {
102109
if (!config.variables.msbuild_path) {
103110
throw new Error('MSBuild is not set, please run `node-gyp configure`.')
104111
}
105112
command = config.variables.msbuild_path
106113
log.verbose('using MSBuild:', command)
107-
await doBuild()
114+
await doBuild(msvs)
108115
return
109116
}
110117

111118
// First make sure we have the build command in the PATH
112119
const execPath = await which(command)
113120
log.verbose('`which` succeeded for `' + command + '`', execPath)
114-
await doBuild()
121+
await doBuild(msvs)
115122
}
116123

117124
/**
118125
* Actually spawn the process and compile the module.
119126
*/
120127

121-
async function doBuild () {
128+
async function doBuild (msvs) {
122129
// Enable Verbose build
123130
const verbose = log.logger.isVisible('verbose')
124131
let j
125132

126-
if (!win && verbose) {
133+
if (!msvs && verbose) {
127134
argv.push('V=1')
128135
}
129136

130-
if (win && !verbose) {
137+
if (msvs && !verbose) {
131138
argv.push('/clp:Verbosity=minimal')
132139
}
133140

134-
if (win) {
141+
if (msvs) {
135142
// Turn off the Microsoft logo on Windows
136143
argv.push('/nologo')
137144
}
138145

139146
// Specify the build type, Release by default
140-
if (win) {
147+
if (msvs) {
141148
// Convert .gypi config target_arch to MSBuild /Platform
142149
// Since there are many ways to state '32-bit Intel', default to it.
143150
// N.B. msbuild's Condition string equality tests are case-insensitive.
@@ -173,7 +180,7 @@ async function build (gyp, argv) {
173180
}
174181
}
175182

176-
if (win) {
183+
if (msvs) {
177184
// did the user specify their own .sln file?
178185
const hasSln = argv.some(function (arg) {
179186
return path.extname(arg) === '.sln'

lib/configure.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,28 @@ async function configure (gyp, argv) {
9292
log.verbose(
9393
'build dir', '"build" dir needed to be created?', isNew ? 'Yes' : 'No'
9494
)
95-
const vsInfo = win ? await findVisualStudio(release.semver, gyp.opts['msvs-version']) : null
96-
return createConfigFile(vsInfo)
95+
if (win) {
96+
let usingMakeGenerator = false
97+
for (let i = argv.length - 1; i >= 0; --i) {
98+
const arg = argv[i]
99+
if (arg === '-f' || arg === '--format') {
100+
const format = argv[i + 1]
101+
if (typeof format === 'string' && format.startsWith('make')) {
102+
usingMakeGenerator = true
103+
break
104+
}
105+
} else if (arg.startsWith('--format=make')) {
106+
usingMakeGenerator = true
107+
break
108+
}
109+
}
110+
let vsInfo = {}
111+
if (!usingMakeGenerator) {
112+
vsInfo = await findVisualStudio(release.semver, gyp.opts['msvs-version'])
113+
}
114+
return createConfigFile(vsInfo)
115+
}
116+
return createConfigFile(null)
97117
}
98118

99119
async function createConfigFile (vsInfo) {

test/node_modules/hello_napi/binding.gyp

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

test/node_modules/hello_napi/common.gypi

Lines changed: 110 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/node_modules/hello_napi/hello.c

Lines changed: 54 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/node_modules/hello_napi/hello.js

Lines changed: 57 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/node_modules/hello_napi/package.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)