Skip to content

Commit db63f3c

Browse files
bzozrefack
authored andcommitted
Add support for Visual Studio 2017
Add support for building with Visual Studio 2017 # Conflicts: # lib/configure.js
1 parent 078a48c commit db63f3c

File tree

4 files changed

+337
-2
lines changed

4 files changed

+337
-2
lines changed

find_vs2017.py

+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
import re
2+
import sys
3+
import os
4+
from ctypes import *
5+
6+
root_dir = os.path.dirname(__file__)
7+
sys.path.insert(0, os.path.join(root_dir, 'comtypes'))
8+
9+
from comtypes import IUnknown
10+
from comtypes import GUID
11+
from comtypes import COMMETHOD
12+
from comtypes import BSTR
13+
from comtypes import DWORD
14+
from comtypes.safearray import _midlSAFEARRAY
15+
from comtypes.client import CreateObject
16+
17+
""" Find Visual Studio 2017 C/C++ compiler install location """
18+
19+
20+
class ISetupInstance(IUnknown):
21+
_iid_ = GUID('{B41463C3-8866-43B5-BC33-2B0676F7F42E}')
22+
_methods_ = [
23+
COMMETHOD([], HRESULT, 'GetInstanceId',
24+
( ['out'], POINTER(BSTR), 'pbstrInstanceId' ) ),
25+
COMMETHOD([], HRESULT, 'GetInstallDate',
26+
( ['out'], POINTER(c_ulonglong), 'pInstallDate') ),
27+
COMMETHOD([], HRESULT, 'GetInstallationName',
28+
( ['out'], POINTER(BSTR), 'pInstallationName') ),
29+
COMMETHOD([], HRESULT, 'GetInstallationPath',
30+
( ['out'], POINTER(BSTR), 'pInstallationPath') ),
31+
COMMETHOD([], HRESULT, 'GetInstallationVersion',
32+
( ['out'], POINTER(BSTR), 'pInstallationVersion') ),
33+
COMMETHOD([], HRESULT, 'GetDisplayName',
34+
( ['in'], DWORD, 'lcid' ),
35+
( ['out'], POINTER(BSTR), 'pDisplayName') ),
36+
COMMETHOD([], HRESULT, 'GetDescription',
37+
( ['in'], DWORD, 'lcid' ),
38+
( ['out'], POINTER(BSTR), 'pDescription') ),
39+
COMMETHOD([], HRESULT, 'ResolvePath',
40+
( ['in'], c_wchar_p, 'pRelativePath' ),
41+
( ['out'], POINTER(BSTR), 'pAbsolutePath') ),
42+
]
43+
44+
class ISetupPackageReference(IUnknown):
45+
_iid_ = GUID('{da8d8a16-b2b6-4487-a2f1-594ccccd6bf5}')
46+
_methods_ = [
47+
COMMETHOD([], HRESULT, 'GetId',
48+
( ['out'], POINTER(BSTR), 'pOut' ) ),
49+
COMMETHOD([], HRESULT, 'GetVersion',
50+
( ['out'], POINTER(BSTR), 'pOut' ) ),
51+
COMMETHOD([], HRESULT, 'GetChip',
52+
( ['out'], POINTER(BSTR), 'pOut' ) ),
53+
COMMETHOD([], HRESULT, 'GetLanguage',
54+
( ['out'], POINTER(BSTR), 'pOut' ) ),
55+
COMMETHOD([], HRESULT, 'GetBranch',
56+
( ['out'], POINTER(BSTR), 'pOut' ) ),
57+
COMMETHOD([], HRESULT, 'GetType',
58+
( ['out'], POINTER(BSTR), 'pOut' ) ),
59+
COMMETHOD([], HRESULT, 'GetUniqueId',
60+
( ['out'], POINTER(BSTR), 'pOut' ) )
61+
]
62+
63+
class ISetupInstance2(ISetupInstance):
64+
_iid_ = GUID('{89143C9A-05AF-49B0-B717-72E218A2185C}')
65+
_methods_ = [
66+
COMMETHOD([], HRESULT, 'GetState',
67+
( ['out'], POINTER(DWORD), 'pState' ) ),
68+
COMMETHOD([], HRESULT, 'GetPackages',
69+
( ['out'], POINTER(_midlSAFEARRAY(POINTER(ISetupPackageReference))), 'ppPackage' ) )
70+
]
71+
72+
class IEnumSetupInstances(IUnknown):
73+
_iid_ = GUID('{6380BCFF-41D3-4B2E-8B2E-BF8A6810C848}')
74+
_methods_ = [
75+
COMMETHOD([], HRESULT, 'Next',
76+
( ['in'], c_ulong, 'celt'),
77+
( ['out'], POINTER(POINTER(ISetupInstance)), 'rgelt' ),
78+
( ['out'], POINTER(c_ulong), 'pceltFetched' ) ),
79+
COMMETHOD([], HRESULT, 'Skip',
80+
( ['in'], c_ulong, 'celt' ) ),
81+
COMMETHOD([], HRESULT, 'Reset'),
82+
]
83+
84+
class ISetupConfiguration(IUnknown):
85+
_iid_ = GUID('{42843719-DB4C-46C2-8E7C-64F1816EFD5B}')
86+
_methods_ = [
87+
COMMETHOD([], HRESULT, 'EnumInstances',
88+
( ['out'], POINTER(POINTER(IEnumSetupInstances)), 'ppIESI' ) ),
89+
COMMETHOD([], HRESULT, 'GetInstanceForCurrentProcess',
90+
( ['out'], POINTER(POINTER(ISetupInstance)), 'ppISI' ) ),
91+
COMMETHOD([], HRESULT, 'GetInstanceForPath',
92+
( ['in'], c_wchar_p, 'wzPath'),
93+
( ['out'], POINTER(POINTER(ISetupInstance)), 'ppISI' ) )
94+
]
95+
96+
class ISetupConfiguration2(ISetupConfiguration) :
97+
_iid_ = GUID('{26AAB78C-4A60-49D6-AF3B-3C35BC93365D}')
98+
_methods_ = [
99+
COMMETHOD([], HRESULT, 'EnumAllInstances',
100+
( ['out'], POINTER(POINTER(IEnumSetupInstances)), 'ppIEnumSetupInstances' ) )
101+
]
102+
103+
104+
def GetVS2017CPPBasePath():
105+
installs = []
106+
iface = CreateObject(GUID('{177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D}'))
107+
setupConfiguration = iface.QueryInterface(ISetupConfiguration2)
108+
allInstances = setupConfiguration.EnumAllInstances()
109+
while True:
110+
result = allInstances.Next(1)
111+
instance = result[0]
112+
if not instance:
113+
break
114+
path = instance.GetInstallationPath()
115+
version = instance.GetInstallationVersion()
116+
instance2 = instance.QueryInterface(ISetupInstance2)
117+
packages = instance2.GetPackages()
118+
for package in packages:
119+
packageId = package.GetId()
120+
if packageId == 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64':
121+
installs.append(path)
122+
return installs
123+
124+
def GetInstalledVS2017WinSDKs(vs_path):
125+
sdks = []
126+
has81sdk = False
127+
win8preg = re.compile(r"Microsoft.VisualStudio.Component.Windows81SDK")
128+
win10preg = re.compile(r"Microsoft.VisualStudio.Component.Windows10SDK.(\d+)")
129+
iface = CreateObject(GUID('{177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D}'))
130+
setupConfiguration = iface.QueryInterface(ISetupConfiguration2)
131+
allInstances = setupConfiguration.EnumAllInstances()
132+
while True:
133+
result = allInstances.Next(1)
134+
instance = result[0]
135+
if not instance:
136+
break
137+
path = instance.GetInstallationPath()
138+
if path != vs_path:
139+
continue
140+
instance2 = instance.QueryInterface(ISetupInstance2)
141+
packages = instance2.GetPackages()
142+
for package in packages:
143+
packageId = package.GetId()
144+
if win8preg.match(packageId):
145+
has81sdk = True
146+
else:
147+
win10match = win10preg.match(packageId)
148+
if win10match:
149+
sdks.append('10.0.' + str(win10match.group(1)) + '.0')
150+
151+
sdks.sort(reverse = True)
152+
if has81sdk:
153+
sdks.append('8.1')
154+
return sdks
155+
156+
def main():
157+
if len(sys.argv) == 1:
158+
installs = GetVS2017CPPBasePath()
159+
if len(installs) == 0:
160+
return
161+
for install in installs:
162+
sdks = GetInstalledVS2017WinSDKs(install)
163+
if len(sdks) > 0:
164+
print install
165+
return
166+
print installs[0]
167+
else:
168+
sdks = GetInstalledVS2017WinSDKs(sys.argv[1])
169+
if len(sdks) > 0:
170+
print sdks[0]
171+
172+
if __name__ == '__main__':
173+
main()

lib/build.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var fs = require('graceful-fs')
1515
, exec = require('child_process').exec
1616
, processRelease = require('./process-release')
1717
, win = process.platform == 'win32'
18+
, findVS = require('./find-vs2017')
1819

1920
exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module'
2021

@@ -107,7 +108,7 @@ function build (gyp, argv, callback) {
107108
if (err) {
108109
if (win && /not found/.test(err.message)) {
109110
// On windows and no 'msbuild' found. Let's guess where it is
110-
findMsbuild()
111+
findMsbuild15()
111112
} else {
112113
// Some other error or 'make' not found on Unix, report that to the user
113114
callback(err)
@@ -122,6 +123,20 @@ function build (gyp, argv, callback) {
122123
/**
123124
* Search for the location of "msbuild.exe" file on Windows.
124125
*/
126+
function findMsbuild15() {
127+
log.verbose('looking for VS2017 msbuild')
128+
findVS.locateMsbuild(gyp, function(err, msbuild_path) {
129+
if (err) {
130+
return callback(err)
131+
}
132+
if (msbuild_path) {
133+
command = msbuild_path
134+
copyNodeLib()
135+
} else {
136+
findMsbuild()
137+
}
138+
})
139+
}
125140

126141
function findMsbuild () {
127142
log.verbose('could not find "msbuild.exe" in PATH - finding location in registry')

lib/configure.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ var fs = require('graceful-fs')
2222
, win = process.platform == 'win32'
2323
, findNodeDirectory = require('./find-node-directory')
2424
, msgFormat = require('util').format
25+
, findVS = require('./find-vs2017')
2526

2627
exports.usage = 'Generates ' + (win ? 'MSVC project files' : 'a Makefile') + ' for the current module'
2728

@@ -39,10 +40,18 @@ function configure (gyp, argv, callback) {
3940
callback(err)
4041
} else {
4142
python = found
42-
getNodeDir()
43+
findVisualStudio2017()
4344
}
4445
})
4546

47+
function findVisualStudio2017() {
48+
if (win) {
49+
findVS.setGypVS2017Env(gyp, getNodeDir)
50+
} else {
51+
getNodeDir()
52+
}
53+
}
54+
4655
function getNodeDir () {
4756

4857
// 'python' should be set by now

lib/find-vs2017.js

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
module.exports = {
2+
locateMsbuild: locateMsbuild,
3+
locateVS2017: locateVS2017,
4+
getVS2017WinSDKVersion: getVS2017WinSDKVersion,
5+
setGypVS2017Env: setGypVS2017Env
6+
}
7+
8+
var log = require('npmlog')
9+
, fs = require('fs')
10+
, path = require('path')
11+
, cp = require('child_process')
12+
, win = process.platform == 'win32'
13+
, msgFormat = require('util').format
14+
, findPython = require('./find-python')
15+
16+
var vs2017_install_path
17+
, vs2017_win_sdk_ver
18+
19+
function run_locate(gyp, callback) {
20+
if (!win) {
21+
return callback(null, '', '')
22+
}
23+
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+
})
55+
}
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+
})
73+
}
74+
75+
}
76+
77+
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+
}
93+
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+
}
101+
})
102+
}
103+
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+
}
113+
114+
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+
}
128+
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+
}
138+
}

0 commit comments

Comments
 (0)