Skip to content

Commit

Permalink
Add support for Visual Studio 2017
Browse files Browse the repository at this point in the history
Add support for building with Visual Studio 2017

# Conflicts:
#	lib/configure.js
  • Loading branch information
bzoz authored and refack committed Feb 6, 2017
1 parent a387531 commit ae96a08
Show file tree
Hide file tree
Showing 4 changed files with 337 additions and 2 deletions.
173 changes: 173 additions & 0 deletions find_vs2017.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import re
import sys
import os
from ctypes import *

root_dir = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(root_dir, 'comtypes'))

from comtypes import IUnknown
from comtypes import GUID
from comtypes import COMMETHOD
from comtypes import BSTR
from comtypes import DWORD
from comtypes.safearray import _midlSAFEARRAY
from comtypes.client import CreateObject

""" Find Visual Studio 2017 C/C++ compiler install location """


class ISetupInstance(IUnknown):
_iid_ = GUID('{B41463C3-8866-43B5-BC33-2B0676F7F42E}')
_methods_ = [
COMMETHOD([], HRESULT, 'GetInstanceId',
( ['out'], POINTER(BSTR), 'pbstrInstanceId' ) ),
COMMETHOD([], HRESULT, 'GetInstallDate',
( ['out'], POINTER(c_ulonglong), 'pInstallDate') ),
COMMETHOD([], HRESULT, 'GetInstallationName',
( ['out'], POINTER(BSTR), 'pInstallationName') ),
COMMETHOD([], HRESULT, 'GetInstallationPath',
( ['out'], POINTER(BSTR), 'pInstallationPath') ),
COMMETHOD([], HRESULT, 'GetInstallationVersion',
( ['out'], POINTER(BSTR), 'pInstallationVersion') ),
COMMETHOD([], HRESULT, 'GetDisplayName',
( ['in'], DWORD, 'lcid' ),
( ['out'], POINTER(BSTR), 'pDisplayName') ),
COMMETHOD([], HRESULT, 'GetDescription',
( ['in'], DWORD, 'lcid' ),
( ['out'], POINTER(BSTR), 'pDescription') ),
COMMETHOD([], HRESULT, 'ResolvePath',
( ['in'], c_wchar_p, 'pRelativePath' ),
( ['out'], POINTER(BSTR), 'pAbsolutePath') ),
]

class ISetupPackageReference(IUnknown):
_iid_ = GUID('{da8d8a16-b2b6-4487-a2f1-594ccccd6bf5}')
_methods_ = [
COMMETHOD([], HRESULT, 'GetId',
( ['out'], POINTER(BSTR), 'pOut' ) ),
COMMETHOD([], HRESULT, 'GetVersion',
( ['out'], POINTER(BSTR), 'pOut' ) ),
COMMETHOD([], HRESULT, 'GetChip',
( ['out'], POINTER(BSTR), 'pOut' ) ),
COMMETHOD([], HRESULT, 'GetLanguage',
( ['out'], POINTER(BSTR), 'pOut' ) ),
COMMETHOD([], HRESULT, 'GetBranch',
( ['out'], POINTER(BSTR), 'pOut' ) ),
COMMETHOD([], HRESULT, 'GetType',
( ['out'], POINTER(BSTR), 'pOut' ) ),
COMMETHOD([], HRESULT, 'GetUniqueId',
( ['out'], POINTER(BSTR), 'pOut' ) )
]

class ISetupInstance2(ISetupInstance):
_iid_ = GUID('{89143C9A-05AF-49B0-B717-72E218A2185C}')
_methods_ = [
COMMETHOD([], HRESULT, 'GetState',
( ['out'], POINTER(DWORD), 'pState' ) ),
COMMETHOD([], HRESULT, 'GetPackages',
( ['out'], POINTER(_midlSAFEARRAY(POINTER(ISetupPackageReference))), 'ppPackage' ) )
]

class IEnumSetupInstances(IUnknown):
_iid_ = GUID('{6380BCFF-41D3-4B2E-8B2E-BF8A6810C848}')
_methods_ = [
COMMETHOD([], HRESULT, 'Next',
( ['in'], c_ulong, 'celt'),
( ['out'], POINTER(POINTER(ISetupInstance)), 'rgelt' ),
( ['out'], POINTER(c_ulong), 'pceltFetched' ) ),
COMMETHOD([], HRESULT, 'Skip',
( ['in'], c_ulong, 'celt' ) ),
COMMETHOD([], HRESULT, 'Reset'),
]

class ISetupConfiguration(IUnknown):
_iid_ = GUID('{42843719-DB4C-46C2-8E7C-64F1816EFD5B}')
_methods_ = [
COMMETHOD([], HRESULT, 'EnumInstances',
( ['out'], POINTER(POINTER(IEnumSetupInstances)), 'ppIESI' ) ),
COMMETHOD([], HRESULT, 'GetInstanceForCurrentProcess',
( ['out'], POINTER(POINTER(ISetupInstance)), 'ppISI' ) ),
COMMETHOD([], HRESULT, 'GetInstanceForPath',
( ['in'], c_wchar_p, 'wzPath'),
( ['out'], POINTER(POINTER(ISetupInstance)), 'ppISI' ) )
]

class ISetupConfiguration2(ISetupConfiguration) :
_iid_ = GUID('{26AAB78C-4A60-49D6-AF3B-3C35BC93365D}')
_methods_ = [
COMMETHOD([], HRESULT, 'EnumAllInstances',
( ['out'], POINTER(POINTER(IEnumSetupInstances)), 'ppIEnumSetupInstances' ) )
]


def GetVS2017CPPBasePath():
installs = []
iface = CreateObject(GUID('{177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D}'))
setupConfiguration = iface.QueryInterface(ISetupConfiguration2)
allInstances = setupConfiguration.EnumAllInstances()
while True:
result = allInstances.Next(1)
instance = result[0]
if not instance:
break
path = instance.GetInstallationPath()
version = instance.GetInstallationVersion()
instance2 = instance.QueryInterface(ISetupInstance2)
packages = instance2.GetPackages()
for package in packages:
packageId = package.GetId()
if packageId == 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64':
installs.append(path)
return installs

def GetInstalledVS2017WinSDKs(vs_path):
sdks = []
has81sdk = False
win8preg = re.compile(r"Microsoft.VisualStudio.Component.Windows81SDK")
win10preg = re.compile(r"Microsoft.VisualStudio.Component.Windows10SDK.(\d+)")
iface = CreateObject(GUID('{177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D}'))
setupConfiguration = iface.QueryInterface(ISetupConfiguration2)
allInstances = setupConfiguration.EnumAllInstances()
while True:
result = allInstances.Next(1)
instance = result[0]
if not instance:
break
path = instance.GetInstallationPath()
if path != vs_path:
continue
instance2 = instance.QueryInterface(ISetupInstance2)
packages = instance2.GetPackages()
for package in packages:
packageId = package.GetId()
if win8preg.match(packageId):
has81sdk = True
else:
win10match = win10preg.match(packageId)
if win10match:
sdks.append('10.0.' + str(win10match.group(1)) + '.0')

sdks.sort(reverse = True)
if has81sdk:
sdks.append('8.1')
return sdks

def main():
if len(sys.argv) == 1:
installs = GetVS2017CPPBasePath()
if len(installs) == 0:
return
for install in installs:
sdks = GetInstalledVS2017WinSDKs(install)
if len(sdks) > 0:
print install
return
print installs[0]
else:
sdks = GetInstalledVS2017WinSDKs(sys.argv[1])
if len(sdks) > 0:
print sdks[0]

if __name__ == '__main__':
main()
17 changes: 16 additions & 1 deletion lib/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var fs = require('graceful-fs')
, exec = require('child_process').exec
, processRelease = require('./process-release')
, win = process.platform == 'win32'
, findVS = require('./find-vs2017')

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

Expand Down Expand Up @@ -107,7 +108,7 @@ function build (gyp, argv, callback) {
if (err) {
if (win && /not found/.test(err.message)) {
// On windows and no 'msbuild' found. Let's guess where it is
findMsbuild()
findMsbuild15()
} else {
// Some other error or 'make' not found on Unix, report that to the user
callback(err)
Expand All @@ -122,6 +123,20 @@ function build (gyp, argv, callback) {
/**
* Search for the location of "msbuild.exe" file on Windows.
*/
function findMsbuild15() {
log.verbose('looking for VS2017 msbuild')
findVS.locateMsbuild(gyp, function(err, msbuild_path) {
if (err) {
return callback(err)
}
if (msbuild_path) {
command = msbuild_path
copyNodeLib()
} else {
findMsbuild()
}
})
}

function findMsbuild () {
log.verbose('could not find "msbuild.exe" in PATH - finding location in registry')
Expand Down
11 changes: 10 additions & 1 deletion lib/configure.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var fs = require('graceful-fs')
, win = process.platform == 'win32'
, findNodeDirectory = require('./find-node-directory')
, msgFormat = require('util').format
, findVS = require('./find-vs2017')

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

Expand All @@ -39,10 +40,18 @@ function configure (gyp, argv, callback) {
callback(err)
} else {
python = found
getNodeDir()
findVisualStudio2017()
}
})

function findVisualStudio2017() {
if (win) {
findVS.setGypVS2017Env(gyp, getNodeDir)
} else {
getNodeDir()
}
}

function getNodeDir () {

// 'python' should be set by now
Expand Down
138 changes: 138 additions & 0 deletions lib/find-vs2017.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
module.exports = {
locateMsbuild: locateMsbuild,
locateVS2017: locateVS2017,
getVS2017WinSDKVersion: getVS2017WinSDKVersion,
setGypVS2017Env: setGypVS2017Env
}

var log = require('npmlog')
, fs = require('fs')
, path = require('path')
, cp = require('child_process')
, win = process.platform == 'win32'
, msgFormat = require('util').format
, findPython = require('./find-python')

var vs2017_install_path
, vs2017_win_sdk_ver

function run_locate(gyp, callback) {
if (!win) {
return callback(null, '', '')
}

if (vs2017_install_path || vs2017_install_path === '') {
return callback(null, vs2017_install_path, vs2017_win_sdk_ver)
}

var python = gyp.opts.python || process.env.PYTHON || 'python2'
, findvc_path = path.join(__dirname, '..', 'find_vs2017.py')

findPython(python, locate_vc);

function locate_vc(err, python_bin) {
if (err) {
return callback(err)
}

log.verbose('find vs2017', 'obtaining vs2017 install path using script %s',
findvc_path)
cp.execFile(python_bin, [findvc_path], function(err, stdout, stderr) {
if (err) {
return callback(err)
}
if (stdout) {
vs2017_install_path = stdout.split('\r\n')[0]
log.verbose('find vs2017', 'found Visual Studio 2017 in %s', vs2017_install_path)
get_sdk_version(python_bin)
} else {
log.verbose('find vs2017',
'no valid Visual Studio 2017 installation found')
vs2017_install_path = ''
vs2017_win_sdk_ver = ''
}
})
}

function get_sdk_version(python_bin) {
log.verbose('find vs2017', 'obtaining installed Windows SDKs')
cp.execFile(python_bin, [findvc_path, vs2017_install_path],
function(err, stdout, stderr) {
if (err) {
return callback(err)
}
if (stdout) {
vs2017_win_sdk_ver = stdout.split('\r\n')[0]
log.verbose('find vs2017', 'found VS2017 WinSDK %s', vs2017_win_sdk_ver)
} else {
log.verbose('find vs2017', 'no installed sdks found')
}

callback(null, vs2017_install_path, vs2017_win_sdk_ver)
})
}

}

function locateMsbuild(gyp, callback) {
run_locate(gyp, function(err, vs_path, sdk) {
if (err) {
return callback(err)
}
if (vs_path === '') {
return callback()
}
var msbuild_location = path.join(vs_path, 'MSBuild',
'15.0', 'Bin', 'MSBuild.exe')
log.verbose('find vs2017', 'looking for msbuild in %s', msbuild_location)
fs.access(msbuild_location, function(err) {
callback(null, err ? null : msbuild_location)
})
})
}

function locateVS2017(gyp, callback) {
run_locate(gyp, function(err, vs_path, sdk) {
if (err) {
callback(err)
} else {
callback(null, vs_path === '' ? null : vs_path)
}
})
}

function getVS2017WinSDKVersion(gyp, callback) {
run_locate(gyp, function(err, vs_path, sdk) {
if (err) {
callback(err)
} else {
callback(null, sdk === '' ? null : sdk)
}
})
}

function setGypVS2017Env(gyp, callback) {
locateVS2017(gyp, setPath)

function setPath(err, vs_path) {
if (err) {
return callback(err)
}
if (vs_path) {
process.env['vs2017_install'] = vs_path
getVS2017WinSDKVersion(gyp, setSDK)
} else {
callback()
}
}

function setSDK(err, sdk) {
if (err) {
return callback(err)
}
if (sdk) {
process.env['vs2017_sdk'] = sdk
}
callback()
}
}

0 comments on commit ae96a08

Please sign in to comment.