Skip to content

Commit eb2c709

Browse files
committed
See issue #960 Added initial `gyp.js` support with --gypjs command line option. Environment variable `npm_config_gypjs` also turns this option on. Update configure and build usage strings depending on `npm_config_gypjs` environment variable. Set `npm_config_gypjs` env variable if `--gypjs` command-line option was set to affect usage text for `configure` and `build` commands. Update usage strings if `--gypjs` command-line option was supplied Trying to load gyp.js module only if --gypjs command-line option was supplied.
1 parent 5eb0972 commit eb2c709

File tree

4 files changed

+162
-86
lines changed

4 files changed

+162
-86
lines changed

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,37 @@ you can require the `.node` file with Node and run your tests!
106106
__Note:__ To create a _Debug_ build of the bindings file, pass the `--debug` (or
107107
`-d`) switch when running either the `configure`, `build` or `rebuild` command.
108108

109+
#### Usage without Python
110+
111+
There is a [`gyp.js`](https://github.com/indutny/gyp.js/) project, a GYP
112+
implementation in JavaScript. It generates [`Ninja`](https://ninja-build.org/)
113+
build files and requires no Python installation.
114+
115+
In this case you will need to install [`Ninja`](https://ninja-build.org/) build
116+
tool and a C/C++ compiler toolchain.
117+
118+
To generate projects files with `gyp.js` instead of `gyp` and to build them with
119+
`ninja`, please supply a command-line option `--gypjs` in `node-gyp` command.
120+
121+
``` bash
122+
$ node-gyp configure --gypjs
123+
```
124+
125+
It is also possible to set `npm_config_gypjs` environment variable to turn on
126+
the `gyp.js` usage.
127+
128+
``` bash
129+
$ npm_config_gypjs=1 node-gyp build
130+
```
131+
132+
Path to an existing `ninja` installation can be set with a `--ninja` command-line
133+
option or in a `NINJA` environment variable.
134+
135+
``` bash
136+
$ node-gyp configure --gypjs --ninja=/my/path/to/ninja
137+
$ npm_config_gypjs=1 NINJA=/my/path/to/ninja node-gyp build
138+
```
139+
109140

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

185218

186219
License

lib/build.js

Lines changed: 62 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ var fs = require('graceful-fs')
1515
, processRelease = require('./process-release')
1616
, win = process.platform == 'win32'
1717

18-
exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module'
18+
exports.usage = 'Invokes `' + (process.env.npm_config_gypjs ? 'ninja' :
19+
(win ? 'msbuild' : 'make')) + '` and builds the module'
1920

2021
function build (gyp, argv, callback) {
2122
var platformMake = 'make'
@@ -36,6 +37,9 @@ function build (gyp, argv, callback) {
3637
, arch
3738
, nodeDir
3839

40+
if (gyp.opts.gypjs) {
41+
command = gyp.opts.ninja || process.env.NINJA || 'ninja'
42+
}
3943
loadConfigGypi()
4044

4145
/**
@@ -70,7 +74,7 @@ function build (gyp, argv, callback) {
7074
log.verbose('architecture', arch)
7175
log.verbose('node dev dir', nodeDir)
7276

73-
if (win) {
77+
if (win && !gyp.opts.gypjs) {
7478
findSolutionFile()
7579
} else {
7680
doWhich()
@@ -102,7 +106,7 @@ function build (gyp, argv, callback) {
102106
// First make sure we have the build command in the PATH
103107
which(command, function (err, execPath) {
104108
if (err) {
105-
if (win && /not found/.test(err.message)) {
109+
if (win && !gyp.opts.gypjs && /not found/.test(err.message)) {
106110
// On windows and no 'msbuild' found. Let's guess where it is
107111
findMsbuild()
108112
} else {
@@ -185,57 +189,72 @@ function build (gyp, argv, callback) {
185189

186190
// Enable Verbose build
187191
var verbose = log.levels[log.level] <= log.levels.verbose
188-
if (!win && verbose) {
189-
argv.push('V=1')
190-
}
191-
if (win && !verbose) {
192-
argv.push('/clp:Verbosity=minimal')
193-
}
192+
if (!gyp.opts.gypjs) {
193+
if (!win && verbose) {
194+
argv.push('V=1')
195+
}
196+
if (win && !verbose) {
197+
argv.push('/clp:Verbosity=minimal')
198+
}
194199

195-
if (win) {
196-
// Turn off the Microsoft logo on Windows
197-
argv.push('/nologo')
198-
}
200+
if (win) {
201+
// Turn off the Microsoft logo on Windows
202+
argv.push('/nologo')
203+
}
199204

200-
// Specify the build type, Release by default
201-
if (win) {
202-
var p = arch === 'x64' ? 'x64' : 'Win32'
203-
argv.push('/p:Configuration=' + buildType + ';Platform=' + p)
204-
if (jobs) {
205-
var j = parseInt(jobs, 10)
206-
if (!isNaN(j) && j > 0) {
207-
argv.push('/m:' + j)
208-
} else if (jobs.toUpperCase() === 'MAX') {
209-
argv.push('/m:' + require('os').cpus().length)
205+
// Specify the build type, Release by default
206+
if (win) {
207+
var p = arch === 'x64' ? 'x64' : 'Win32'
208+
argv.push('/p:Configuration=' + buildType + ';Platform=' + p)
209+
if (jobs) {
210+
var j = parseInt(jobs, 10)
211+
if (!isNaN(j) && j > 0) {
212+
argv.push('/m:' + j)
213+
} else if (jobs.toUpperCase() === 'MAX') {
214+
argv.push('/m:' + require('os').cpus().length)
215+
}
216+
}
217+
} else {
218+
argv.push('BUILDTYPE=' + buildType)
219+
// Invoke the Makefile in the 'build' dir.
220+
argv.push('-C')
221+
argv.push('build')
222+
if (jobs) {
223+
var j = parseInt(jobs, 10)
224+
if (!isNaN(j) && j > 0) {
225+
argv.push('--jobs')
226+
argv.push(j)
227+
} else if (jobs.toUpperCase() === 'MAX') {
228+
argv.push('--jobs')
229+
argv.push(require('os').cpus().length)
230+
}
231+
}
232+
}
233+
234+
if (win) {
235+
// did the user specify their own .sln file?
236+
var hasSln = argv.some(function (arg) {
237+
return path.extname(arg) == '.sln'
238+
})
239+
if (!hasSln) {
240+
argv.unshift(gyp.opts.solution || guessedSolution)
210241
}
211242
}
212243
} else {
213-
argv.push('BUILDTYPE=' + buildType)
214-
// Invoke the Makefile in the 'build' dir.
215-
argv.push('-C')
216-
argv.push('build')
244+
// build with ninja
245+
if (verbose) {
246+
argv.push('-v')
247+
}
248+
// Specify the build type, Release by default
249+
argv.push('-C', path.join('build', buildType))
217250
if (jobs) {
218-
var j = parseInt(jobs, 10)
251+
var j = jobs.toUpperCase() === 'MAX'? require('os').cpus().length : parseInt(jobs, 10)
219252
if (!isNaN(j) && j > 0) {
220-
argv.push('--jobs')
221-
argv.push(j)
222-
} else if (jobs.toUpperCase() === 'MAX') {
223-
argv.push('--jobs')
224-
argv.push(require('os').cpus().length)
253+
argv.push('-j' + j)
225254
}
226255
}
227256
}
228257

229-
if (win) {
230-
// did the user specify their own .sln file?
231-
var hasSln = argv.some(function (arg) {
232-
return path.extname(arg) == '.sln'
233-
})
234-
if (!hasSln) {
235-
argv.unshift(gyp.opts.solution || guessedSolution)
236-
}
237-
}
238-
239258
var proc = gyp.spawn(command, argv)
240259
proc.on('exit', onExit)
241260
}

lib/configure.js

Lines changed: 63 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,39 @@ var fs = require('graceful-fs')
2121
, execFile = cp.execFile
2222
, win = process.platform == 'win32'
2323
, findNodeDirectory = require('./find-node-directory')
24-
, msgFormat = require('util').format
24+
, gypjs = undefined
2525

26-
exports.usage = 'Generates ' + (win ? 'MSVC project files' : 'a Makefile') + ' for the current module'
26+
exports.usage = 'Generates ' + (process.env.npm_config_gypjs ? 'ninja build files' :
27+
(win ? 'MSVC project files' : 'a Makefile')) + ' for the current module'
2728

2829
function configure (gyp, argv, callback) {
2930

3031
var python = gyp.opts.python || process.env.PYTHON || 'python2'
3132
, buildDir = path.resolve('build')
3233
, configNames = [ 'config.gypi', 'common.gypi' ]
3334
, configs = []
35+
, buildType
36+
, arch
3437
, nodeDir
3538
, release = processRelease(argv, gyp, process.version, process.release)
3639

37-
findPython(python, function (err, found) {
38-
if (err) {
39-
callback(err)
40-
} else {
41-
python = found
42-
getNodeDir()
40+
if (!gyp.opts.gypjs) {
41+
findPython(python, function (err, found) {
42+
if (err) {
43+
callback(err)
44+
} else {
45+
python = found
46+
getNodeDir()
47+
}
48+
})
49+
} else {
50+
try {
51+
gypjs = require('gyp.js')
52+
} catch (err) {
53+
return callback(new Error('Can\'t find module gyp.js, you can install it with `npm install gyp.js`'))
4354
}
44-
})
55+
getNodeDir()
56+
}
4557

4658
function getNodeDir () {
4759

@@ -124,9 +136,10 @@ function configure (gyp, argv, callback) {
124136
if (!defaults.default_configuration) {
125137
defaults.default_configuration = 'Release'
126138
}
139+
buildType = defaults.default_configuration
127140

128141
// set the target_arch variable
129-
variables.target_arch = gyp.opts.arch || process.arch || 'ia32'
142+
variables.target_arch = arch = gyp.opts.arch || process.arch || 'ia32'
130143

131144
// set the node development directory
132145
variables.nodedir = nodeDir
@@ -185,35 +198,37 @@ function configure (gyp, argv, callback) {
185198
function runGyp (err) {
186199
if (err) return callback(err)
187200

188-
if (!~argv.indexOf('-f') && !~argv.indexOf('--format')) {
189-
if (win) {
190-
log.verbose('gyp', 'gyp format was not specified; forcing "msvs"')
191-
// force the 'make' target for non-Windows
192-
argv.push('-f', 'msvs')
193-
} else {
194-
log.verbose('gyp', 'gyp format was not specified; forcing "make"')
195-
// force the 'make' target for non-Windows
196-
argv.push('-f', 'make')
201+
if (!gyp.opts.gypjs) {
202+
if (!~argv.indexOf('-f') && !~argv.indexOf('--format')) {
203+
if (win) {
204+
log.verbose('gyp', 'gyp format was not specified; forcing "msvs"')
205+
// force the 'msvs' target for non-Windows
206+
argv.push('-f', 'msvs')
207+
} else {
208+
log.verbose('gyp', 'gyp format was not specified; forcing "make"')
209+
// force the 'make' target for non-Windows
210+
argv.push('-f', 'make')
211+
}
197212
}
198-
}
199213

200-
function hasMsvsVersion () {
201-
return argv.some(function (arg) {
202-
return arg.indexOf('msvs_version') === 0
203-
})
204-
}
214+
function hasMsvsVersion () {
215+
return argv.some(function (arg) {
216+
return arg.indexOf('msvs_version') === 0
217+
})
218+
}
205219

206-
if (win && !hasMsvsVersion()) {
207-
if ('msvs_version' in gyp.opts) {
208-
argv.push('-G', 'msvs_version=' + gyp.opts.msvs_version)
209-
} else {
210-
argv.push('-G', 'msvs_version=auto')
220+
if (win && !hasMsvsVersion()) {
221+
if ('msvs_version' in gyp.opts) {
222+
argv.push('-G', 'msvs_version=' + gyp.opts.msvs_version)
223+
} else {
224+
argv.push('-G', 'msvs_version=auto')
225+
}
211226
}
212227
}
213228

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

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

@@ -258,11 +272,12 @@ function configure (gyp, argv, callback) {
258272
}
259273
var nodeGypDir = path.resolve(__dirname, '..')
260274
var nodeLibFile = path.join(nodeDir,
261-
!gyp.opts.nodedir ? '<(target_arch)' : '$(Configuration)',
275+
!gyp.opts.nodedir ? '<(target_arch)' :
276+
(gyp.opts.gypjs ? buildType : '$(Configuration)'),
262277
release.name + '.lib')
263278

264-
argv.push('-I', addon_gypi)
265-
argv.push('-I', common_gypi)
279+
argv.push('-I' + addon_gypi)
280+
argv.push('-I' + common_gypi)
266281
argv.push('-Dlibrary=shared_library')
267282
argv.push('-Dvisibility=default')
268283
argv.push('-Dnode_root_dir=' + nodeDir)
@@ -284,15 +299,20 @@ function configure (gyp, argv, callback) {
284299
// enforce use of the "binding.gyp" file
285300
argv.unshift('binding.gyp')
286301

287-
// execute `gyp` from the current target nodedir
288-
argv.unshift(gyp_script)
302+
if (!gyp.opts.gypjs) {
303+
// execute `gyp` from the current target nodedir
304+
argv.unshift(gyp_script)
289305

290-
// make sure python uses files that came with this particular node package
291-
var pypath = new PathArray(process.env, 'PYTHONPATH')
292-
pypath.unshift(path.join(__dirname, '..', 'gyp', 'pylib'))
306+
// make sure python uses files that came with this particular node package
307+
var pypath = new PathArray(process.env, 'PYTHONPATH')
308+
pypath.unshift(path.join(__dirname, '..', 'gyp', 'pylib'))
293309

294-
var cp = gyp.spawn(python, argv)
295-
cp.on('exit', onCpExit)
310+
var cp = gyp.spawn(python, argv)
311+
cp.on('exit', onCpExit)
312+
} else {
313+
argv.push('-Dtarget_arch=' + arch)
314+
onCpExit(gypjs.main(argv))
315+
}
296316
})
297317
}
298318

lib/node-gyp.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ proto.configDefs = {
9999
, 'tarball': String // 'install'
100100
, jobs: String // 'build'
101101
, thin: String // 'configure'
102+
, gypjs: Boolean // 'configure', 'build'
102103
}
103104

104105
/**
@@ -175,6 +176,9 @@ proto.parseArgv = function parseOpts (argv) {
175176
if (this.opts.loglevel) {
176177
log.level = this.opts.loglevel
177178
}
179+
if (this.opts.gypjs) {
180+
process.env[npm_config_prefix + 'gypjs'] = true
181+
}
178182
log.resume()
179183
}
180184

0 commit comments

Comments
 (0)