Skip to content

Commit

Permalink
win: detect all VS versions in node-gyp
Browse files Browse the repository at this point in the history
PR-URL: #1762
Reviewed-By: Rod Vagg <[email protected]>
Reviewed-By: Refael Ackermann <[email protected]>
  • Loading branch information
joaocgreis committed Jun 4, 2019
1 parent 7fe4095 commit 8f43f68
Show file tree
Hide file tree
Showing 5 changed files with 636 additions and 206 deletions.
76 changes: 7 additions & 69 deletions lib/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ var fs = require('graceful-fs')
, glob = require('glob')
, log = require('npmlog')
, which = require('which')
, exec = require('child_process').exec
, win = process.platform === 'win32'

exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module'
Expand Down Expand Up @@ -96,7 +95,11 @@ function build (gyp, argv, callback) {

function doWhich () {
// On Windows use msbuild provided by node-gyp configure
if (win && config.variables.msbuild_path) {
if (win) {
if (!config.variables.msbuild_path) {
return callback(new Error(
'MSBuild is not set, please run `node-gyp configure`.'))
}
command = config.variables.msbuild_path
log.verbose('using MSBuild:', command)
doBuild()
Expand All @@ -105,80 +108,15 @@ 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)) {
// On windows and no 'msbuild' found. Let's guess where it is
findMsbuild()
} else {
// Some other error or 'make' not found on Unix, report that to the user
callback(err)
}
// Some other error or 'make' not found on Unix, report that to the user
callback(err)
return
}
log.verbose('`which` succeeded for `' + command + '`', execPath)
doBuild()
})
}

/**
* Search for the location of "msbuild.exe" file on Windows.
*/

function findMsbuild () {
log.verbose('could not find "msbuild.exe" in PATH - finding location in registry')
var notfoundErr = 'Can\'t find "msbuild.exe". Do you have Microsoft Visual Studio C++ 2008+ installed?'
var cmd = 'reg query "HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions" /s'
if (process.arch !== 'ia32')
cmd += ' /reg:32'
exec(cmd, function (err, stdout) {
if (err) {
return callback(new Error(err.message + '\n' + notfoundErr))
}
var reVers = /ToolsVersions\\([^\\]+)$/i
, rePath = /\r\n[ \t]+MSBuildToolsPath[ \t]+REG_SZ[ \t]+([^\r]+)/i
, msbuilds = []
, r
, msbuildPath
stdout.split('\r\n\r\n').forEach(function(l) {
if (!l) return
l = l.trim()
if (r = reVers.exec(l.substring(0, l.indexOf('\r\n')))) {
var ver = parseFloat(r[1], 10)
if (ver >= 3.5) {
if (r = rePath.exec(l)) {
msbuilds.push({
version: ver,
path: r[1]
})
}
}
}
})
msbuilds.sort(function (x, y) {
return (x.version < y.version ? -1 : 1)
})
;(function verifyMsbuild () {
if (!msbuilds.length) return callback(new Error(notfoundErr))
msbuildPath = path.resolve(msbuilds.pop().path, 'msbuild.exe')
fs.stat(msbuildPath, function (err) {
if (err) {
if (err.code == 'ENOENT') {
if (msbuilds.length) {
return verifyMsbuild()
} else {
callback(new Error(notfoundErr))
}
} else {
callback(err)
}
return
}
command = msbuildPath
doBuild()
})
})()
})
}

/**
* Actually spawn the process and compile the module.
*/
Expand Down
47 changes: 12 additions & 35 deletions lib/configure.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,22 +83,16 @@ function configure (gyp, argv, callback) {
mkdirp(buildDir, function (err, isNew) {
if (err) return callback(err)
log.verbose('build dir', '"build" dir needed to be created?', isNew)
if (win && (!gyp.opts.msvs_version || gyp.opts.msvs_version === '2017')) {
findVisualStudio(function (err, vsSetup) {
if (err) {
log.verbose('Not using VS2017:', err.message)
createConfigFile()
} else {
createConfigFile(null, vsSetup)
}
})
if (win) {
findVisualStudio(release.semver, gyp.opts.msvs_version,
createConfigFile)
} else {
createConfigFile()
}
})
}

function createConfigFile (err, vsSetup) {
function createConfigFile (err, vsInfo) {
if (err) return callback(err)

var configFilename = 'config.gypi'
Expand Down Expand Up @@ -145,17 +139,14 @@ function configure (gyp, argv, callback) {
// disable -T "thin" static archives by default
variables.standalone_static_library = gyp.opts.thin ? 0 : 1

if (vsSetup) {
// GYP doesn't (yet) have support for VS2017, so we force it to VS2015
// to avoid pulling a floating patch that has not landed upstream.
// Ref: https://chromium-review.googlesource.com/#/c/433540/
gyp.opts.msvs_version = '2015'
process.env['GYP_MSVS_VERSION'] = 2015
process.env['GYP_MSVS_OVERRIDE_PATH'] = vsSetup.path
defaults['msbuild_toolset'] = 'v141'
defaults['msvs_windows_target_platform_version'] = vsSetup.sdk
variables['msbuild_path'] = path.join(vsSetup.path, 'MSBuild', '15.0',
'Bin', 'MSBuild.exe')
if (win) {
process.env['GYP_MSVS_VERSION'] = Math.min(vsInfo.versionYear, 2015)
process.env['GYP_MSVS_OVERRIDE_PATH'] = vsInfo.path
defaults['msbuild_toolset'] = vsInfo.toolset
if (vsInfo.sdk) {
defaults['msvs_windows_target_platform_version'] = vsInfo.sdk
}
variables['msbuild_path'] = vsInfo.msBuild
}

// loop through the rest of the opts and add the unknown ones as variables.
Expand Down Expand Up @@ -221,20 +212,6 @@ function configure (gyp, argv, callback) {
}
}

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')
}
}

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

0 comments on commit 8f43f68

Please sign in to comment.