From 3b214de9a3b8c0e3da6a48685f3ae85ff812e86f Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Mon, 20 Feb 2017 19:16:24 -0500 Subject: [PATCH] win: find and setup for VS2017 --- lib/build.js | 24 +++- lib/configure.js | 27 ++++- tools/Get-VS7.cs | 240 +++++++++++++++++++++++++++++++++++++++ tools/try_powershell.cmd | 3 + 4 files changed, 290 insertions(+), 4 deletions(-) create mode 100644 tools/Get-VS7.cs create mode 100644 tools/try_powershell.cmd diff --git a/lib/build.js b/lib/build.js index 0374fbc810..c68180e699 100644 --- a/lib/build.js +++ b/lib/build.js @@ -12,9 +12,10 @@ var fs = require('graceful-fs') , log = require('npmlog') , which = require('which') , mkdirp = require('mkdirp') - , exec = require('child_process').exec + , cp = require('child_process') + , exec = cp.exec , processRelease = require('./process-release') - , win = process.platform == 'win32' + , win = process.platform === 'win32' exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module' @@ -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) @@ -122,6 +123,23 @@ function build (gyp, argv, callback) { /** * Search for the location of "msbuild.exe" file on Windows. */ + function findMsbuild15() { + log.verbose('looking for VS2017 msbuild') + try { + var cmdPath = '"' + __dirname + '\\..\\tools\\try_powershell.cmd"' + var vsSetupRaw = cp.execSync(cmdPath).toString() + var vsSetup = JSON.parse(vsSetupRaw)[0] + var msbuild_path = vsSetup.InstallationPath + '\\MSBuild\\15.0\\Bin\\MSBuild.exe' + } catch (_) { + log.verbose('failed looking for VS2017 msbuild') + } + if (msbuild_path) { + command = msbuild_path + copyNodeLib() + } else { + findMsbuild() + } + } function findMsbuild () { log.verbose('could not find "msbuild.exe" in PATH - finding location in registry') diff --git a/lib/configure.js b/lib/configure.js index d52b2902b0..0f6f7bd6d7 100644 --- a/lib/configure.js +++ b/lib/configure.js @@ -19,7 +19,7 @@ var fs = require('graceful-fs') , cp = require('child_process') , extend = require('util')._extend , processRelease = require('./process-release') - , win = process.platform == 'win32' + , win = process.platform === 'win32' , findNodeDirectory = require('./find-node-directory') , msgFormat = require('util').format @@ -90,6 +90,28 @@ function configure (gyp, argv, callback) { }) } + function findVisualStudio2017 (config) { + if (gyp.opts.msvs_version && gyp.opts.msvs_version !== '2017') + return + + try { + log.verbose('looking for VS2017') + var cmdPath = '"' + __dirname + '\\..\\tools\\try_powershell.cmd"' + var vsSetupRaw = cp.execSync(cmdPath).toString() + if (!vsSetupRaw) return + var vsSetup = JSON.parse(vsSetupRaw)[0] + } catch (_) { + log.verbose('failed looking for VS2017') + return + } + + gyp.opts.msvs_version = '2015' + process.env['GYP_MSVS_VERSION'] = 2015 + process.env['GYP_MSVS_OVERRIDE_PATH'] = vsSetup.InstallationPath + config['msbuild_toolset'] = 'v141' + config['msvs_windows_target_platform_version'] = vsSetup.SDK + } + function createConfigFile (err) { if (err) return callback(err) @@ -137,6 +159,9 @@ function configure (gyp, argv, callback) { // disable -T "thin" static archives by default variables.standalone_static_library = gyp.opts.thin ? 0 : 1 + if (win) + findVisualStudio2017(defaults) + // loop through the rest of the opts and add the unknown ones as variables. // this allows for module-specific configure flags like: // diff --git a/tools/Get-VS7.cs b/tools/Get-VS7.cs new file mode 100644 index 0000000000..8c0bc6eb0d --- /dev/null +++ b/tools/Get-VS7.cs @@ -0,0 +1,240 @@ +// powershell -ExecutionPolicy Unrestricted -Version "2.0" -Command "&{ Add-Type -Path Program.cs; [VisualStudioConfiguration.Program]::Main(@())}" +using System; +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(); + + 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(); + ISetupInstance2[] rgelt = new ISetupInstance2[1]; + int pceltFetched; + Console.Write("["); + e.Next(1, rgelt, out pceltFetched); + while (pceltFetched > 0) + { + PrintInstance(rgelt[0]); + e.Next(1, rgelt, out pceltFetched); + if (pceltFetched > 0) + Console.Write(","); + } + Console.Write("]"); + } + + private static void PrintInstance(ISetupInstance2 setupInstance2) + { + Console.Write("{\n"); + string[] prodParts = setupInstance2.GetProduct().GetId().Split('.'); + Array.Reverse(prodParts); + string prod = prodParts[0]; + string instPath = setupInstance2.GetInstallationPath().Replace("\\", "\\\\"); + Console.Write(String.Format("\"Product\": \"{0}\",\n", prod)); + Console.Write(String.Format("\"InstallationPath\": \"{0}\",\n", instPath)); + Console.Write(String.Format("\"Version\": \"{0}\",\n", setupInstance2.GetInstallationVersion())); + foreach (ISetupPackageReference package in setupInstance2.GetPackages()) + { + if (package.GetType() != "Exe") continue; + string id = package.GetId(); + if (id.IndexOf("SDK", StringComparison.Ordinal) == -1) continue; + string[] parts = id.Split('_'); + if (parts.Length < 2) continue; + string sdkVer = parts[1]; + char[] chars = {'1', '0', '8'}; + if (sdkVer.IndexOfAny(chars) == -1) continue; + Console.Write(String.Format("\"SDKFull\": \"{0}\",\n", sdkVer)); + string[] sdkParts = sdkVer.Split('.'); + sdkParts[sdkParts.Length - 1] = "0"; + Console.Write(String.Format("\"SDK\": \"{0}\",\n", String.Join(".", sdkParts))); + } + String cmd = (setupInstance2.GetInstallationPath() + "\\Common7\\Tools\\VsDevCmd.bat"); + cmd = cmd.Replace("\\", "\\\\"); + Console.Write(String.Format("\"CmdPath\": \"{0}\"\n", cmd)); + Console.Write("}"); + } + } + +} + +public static class Program +{ + public static int Main(string[] args) + { + VisualStudioConfiguration.Main.Query(); + return 0; + } +} diff --git a/tools/try_powershell.cmd b/tools/try_powershell.cmd new file mode 100644 index 0000000000..2ee41e0bf8 --- /dev/null +++ b/tools/try_powershell.cmd @@ -0,0 +1,3 @@ +@IF NOT DEFINED DEBUG_GETTER @echo off +SET CSFILE=%~dp0Get-VS7.cs +powershell -ExecutionPolicy Unrestricted -Command "&{ Add-Type -Path '%CSFILE%'; [VisualStudioConfiguration.Main]::Query()}"