Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -108,6 +108,37 @@ you can require the `.node` file with Node and run your tests!
__Note:__ To create a _Debug_ build of the bindings file, pass the `--debug` (or
`-d`) switch when running either the `configure`, `build` or `rebuild` command.

#### Usage without Python

There is a [`gyp.js`](https://github.com/indutny/gyp.js/) project, a GYP
implementation in JavaScript. It generates [`Ninja`](https://ninja-build.org/)
build files and requires no Python installation.

In this case you will need to install [`Ninja`](https://ninja-build.org/) build
tool and a C/C++ compiler toolchain.

To generate projects files with `gyp.js` instead of `gyp` and to build them with
`ninja`, please supply a command-line option `--gypjs` in `node-gyp` command.

``` bash
$ node-gyp configure --gypjs
```

It is also possible to set `npm_config_gypjs` environment variable to turn on
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO no need for this after #1185

the `gyp.js` usage.

``` bash
$ npm_config_gypjs=1 node-gyp build
```

Path to an existing `ninja` installation can be set with a `--ninja` command-line
option or in a `NINJA` environment variable.

``` bash
$ node-gyp configure --gypjs --ninja=/my/path/to/ninja
$ npm_config_gypjs=1 NINJA=/my/path/to/ninja node-gyp build
```


The "binding.gyp" file
----------------------
@@ -184,6 +215,8 @@ Command Options
| `--python=$path` | Set path to the python (2) binary
| `--msvs_version=$version` | Set Visual Studio version (win)
| `--solution=$solution` | Set Visual Studio Solution version (win)
| `--gypjs` | Use gyp.js instead of gyp
| `--ninja=$ninja` | Override ninja command (with --gypjs)


License
2 changes: 1 addition & 1 deletion addon.gypi
Original file line number Diff line number Diff line change
@@ -92,7 +92,7 @@
'-luuid.lib',
'-lodbc32.lib',
'-lDelayImp.lib',
'-l"<(node_root_dir)/$(ConfigurationName)/<(node_lib_file)"'
'-l"<(node_lib_file)"'
],
'msvs_disabled_warnings': [
# warning C4251: 'node::ObjectWrap::handle_' : class 'v8::Persistent<T>'
136 changes: 64 additions & 72 deletions lib/build.js
Original file line number Diff line number Diff line change
@@ -11,12 +11,12 @@ var fs = require('graceful-fs')
, glob = require('glob')
, log = require('npmlog')
, which = require('which')
, mkdirp = require('mkdirp')
, exec = require('child_process').exec
, processRelease = require('./process-release')
, win = process.platform == 'win32'

exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module'
exports.usage = 'Invokes `' + (process.env.npm_config_gypjs ? 'ninja' :
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can move to ` templates

(win ? 'msbuild' : 'make')) + '` and builds the module'

function build (gyp, argv, callback) {
var platformMake = 'make'
@@ -36,8 +36,10 @@ function build (gyp, argv, callback) {
, config
, arch
, nodeDir
, copyDevLib

if (gyp.opts.gypjs) {
command = gyp.opts.ninja || process.env.NINJA || 'ninja'
}
loadConfigGypi()

/**
@@ -60,7 +62,6 @@ function build (gyp, argv, callback) {
buildType = config.target_defaults.default_configuration
arch = config.variables.target_arch
nodeDir = config.variables.nodedir
copyDevLib = config.variables.copy_dev_lib == 'true'

if ('debug' in gyp.opts) {
buildType = gyp.opts.debug ? 'Debug' : 'Release'
@@ -73,7 +74,7 @@ function build (gyp, argv, callback) {
log.verbose('architecture', arch)
log.verbose('node dev dir', nodeDir)

if (win) {
if (win && !gyp.opts.gypjs) {
findSolutionFile()
} else {
doWhich()
@@ -105,7 +106,7 @@ function build (gyp, argv, callback) {
// First make sure we have the build command in the PATH
which(command, function (err, execPath) {
if (err) {
if (win && /not found/.test(err.message)) {
if (win && !gyp.opts.gypjs && /not found/.test(err.message)) {
// On windows and no 'msbuild' found. Let's guess where it is
findMsbuild()
} else {
@@ -115,7 +116,7 @@ function build (gyp, argv, callback) {
return
}
log.verbose('`which` succeeded for `' + command + '`', execPath)
copyNodeLib()
doBuild()
})
}

@@ -173,36 +174,12 @@ function build (gyp, argv, callback) {
return
}
command = msbuildPath
copyNodeLib()
doBuild()
})
})()
})
}

/**
* Copies the node.lib file for the current target architecture into the
* current proper dev dir location.
*/

function copyNodeLib () {
if (!win || !copyDevLib) return doBuild()

var buildDir = path.resolve(nodeDir, buildType)
, archNodeLibPath = path.resolve(nodeDir, arch, release.name + '.lib')
, buildNodeLibPath = path.resolve(buildDir, release.name + '.lib')

mkdirp(buildDir, function (err, isNew) {
if (err) return callback(err)
log.verbose('"' + buildType + '" dir needed to be created?', isNew)
var rs = fs.createReadStream(archNodeLibPath)
, ws = fs.createWriteStream(buildNodeLibPath)
log.verbose('copying "' + release.name + '.lib" for ' + arch, buildNodeLibPath)
rs.pipe(ws)
rs.on('error', callback)
ws.on('error', callback)
rs.on('end', doBuild)
})
}

/**
* Actually spawn the process and compile the module.
@@ -212,57 +189,72 @@ function build (gyp, argv, callback) {

// Enable Verbose build
var verbose = log.levels[log.level] <= log.levels.verbose
if (!win && verbose) {
argv.push('V=1')
}
if (win && !verbose) {
argv.push('/clp:Verbosity=minimal')
}
if (!gyp.opts.gypjs) {
if (!win && verbose) {
argv.push('V=1')
}
if (win && !verbose) {
argv.push('/clp:Verbosity=minimal')
}

if (win) {
// Turn off the Microsoft logo on Windows
argv.push('/nologo')
}
if (win) {
// Turn off the Microsoft logo on Windows
argv.push('/nologo')
}

// Specify the build type, Release by default
if (win) {
var p = arch === 'x64' ? 'x64' : 'Win32'
argv.push('/p:Configuration=' + buildType + ';Platform=' + p)
if (jobs) {
var j = parseInt(jobs, 10)
if (!isNaN(j) && j > 0) {
argv.push('/m:' + j)
} else if (jobs.toUpperCase() === 'MAX') {
argv.push('/m:' + require('os').cpus().length)
// Specify the build type, Release by default
if (win) {
var p = arch === 'x64' ? 'x64' : 'Win32'
argv.push('/p:Configuration=' + buildType + ';Platform=' + p)
if (jobs) {
var j = parseInt(jobs, 10)
if (!isNaN(j) && j > 0) {
argv.push('/m:' + j)
} else if (jobs.toUpperCase() === 'MAX') {
argv.push('/m:' + require('os').cpus().length)
}
}
} else {
argv.push('BUILDTYPE=' + buildType)
// Invoke the Makefile in the 'build' dir.
argv.push('-C')
argv.push('build')
if (jobs) {
var j = parseInt(jobs, 10)
if (!isNaN(j) && j > 0) {
argv.push('--jobs')
argv.push(j)
} else if (jobs.toUpperCase() === 'MAX') {
argv.push('--jobs')
argv.push(require('os').cpus().length)
}
}
}

if (win) {
// did the user specify their own .sln file?
var hasSln = argv.some(function (arg) {
return path.extname(arg) == '.sln'
})
if (!hasSln) {
argv.unshift(gyp.opts.solution || guessedSolution)
}
}
} else {
argv.push('BUILDTYPE=' + buildType)
// Invoke the Makefile in the 'build' dir.
argv.push('-C')
argv.push('build')
// build with ninja
if (verbose) {
argv.push('-v')
}
// Specify the build type, Release by default
argv.push('-C', path.join('build', buildType))
if (jobs) {
var j = parseInt(jobs, 10)
var j = jobs.toUpperCase() === 'MAX'? require('os').cpus().length : parseInt(jobs, 10)
if (!isNaN(j) && j > 0) {
argv.push('--jobs')
argv.push(j)
} else if (jobs.toUpperCase() === 'MAX') {
argv.push('--jobs')
argv.push(require('os').cpus().length)
argv.push('-j' + j)
}
}
}

if (win) {
// did the user specify their own .sln file?
var hasSln = argv.some(function (arg) {
return path.extname(arg) == '.sln'
})
if (!hasSln) {
argv.unshift(gyp.opts.solution || guessedSolution)
}
}

var proc = gyp.spawn(command, argv)
proc.on('exit', onExit)
}
120 changes: 71 additions & 49 deletions lib/configure.js
Original file line number Diff line number Diff line change
@@ -21,27 +21,39 @@ var fs = require('graceful-fs')
, processRelease = require('./process-release')
, win = process.platform == 'win32'
, findNodeDirectory = require('./find-node-directory')
, msgFormat = require('util').format
, gypjs = undefined

exports.usage = 'Generates ' + (win ? 'MSVC project files' : 'a Makefile') + ' for the current module'
exports.usage = 'Generates ' + (process.env.npm_config_gypjs ? 'ninja build files' :
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

template

(win ? 'MSVC project files' : 'a Makefile')) + ' for the current module'

function configure (gyp, argv, callback) {

var python = gyp.opts.python || process.env.PYTHON || 'python2'
, buildDir = path.resolve('build')
, configNames = [ 'config.gypi', 'common.gypi' ]
, configs = []
, buildType
, arch
, nodeDir
, release = processRelease(argv, gyp, process.version, process.release)

findPython(python, function (err, found) {
if (err) {
callback(err)
} else {
python = found
getNodeDir()
if (!gyp.opts.gypjs) {
findPython(python, function (err, found) {
if (err) {
callback(err)
} else {
python = found
getNodeDir()
}
})
} else {
try {
gypjs = require('gyp.js')
} catch (err) {
return callback(new Error('Can\'t find module gyp.js, you can install it with `npm install gyp.js`'))
}
})
getNodeDir()
}

function getNodeDir () {

@@ -124,16 +136,14 @@ function configure (gyp, argv, callback) {
if (!defaults.default_configuration) {
defaults.default_configuration = 'Release'
}
buildType = defaults.default_configuration

// set the target_arch variable
variables.target_arch = gyp.opts.arch || process.arch || 'ia32'
variables.target_arch = arch = gyp.opts.arch || process.arch || 'ia32'

// set the node development directory
variables.nodedir = nodeDir

// don't copy dev libraries with nodedir option
variables.copy_dev_lib = !gyp.opts.nodedir

// disable -T "thin" static archives by default
variables.standalone_static_library = gyp.opts.thin ? 0 : 1

@@ -188,35 +198,37 @@ function configure (gyp, argv, callback) {
function runGyp (err) {
if (err) return callback(err)

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
argv.push('-f', 'msvs')
} else {
log.verbose('gyp', 'gyp format was not specified; forcing "make"')
// force the 'make' target for non-Windows
argv.push('-f', 'make')
if (!gyp.opts.gypjs) {
if (!~argv.indexOf('-f') && !~argv.indexOf('--format')) {
if (win) {
log.verbose('gyp', 'gyp format was not specified; forcing "msvs"')
// force the 'msvs' target for non-Windows
argv.push('-f', 'msvs')
} else {
log.verbose('gyp', 'gyp format was not specified; forcing "make"')
// force the 'make' target for non-Windows
argv.push('-f', 'make')
}
}
}

function hasMsvsVersion () {
return argv.some(function (arg) {
return arg.indexOf('msvs_version') === 0
})
}
function hasMsvsVersion () {
return argv.some(function (arg) {
return arg.indexOf('msvs_version') === 0
})
}

if (win && !hasMsvsVersion()) {
if ('msvs_version' in gyp.opts) {
argv.push('-G', 'msvs_version=' + gyp.opts.msvs_version)
} else {
argv.push('-G', 'msvs_version=auto')
if (win && !hasMsvsVersion()) {
if ('msvs_version' in gyp.opts) {
argv.push('-G', 'msvs_version=' + gyp.opts.msvs_version)
} else {
argv.push('-G', 'msvs_version=auto')
}
}
}

// include all the ".gypi" files that were found
configs.forEach(function (config) {
argv.push('-I', config)
argv.push('-I' + config)
})

// for AIX we need to set up the path to the exp file
@@ -240,9 +252,8 @@ function configure (gyp, argv, callback) {
if (node_exp_file !== undefined) {
log.verbose(logprefix, 'Found exports file: %s', node_exp_file)
} else {
var msg = msgFormat('Could not find node.exp file in %s', node_root_dir)
log.error(logprefix, 'Could not find exports file')
return callback(new Error(msg))
return callback(new Error('Could not find node.exp file in ' + node_root_dir))
}
}

@@ -260,17 +271,21 @@ function configure (gyp, argv, callback) {
output_dir = buildDir
}
var nodeGypDir = path.resolve(__dirname, '..')
var nodeLibFile = path.join(nodeDir,
!gyp.opts.nodedir ? '<(target_arch)' :
(gyp.opts.gypjs ? buildType : '$(Configuration)'),
release.name + '.lib')

argv.push('-I', addon_gypi)
argv.push('-I', common_gypi)
argv.push('-I' + addon_gypi)
argv.push('-I' + common_gypi)
argv.push('-Dlibrary=shared_library')
argv.push('-Dvisibility=default')
argv.push('-Dnode_root_dir=' + nodeDir)
if (process.platform === 'aix') {
argv.push('-Dnode_exp_file=' + node_exp_file)
}
argv.push('-Dnode_gyp_dir=' + nodeGypDir)
argv.push('-Dnode_lib_file=' + release.name + '.lib')
argv.push('-Dnode_lib_file=' + nodeLibFile)
argv.push('-Dmodule_root_dir=' + process.cwd())
argv.push('--depth=.')
argv.push('--no-parallel')
@@ -284,18 +299,25 @@ function configure (gyp, argv, callback) {
// enforce use of the "binding.gyp" file
argv.unshift('binding.gyp')

// execute `gyp` from the current target nodedir
argv.unshift(gyp_script)
if (!gyp.opts.gypjs) {
// execute `gyp` from the current target nodedir
argv.unshift(gyp_script)

// make sure python uses files that came with this particular node package
var pypath = [path.join(__dirname, '..', 'gyp', 'pylib')]
if (process.env.PYTHONPATH) {
pypath.push(process.env.PYTHONPATH)
}
process.env.PYTHONPATH = pypath.join(win ? ';' : ':')
// make sure python uses files that came with this particular node package
var pypath = [path.join(__dirname, '..', 'gyp', 'pylib')]
if (process.env.PYTHONPATH) {
pypath.push(process.env.PYTHONPATH)
}
process.env.PYTHONPATH = pypath.join(win ? ';' : ':')

var cp = gyp.spawn(python, argv)
cp.on('exit', onCpExit)
var cp = gyp.spawn(python, argv)
cp.on('exit', onCpExit)
} else {
argv.push('-Dtarget_arch=' + arch)
log.info('using', 'gyp.js@' + gypjs.version)
log.info('gyp.js args', argv)
onCpExit(gypjs.main(argv, path.join(process.cwd(), 'build', buildType)))
}
})
}

4 changes: 4 additions & 0 deletions lib/node-gyp.js
Original file line number Diff line number Diff line change
@@ -89,6 +89,7 @@ proto.configDefs = {
, 'tarball': String // 'install'
, jobs: String // 'build'
, thin: String // 'configure'
, gypjs: Boolean // 'configure', 'build'
}

/**
@@ -165,6 +166,9 @@ proto.parseArgv = function parseOpts (argv) {
if (this.opts.loglevel) {
log.level = this.opts.loglevel
}
if (this.opts.gypjs) {
process.env[npm_config_prefix + 'gypjs'] = true
}
log.resume()
}