Skip to content

Commit

Permalink
feat: support gyp with ninja
Browse files Browse the repository at this point in the history
  • Loading branch information
codebytere committed Jul 24, 2020
1 parent aaf33c3 commit d842d73
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 41 deletions.
8 changes: 8 additions & 0 deletions addon.gypi
Expand Up @@ -169,6 +169,14 @@
# clients of class 'node::ObjectWrap'
4251
],
'configurations': {
'Debug_x64': {
'inherit_from': ['Debug'],
},
'Release_x64': {
'inherit_from': ['Release'],
}
}
}, {
# OS!="win"
'defines': [
Expand Down
24 changes: 18 additions & 6 deletions lib/build.js
Expand Up @@ -8,7 +8,7 @@ const which = require('which')
const win = process.platform === 'win32'

function build (gyp, argv, callback) {
var platformMake = 'make'
let platformMake = 'make'
if (process.platform === 'aix') {
platformMake = 'gmake'
} else if (process.platform.indexOf('bsd') !== -1) {
Expand All @@ -19,15 +19,20 @@ function build (gyp, argv, callback) {
})
}

var makeCommand = gyp.opts.make || process.env.MAKE || platformMake
var command = win ? 'msbuild' : makeCommand
var jobs = gyp.opts.jobs || process.env.JOBS
var buildType
var config
var arch
var nodeDir
var guessedSolution

const makeCommand = gyp.opts.make || process.env.MAKE || platformMake
let command = win ? 'msbuild' : makeCommand
if (gyp.opts.ninja) {
const ninjaPath = gyp.opts['ninja-path'] || path.resolve(gyp.devDir, 'ninja')
command = path.resolve(ninjaPath, 'ninja')
}

loadConfigGypi()

/**
Expand Down Expand Up @@ -127,8 +132,12 @@ function build (gyp, argv, callback) {
var verbose = log.levels[log.level] <= log.levels.verbose
var j

if (!win && verbose) {
argv.push('V=1')
if (verbose) {
if (gyp.opts.ninja) {
argv.push('-v')
} else if (!win) {
argv.push('V=1')
}
}

if (win && !verbose) {
Expand All @@ -141,7 +150,10 @@ function build (gyp, argv, callback) {
}

// Specify the build type, Release by default
if (win) {
if (gyp.opts.ninja) {
argv.push('-C')
argv.push(path.join('build', buildType))
} else if (win) {
// Convert .gypi config target_arch to MSBuild /Platform
// Since there are many ways to state '32-bit Intel', default to it.
// N.B. msbuild's Condition string equality tests are case-insensitive.
Expand Down
4 changes: 3 additions & 1 deletion lib/configure.js
Expand Up @@ -225,7 +225,9 @@ function configure (gyp, argv, callback) {
return callback(err)
}

if (!~argv.indexOf('-f') && !~argv.indexOf('--format')) {
if (!gyp.opts.ninja) {
argv.push('-f', 'ninja')
} else if (!~argv.indexOf('-f') && !~argv.indexOf('--format')) {
if (win) {
log.verbose('gyp', 'gyp format was not specified; forcing "msvs"')
// force the 'make' target for non-Windows
Expand Down
144 changes: 111 additions & 33 deletions lib/install.js
Expand Up @@ -11,10 +11,14 @@ const request = require('request')
const processRelease = require('./process-release')
const win = process.platform === 'win32'
const getProxyFromURI = require('./proxy')
const { spawn } = require('child_process')

function install (fs, gyp, argv, callback) {
var release = processRelease(argv, gyp, process.version, process.release)

const ninjaPath = gyp.opts['ninja-path'] || path.resolve(gyp.devDir, 'ninja')
const ninjaUrl = 'https://github.com/ninja-build/ninja/archive/v1.10.0.tar.gz'

// ensure no double-callbacks happen
function cb (err) {
if (cb.done) {
Expand Down Expand Up @@ -62,42 +66,62 @@ function install (fs, gyp, argv, callback) {
// the directory where the dev files will be installed
var devDir = path.resolve(gyp.devDir, release.versionDir)

// If '--ensure' was passed, then don't *always* install the version;
// check if it is already installed, and only install when needed
if (gyp.opts.ensure) {
log.verbose('install', '--ensure was passed, so won\'t reinstall if already installed')
fs.stat(devDir, function (err) {
if (err) {
if (err.code === 'ENOENT') {
log.verbose('install', 'version not already installed, continuing with install', release.version)
go()
} else if (err.code === 'EACCES') {
eaccesFallback(err)
} else {
cb(err)
}
return
}
log.verbose('install', 'version is already installed, need to check "installVersion"')
var installVersionFile = path.resolve(devDir, 'installVersion')
fs.readFile(installVersionFile, 'ascii', function (err, ver) {
if (err && err.code !== 'ENOENT') {
return cb(err)
}
var installVersion = parseInt(ver, 10) || 0
log.verbose('got "installVersion"', installVersion)
log.verbose('needs "installVersion"', gyp.package.installVersion)
if (installVersion < gyp.package.installVersion) {
log.verbose('install', 'version is no good; reinstalling')
go()
} else {
log.verbose('install', 'version is good')
cb()
function handleInstall (err) {
if (err) cb(err)

// If '--ensure' was passed, then don't *always* install the version;
// check if it is already installed, and only install when needed
if (gyp.opts.ensure) {
log.verbose('install', '--ensure was passed, so won\'t reinstall if already installed')
fs.stat(devDir, function (err) {
if (err) {
if (err.code === 'ENOENT') {
log.verbose('install', 'version not already installed, continuing with install', release.version)
go()
} else if (err.code === 'EACCES') {
eaccesFallback(err)
} else {
cb(err)
}
return
}
log.verbose('install', 'version is already installed, need to check "installVersion"')
var installVersionFile = path.resolve(devDir, 'installVersion')
fs.readFile(installVersionFile, 'ascii', function (err, ver) {
if (err && err.code !== 'ENOENT') {
return cb(err)
}
var installVersion = parseInt(ver, 10) || 0
log.verbose('got "installVersion"', installVersion)
log.verbose('needs "installVersion"', gyp.package.installVersion)
if (installVersion < gyp.package.installVersion) {
log.verbose('install', 'version is no good; reinstalling')
go()
} else {
log.verbose('install', 'version is good')
cb()
}
})
})
} else {
go()
}
}

if (gyp.opts.ninja) {
downloadNinja((err, alreadyExists) => {
if (err) return cb(err)

if (alreadyExists) {
log.verbose('ninja', 'appears to be previously installed')
handleInstall()
} else {
log.verbose('ninja', 'building...')
buildNinja(handleInstall)
}
})
} else {
go()
handleInstall()
}

function getContentSha (res, callback) {
Expand Down Expand Up @@ -297,7 +321,7 @@ function install (fs, gyp, argv, callback) {
}

function downloadNodeLib (done) {
log.verbose('on Windows; need to download `' + release.name + '.lib`...')
log.verbose('on Windows need to download `' + release.name + '.lib`...')
var archs = ['ia32', 'x64', 'arm64']
var async = archs.length
archs.forEach(function (arch) {
Expand Down Expand Up @@ -352,6 +376,60 @@ function install (fs, gyp, argv, callback) {
}) // mkdir()
} // go()

function downloadNinja (done) {
if (fs.existsSync(ninjaPath) && gyp.opts.ensure) {
return done(null, true)
}

log.verbose('ninja', `url: ${ninjaUrl}`)
log.verbose('ninja', 'downloading...')

request({ strictSSL: false, url: ninjaUrl })
.on('response', (res) => {
if (res.statusCode !== 200) {
const error = new Error(`Ninja failed downloading tarball: ${res.statusCode}`)
return done(error)
}

log.verbose('ninja', `http status: ${res.statusCode}`)
function logger (path) {
const name = path.substring(ninjaPath.length + 1).replace(/[.]+?\//, '')
if (name.length > 0) {
log.verbose('ninja extracting: ', name)
}
return true
}

fs.mkdirSync(ninjaPath)
res.pipe(tar.extract({
cwd: ninjaPath,
strip: 1,
filter: logger
}).on('end', done).on('error', done))
})
.on('error', done)
}

function buildNinja (done) {
const bootstrap = spawn('python', ['configure.py', '--bootstrap'], {
cwd: ninjaPath,
env: process.env
})

bootstrap.on('close', (code) => {
const error = 'Failed to build Ninja'
if (code !== 0) done(error)
done()
})

const dataFn = (data) => {
log.verbose('ninja bootstrap', data.toString().trim())
}

bootstrap.stdout.on('data', dataFn)
bootstrap.stderr.on('data', dataFn)
}

/**
* Checks if a given filename is "valid" for this installation.
*/
Expand Down
4 changes: 3 additions & 1 deletion lib/node-gyp.js
Expand Up @@ -75,7 +75,9 @@ proto.configDefs = {
'dist-url': String, // 'install'
tarball: String, // 'install'
jobs: String, // 'build'
thin: String // 'configure'
thin: String, // 'configure'
ninja: String, // 'everywhere
'ninja-path': String
}

/**
Expand Down

0 comments on commit d842d73

Please sign in to comment.