Skip to content

Commit a9cabb9

Browse files
committed
Use minimal powershell script to extract VS2017 location and version via COM*
Work with all flavors of VS2017, even the minimal "C++ Build Tools" *https://blogs.msdn.microsoft.com/heaths/2016/09/15/changes-to-visual-studio-15-setup/
1 parent f452498 commit a9cabb9

File tree

2 files changed

+262
-113
lines changed

2 files changed

+262
-113
lines changed

lib/find-vs2017.js

Lines changed: 49 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,138 +1,74 @@
11
module.exports = {
22
locateMsbuild: locateMsbuild,
3-
locateVS2017: locateVS2017,
4-
getVS2017WinSDKVersion: getVS2017WinSDKVersion,
53
setGypVS2017Env: setGypVS2017Env
64
}
75

86
var log = require('npmlog')
97
, fs = require('fs')
108
, path = require('path')
119
, cp = require('child_process')
12-
, win = process.platform == 'win32'
13-
, msgFormat = require('util').format
14-
, findPython = require('./find-python')
1510

16-
var vs2017_install_path
17-
, vs2017_win_sdk_ver
18-
19-
function run_locate(gyp, callback) {
20-
if (!win) {
21-
return callback(null, '', '')
11+
var vs2017Setup
12+
13+
function tryVS7_COM (gyp) {
14+
if (vs2017Setup) return vs2017Setup;
15+
try {
16+
const csFile = path.join(__dirname, '..', 'tools', 'Get-VS7.cs');
17+
const cmd = 'powershell -ExecutionPolicy Unrestricted -Command ' +
18+
'"&{ Add-Type -Path \'' + csFile + '\'; [VisualStudioConfiguration.Main]::Query()}"'
19+
const vsSetupRaw = cp.execSync(cmd).toString();
20+
if (!vsSetupRaw) return;
21+
const vsSetup = vsSetupRaw.split(/[\r|\n]/g).reduce((s, l) => {
22+
const lParts = l.split(': ');
23+
if (lParts.length > 1) s[lParts[0]] = lParts[1];
24+
return s;
25+
}, {});
26+
return vs2017Setup = vsSetup;
27+
} catch (e) {
28+
gyp.log.verbose('try VS7', 'Couldn\'t find VS2017 :(');
2229
}
30+
}
2331

24-
if (vs2017_install_path || vs2017_install_path === '') {
25-
return callback(null, vs2017_install_path, vs2017_win_sdk_ver)
26-
}
27-
28-
var python = gyp.opts.python || process.env.PYTHON || 'python2'
29-
, findvc_path = path.join(__dirname, '..', 'find_vs2017.py')
30-
31-
findPython(python, locate_vc);
32-
33-
function locate_vc(err, python_bin) {
34-
if (err) {
35-
return callback(err)
36-
}
37-
38-
log.verbose('find vs2017', 'obtaining vs2017 install path using script %s',
39-
findvc_path)
40-
cp.execFile(python_bin, [findvc_path], function(err, stdout, stderr) {
41-
if (err) {
42-
return callback(err)
43-
}
44-
if (stdout) {
45-
vs2017_install_path = stdout.split('\r\n')[0]
46-
log.verbose('find vs2017', 'found Visual Studio 2017 in %s', vs2017_install_path)
47-
get_sdk_version(python_bin)
48-
} else {
49-
log.verbose('find vs2017',
50-
'no valid Visual Studio 2017 installation found')
51-
vs2017_install_path = ''
52-
vs2017_win_sdk_ver = ''
53-
}
54-
})
32+
function tryVS7_registry(gyp) {
33+
const magicKey = String.raw`HKLM\Software\Microsoft\VisualStudio\SxS\VS7`;
34+
const magicQuery = `reg query ${magicKey} /reg:32`;
35+
const qRet = cp.execSync(magicQuery).toString().trim();
36+
if (qRet.includes('ERROR')) {
37+
gyp.bindings.log('Couldn\'t find VS7 in registry:(');
38+
return;
5539
}
56-
57-
function get_sdk_version(python_bin) {
58-
log.verbose('find vs2017', 'obtaining installed Windows SDKs')
59-
cp.execFile(python_bin, [findvc_path, vs2017_install_path],
60-
function(err, stdout, stderr) {
61-
if (err) {
62-
return callback(err)
63-
}
64-
if (stdout) {
65-
vs2017_win_sdk_ver = stdout.split('\r\n')[0]
66-
log.verbose('find vs2017', 'found VS2017 WinSDK %s', vs2017_win_sdk_ver)
67-
} else {
68-
log.verbose('find vs2017', 'no installed sdks found')
69-
}
70-
71-
callback(null, vs2017_install_path, vs2017_win_sdk_ver)
72-
})
40+
const values = qRet.split(/[\r|\n]+/g).slice(1);
41+
const ret = values.map(v => {
42+
const parts = v.trim().replace(/\s+/g, ' ').split(' ');
43+
return [Number(parts[0]), parts[2]];
44+
});
45+
if (!ret.length) {
46+
gyp.bindings.log('Couldn\'t find VS7 in registry');
47+
return;
7348
}
74-
49+
const maxVer = Math.max.apply(Math, ret.map(v => v[0]));
50+
return ret.find(v => v[0] === maxVer)[1];
7551
}
7652

7753
function locateMsbuild(gyp, callback) {
78-
run_locate(gyp, function(err, vs_path, sdk) {
79-
if (err) {
80-
return callback(err)
81-
}
82-
if (vs_path === '') {
83-
return callback()
84-
}
85-
var msbuild_location = path.join(vs_path, 'MSBuild',
86-
'15.0', 'Bin', 'MSBuild.exe')
87-
log.verbose('find vs2017', 'looking for msbuild in %s', msbuild_location)
88-
fs.access(msbuild_location, function(err) {
89-
callback(null, err ? null : msbuild_location)
90-
})
91-
})
92-
}
54+
const vsSetup = tryVS7_COM(gyp) || tryVS7_registry(gyp);
55+
if (!vsSetup)return callback()
9356

94-
function locateVS2017(gyp, callback) {
95-
run_locate(gyp, function(err, vs_path, sdk) {
96-
if (err) {
97-
callback(err)
98-
} else {
99-
callback(null, vs_path === '' ? null : vs_path)
100-
}
57+
const msbuild_location = path.join(vsSetup.InstallationPath, 'MSBuild',
58+
'15.0', 'Bin', 'MSBuild.exe')
59+
log.verbose('find vs2017', 'looking for msbuild in %s', msbuild_location)
60+
fs.access(msbuild_location, function(err) {
61+
callback(null, err ? null : msbuild_location)
10162
})
10263
}
10364

104-
function getVS2017WinSDKVersion(gyp, callback) {
105-
run_locate(gyp, function(err, vs_path, sdk) {
106-
if (err) {
107-
callback(err)
108-
} else {
109-
callback(null, sdk === '' ? null : sdk)
110-
}
111-
})
112-
}
11365

11466
function setGypVS2017Env(gyp, callback) {
115-
locateVS2017(gyp, setPath)
116-
117-
function setPath(err, vs_path) {
118-
if (err) {
119-
return callback(err)
120-
}
121-
if (vs_path) {
122-
process.env['vs2017_install'] = vs_path
123-
getVS2017WinSDKVersion(gyp, setSDK)
124-
} else {
125-
callback()
126-
}
127-
}
67+
const vsSetup = tryVS7_COM(gyp) || tryVS7_registry(gyp);
68+
if (!vsSetup)return callback()
12869

129-
function setSDK(err, sdk) {
130-
if (err) {
131-
return callback(err)
132-
}
133-
if (sdk) {
134-
process.env['vs2017_sdk'] = sdk
135-
}
136-
callback()
137-
}
70+
gyp.opts.msvs_version = '2017';
71+
process.env['vs2017_install'] = vsSetup.InstallationPath;
72+
if (vsSetup.SDK) process.env['vs2017_sdk'] = vsSetup.SDK.replace(/\d+$/, '0')
73+
callback();
13874
}

0 commit comments

Comments
 (0)