-
Notifications
You must be signed in to change notification settings - Fork 29.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
build: build addon tests in parallel #21155
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
'use strict'; | ||
|
||
// Usage: e.g. node build-addons.js <path to node-gyp> <directory> | ||
|
||
const child_process = require('child_process'); | ||
const path = require('path'); | ||
const fs = require('fs').promises; | ||
const util = require('util'); | ||
|
||
const execFile = util.promisify(child_process.execFile); | ||
|
||
const parallelization = +process.env.JOBS || require('os').cpus().length; | ||
const nodeGyp = process.argv[2]; | ||
|
||
async function runner(directoryQueue) { | ||
if (directoryQueue.length === 0) | ||
return; | ||
|
||
const dir = directoryQueue.shift(); | ||
const next = () => runner(directoryQueue); | ||
|
||
try { | ||
// Only run for directories that have a `binding.gyp`. | ||
// (https://github.com/nodejs/node/issues/14843) | ||
await fs.stat(path.join(dir, 'binding.gyp')); | ||
} catch (err) { | ||
if (err.code === 'ENOENT' || err.code === 'ENOTDIR') | ||
return next(); | ||
throw err; | ||
} | ||
|
||
console.log(`Building addon in ${dir}`); | ||
const { stdout, stderr } = | ||
await execFile(process.execPath, [nodeGyp, 'rebuild', `--directory=${dir}`], | ||
{ | ||
stdio: 'inherit', | ||
env: { ...process.env, MAKEFLAGS: '-j1' } | ||
}); | ||
|
||
process.stdout.write(stdout); | ||
process.stderr.write(stderr); | ||
|
||
return next(); | ||
} | ||
|
||
async function main(directory) { | ||
const directoryQueue = (await fs.readdir(directory)) | ||
.map((subdir) => path.join(directory, subdir)); | ||
|
||
const runners = []; | ||
for (let i = 0; i < parallelization; ++i) | ||
runners.push(runner(directoryQueue)); | ||
return Promise.all(runners); | ||
} | ||
|
||
main(process.argv[3]).catch((err) => setImmediate(() => { throw err; })); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the setImmediate() to get around a UnhandledPromiseRejectionWarning? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @bnoordhuis Yup, it’s so the process really crashes in that case There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes you wonder if we should export |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this for
execFile
? We will write the output to this process later anyway?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@joyeecheung This is so we don’t get interleaved output from multiple builds running in parallel … will add a comment :)