mirror of
https://github.com/electron/node-gyp.git
synced 2025-09-15 13:43:40 +02:00
win: find and setup for VS2017
PR-URL: https://github.com/nodejs/node-gyp/pull/1130 Reviewed-By: João Reis <reis@janeasystems.com> Reviewed-By: Bartosz Sosnowski <bartosz@janeasystems.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Rod Vagg <rod@vagg.org>
This commit is contained in:
parent
ec5fc36a80
commit
ae141e1906
4 changed files with 353 additions and 6 deletions
268
lib/Find-VS2017.cs
Normal file
268
lib/Find-VS2017.cs
Normal file
|
@ -0,0 +1,268 @@
|
||||||
|
// Copyright 2017 - Refael Ackermann
|
||||||
|
// Distributed under MIT style license
|
||||||
|
// See accompanying file LICENSE at https://github.com/node4good/windows-autoconf
|
||||||
|
|
||||||
|
// Usage:
|
||||||
|
// powershell -ExecutionPolicy Unrestricted -Version "2.0" -Command "&{Add-Type -Path Find-VS2017.cs; [VisualStudioConfiguration.Main]::Query()}"
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace VisualStudioConfiguration
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum InstanceState : uint
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Local = 1,
|
||||||
|
Registered = 2,
|
||||||
|
NoRebootRequired = 4,
|
||||||
|
NoErrors = 8,
|
||||||
|
Complete = 4294967295,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848")]
|
||||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
[ComImport]
|
||||||
|
public interface IEnumSetupInstances
|
||||||
|
{
|
||||||
|
|
||||||
|
void Next([MarshalAs(UnmanagedType.U4), In] int celt,
|
||||||
|
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Interface), Out] ISetupInstance[] rgelt,
|
||||||
|
[MarshalAs(UnmanagedType.U4)] out int pceltFetched);
|
||||||
|
|
||||||
|
void Skip([MarshalAs(UnmanagedType.U4), In] int celt);
|
||||||
|
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.Interface)]
|
||||||
|
IEnumSetupInstances Clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("42843719-DB4C-46C2-8E7C-64F1816EFD5B")]
|
||||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
[ComImport]
|
||||||
|
public interface ISetupConfiguration
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("26AAB78C-4A60-49D6-AF3B-3C35BC93365D")]
|
||||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
[ComImport]
|
||||||
|
public interface ISetupConfiguration2 : ISetupConfiguration
|
||||||
|
{
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.Interface)]
|
||||||
|
IEnumSetupInstances EnumInstances();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.Interface)]
|
||||||
|
ISetupInstance GetInstanceForCurrentProcess();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.Interface)]
|
||||||
|
ISetupInstance GetInstanceForPath([MarshalAs(UnmanagedType.LPWStr), In] string path);
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.Interface)]
|
||||||
|
IEnumSetupInstances EnumAllInstances();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("B41463C3-8866-43B5-BC33-2B0676F7F42E")]
|
||||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
[ComImport]
|
||||||
|
public interface ISetupInstance
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("89143C9A-05AF-49B0-B717-72E218A2185C")]
|
||||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
[ComImport]
|
||||||
|
public interface ISetupInstance2 : ISetupInstance
|
||||||
|
{
|
||||||
|
[return: MarshalAs(UnmanagedType.BStr)]
|
||||||
|
string GetInstanceId();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.Struct)]
|
||||||
|
System.Runtime.InteropServices.ComTypes.FILETIME GetInstallDate();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.BStr)]
|
||||||
|
string GetInstallationName();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.BStr)]
|
||||||
|
string GetInstallationPath();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.BStr)]
|
||||||
|
string GetInstallationVersion();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.BStr)]
|
||||||
|
string GetDisplayName([MarshalAs(UnmanagedType.U4), In] int lcid);
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.BStr)]
|
||||||
|
string GetDescription([MarshalAs(UnmanagedType.U4), In] int lcid);
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.BStr)]
|
||||||
|
string ResolvePath([MarshalAs(UnmanagedType.LPWStr), In] string pwszRelativePath);
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.U4)]
|
||||||
|
InstanceState GetState();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)]
|
||||||
|
ISetupPackageReference[] GetPackages();
|
||||||
|
|
||||||
|
ISetupPackageReference GetProduct();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.BStr)]
|
||||||
|
string GetProductPath();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.VariantBool)]
|
||||||
|
bool IsLaunchable();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.VariantBool)]
|
||||||
|
bool IsComplete();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)]
|
||||||
|
ISetupPropertyStore GetProperties();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.BStr)]
|
||||||
|
string GetEnginePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("DA8D8A16-B2B6-4487-A2F1-594CCCCD6BF5")]
|
||||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
[ComImport]
|
||||||
|
public interface ISetupPackageReference
|
||||||
|
{
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.BStr)]
|
||||||
|
string GetId();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.BStr)]
|
||||||
|
string GetVersion();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.BStr)]
|
||||||
|
string GetChip();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.BStr)]
|
||||||
|
string GetLanguage();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.BStr)]
|
||||||
|
string GetBranch();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.BStr)]
|
||||||
|
string GetType();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.BStr)]
|
||||||
|
string GetUniqueId();
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.VariantBool)]
|
||||||
|
bool GetIsExtension();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("c601c175-a3be-44bc-91f6-4568d230fc83")]
|
||||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
[ComImport]
|
||||||
|
public interface ISetupPropertyStore
|
||||||
|
{
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
|
||||||
|
string[] GetNames();
|
||||||
|
|
||||||
|
object GetValue([MarshalAs(UnmanagedType.LPWStr), In] string pwszName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("42843719-DB4C-46C2-8E7C-64F1816EFD5B")]
|
||||||
|
[CoClass(typeof(SetupConfigurationClass))]
|
||||||
|
[ComImport]
|
||||||
|
public interface SetupConfiguration : ISetupConfiguration2, ISetupConfiguration
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D")]
|
||||||
|
[ClassInterface(ClassInterfaceType.None)]
|
||||||
|
[ComImport]
|
||||||
|
public class SetupConfigurationClass
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Main
|
||||||
|
{
|
||||||
|
public static void Query()
|
||||||
|
{
|
||||||
|
ISetupConfiguration query = new SetupConfiguration();
|
||||||
|
ISetupConfiguration2 query2 = (ISetupConfiguration2)query;
|
||||||
|
IEnumSetupInstances e = query2.EnumAllInstances();
|
||||||
|
|
||||||
|
int pceltFetched;
|
||||||
|
ISetupInstance2[] rgelt = new ISetupInstance2[1];
|
||||||
|
StringBuilder log = new StringBuilder();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
e.Next(1, rgelt, out pceltFetched);
|
||||||
|
if (pceltFetched <= 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine(String.Format("{{\"log\":\"{0}\"}}", log.ToString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (CheckInstance(rgelt[0], ref log))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool CheckInstance(ISetupInstance2 setupInstance2, ref StringBuilder log)
|
||||||
|
{
|
||||||
|
// Visual Studio Community 2017 component directory:
|
||||||
|
// https://www.visualstudio.com/en-us/productinfo/vs2017-install-product-Community.workloads
|
||||||
|
|
||||||
|
string path = setupInstance2.GetInstallationPath().Replace("\\", "\\\\");
|
||||||
|
log.Append(String.Format("Found installation at: {0}\\n", path));
|
||||||
|
|
||||||
|
bool hasMSBuild = false;
|
||||||
|
bool hasVCTools = false;
|
||||||
|
uint Win10SDKVer = 0;
|
||||||
|
bool hasWin8SDK = false;
|
||||||
|
|
||||||
|
foreach (ISetupPackageReference package in setupInstance2.GetPackages())
|
||||||
|
{
|
||||||
|
const string Win10SDKPrefix = "Microsoft.VisualStudio.Component.Windows10SDK.";
|
||||||
|
|
||||||
|
string id = package.GetId();
|
||||||
|
if (id == "Microsoft.VisualStudio.VC.MSBuild.Base")
|
||||||
|
hasMSBuild = true;
|
||||||
|
else if (id == "Microsoft.VisualStudio.Component.VC.Tools.x86.x64")
|
||||||
|
hasVCTools = true;
|
||||||
|
else if (id.StartsWith(Win10SDKPrefix))
|
||||||
|
Win10SDKVer = Math.Max(Win10SDKVer, UInt32.Parse(id.Substring(Win10SDKPrefix.Length)));
|
||||||
|
else if (id == "Microsoft.VisualStudio.Component.Windows81SDK")
|
||||||
|
hasWin8SDK = true;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
log.Append(String.Format(" - Found {0}\\n", id));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasMSBuild)
|
||||||
|
log.Append(" - Missing Visual Studio C++ core features (Microsoft.VisualStudio.VC.MSBuild.Base)\\n");
|
||||||
|
if (!hasVCTools)
|
||||||
|
log.Append(" - Missing VC++ 2017 v141 toolset (x86,x64) (Microsoft.VisualStudio.Component.VC.Tools.x86.x64)\\n");
|
||||||
|
if ((Win10SDKVer == 0) && (!hasWin8SDK))
|
||||||
|
log.Append(" - Missing a Windows SDK (Microsoft.VisualStudio.Component.Windows10SDK.* or Microsoft.VisualStudio.Component.Windows81SDK)\\n");
|
||||||
|
|
||||||
|
if (hasMSBuild && hasVCTools)
|
||||||
|
{
|
||||||
|
if (Win10SDKVer > 0)
|
||||||
|
{
|
||||||
|
log.Append(" - Using this installation with Windows 10 SDK"/*\\n*/);
|
||||||
|
Console.WriteLine(String.Format("{{\"log\":\"{0}\",\"path\":\"{1}\",\"sdk\":\"10.0.{2}.0\"}}", log.ToString(), path, Win10SDKVer));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (hasWin8SDK)
|
||||||
|
{
|
||||||
|
log.Append(" - Using this installation with Windows 8.1 SDK"/*\\n*/);
|
||||||
|
Console.WriteLine(String.Format("{{\"log\":\"{0}\",\"path\":\"{1}\",\"sdk\":\"8.1\"}}", log.ToString(), path));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Append(" - Some required components are missing, not using this installation\\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ var fs = require('graceful-fs')
|
||||||
, mkdirp = require('mkdirp')
|
, mkdirp = require('mkdirp')
|
||||||
, exec = require('child_process').exec
|
, exec = require('child_process').exec
|
||||||
, processRelease = require('./process-release')
|
, processRelease = require('./process-release')
|
||||||
, win = process.platform == 'win32'
|
, win = process.platform === 'win32'
|
||||||
|
|
||||||
exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module'
|
exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module'
|
||||||
|
|
||||||
|
@ -124,6 +124,13 @@ function build (gyp, argv, callback) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function findMsbuild () {
|
function findMsbuild () {
|
||||||
|
if (config.variables.msbuild_path) {
|
||||||
|
command = config.variables.msbuild_path
|
||||||
|
log.verbose('using MSBuild:', command)
|
||||||
|
copyNodeLib()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
log.verbose('could not find "msbuild.exe" in PATH - finding location in registry')
|
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 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'
|
var cmd = 'reg query "HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions" /s'
|
||||||
|
|
|
@ -19,9 +19,11 @@ var fs = require('graceful-fs')
|
||||||
, cp = require('child_process')
|
, cp = require('child_process')
|
||||||
, extend = require('util')._extend
|
, extend = require('util')._extend
|
||||||
, processRelease = require('./process-release')
|
, processRelease = require('./process-release')
|
||||||
, win = process.platform == 'win32'
|
, win = process.platform === 'win32'
|
||||||
, findNodeDirectory = require('./find-node-directory')
|
, findNodeDirectory = require('./find-node-directory')
|
||||||
, msgFormat = require('util').format
|
, msgFormat = require('util').format
|
||||||
|
if (win)
|
||||||
|
var findVS2017 = require('./find-vs2017')
|
||||||
|
|
||||||
exports.usage = 'Generates ' + (win ? 'MSVC project files' : 'a Makefile') + ' for the current module'
|
exports.usage = 'Generates ' + (win ? 'MSVC project files' : 'a Makefile') + ' for the current module'
|
||||||
|
|
||||||
|
@ -86,11 +88,22 @@ function configure (gyp, argv, callback) {
|
||||||
mkdirp(buildDir, function (err, isNew) {
|
mkdirp(buildDir, function (err, isNew) {
|
||||||
if (err) return callback(err)
|
if (err) return callback(err)
|
||||||
log.verbose('build dir', '"build" dir needed to be created?', isNew)
|
log.verbose('build dir', '"build" dir needed to be created?', isNew)
|
||||||
createConfigFile()
|
if (win && (!gyp.opts.msvs_version || gyp.opts.msvs_version === '2017')) {
|
||||||
|
findVS2017(function (err, vsSetup) {
|
||||||
|
if (err) {
|
||||||
|
log.verbose('Not using VS2017:', err.message)
|
||||||
|
createConfigFile()
|
||||||
|
} else {
|
||||||
|
createConfigFile(null, vsSetup)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
createConfigFile()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function createConfigFile (err) {
|
function createConfigFile (err, vsSetup) {
|
||||||
if (err) return callback(err)
|
if (err) return callback(err)
|
||||||
|
|
||||||
var configFilename = 'config.gypi'
|
var configFilename = 'config.gypi'
|
||||||
|
@ -137,6 +150,19 @@ function configure (gyp, argv, callback) {
|
||||||
// disable -T "thin" static archives by default
|
// disable -T "thin" static archives by default
|
||||||
variables.standalone_static_library = gyp.opts.thin ? 0 : 1
|
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')
|
||||||
|
}
|
||||||
|
|
||||||
// loop through the rest of the opts and add the unknown ones as variables.
|
// loop through the rest of the opts and add the unknown ones as variables.
|
||||||
// this allows for module-specific configure flags like:
|
// this allows for module-specific configure flags like:
|
||||||
//
|
//
|
||||||
|
|
46
lib/find-vs2017.js
Normal file
46
lib/find-vs2017.js
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
var log = require('npmlog')
|
||||||
|
, execFile = require('child_process').execFile
|
||||||
|
, path = require('path')
|
||||||
|
|
||||||
|
function findVS2017(callback) {
|
||||||
|
var ps = path.join(process.env.SystemRoot, 'System32', 'WindowsPowerShell',
|
||||||
|
'v1.0', 'powershell.exe')
|
||||||
|
var csFile = path.join(__dirname, 'Find-VS2017.cs')
|
||||||
|
var psArgs = ['-ExecutionPolicy', 'Unrestricted', '-Command',
|
||||||
|
'&{Add-Type -Path \'' + csFile +
|
||||||
|
'\'; [VisualStudioConfiguration.Main]::Query()}']
|
||||||
|
|
||||||
|
log.silly('find vs2017', 'Running', ps, psArgs)
|
||||||
|
var child = execFile(ps, psArgs, { encoding: 'utf8' },
|
||||||
|
function (err, stdout, stderr) {
|
||||||
|
log.silly('find vs2017', 'PS err:', err)
|
||||||
|
log.silly('find vs2017', 'PS stdout:', stdout)
|
||||||
|
log.silly('find vs2017', 'PS stderr:', stderr)
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
return callback(new Error('Could not use PowerShell to find VS2017'))
|
||||||
|
|
||||||
|
var vsSetup
|
||||||
|
try {
|
||||||
|
vsSetup = JSON.parse(stdout)
|
||||||
|
} catch (e) {
|
||||||
|
log.silly('find vs2017', e)
|
||||||
|
return callback(new Error('Could not use PowerShell to find VS2017'))
|
||||||
|
}
|
||||||
|
log.silly('find vs2017', 'vsSetup:', vsSetup)
|
||||||
|
|
||||||
|
if (vsSetup && vsSetup.log)
|
||||||
|
log.verbose('find vs2017', vsSetup.log.trimRight())
|
||||||
|
|
||||||
|
if (!vsSetup || !vsSetup.path || !vsSetup.sdk) {
|
||||||
|
return callback(new Error('No usable installation of VS2017 found'))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.verbose('find vs2017', 'using installation:', vsSetup.path)
|
||||||
|
callback(null, { "path": vsSetup.path, "sdk": vsSetup.sdk })
|
||||||
|
})
|
||||||
|
|
||||||
|
child.stdin.end()
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = findVS2017
|
Loading…
Add table
Add a link
Reference in a new issue