Skip to content

Commit b25b8eb

Browse files
committed
win: find and setup for VS2017
1 parent ec5fc36 commit b25b8eb

File tree

4 files changed

+299
-6
lines changed

4 files changed

+299
-6
lines changed

lib/build.js

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ var fs = require('graceful-fs')
1212
, log = require('npmlog')
1313
, which = require('which')
1414
, mkdirp = require('mkdirp')
15-
, exec = require('child_process').exec
15+
, cp = require('child_process')
16+
, exec = cp.exec
1617
, processRelease = require('./process-release')
17-
, win = process.platform == 'win32'
18+
, win = process.platform === 'win32'
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,23 @@ 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+
try {
129+
var cmdPath = '"' + __dirname + '\\..\\tools\\try_powershell.cmd"'
130+
var vsSetupRaw = cp.execSync(cmdPath).toString()
131+
var vsSetup = JSON.parse(vsSetupRaw)[0]
132+
} catch (_) {
133+
log.verbose('failed looking for VS2017 msbuild')
134+
}
135+
if (vsSetup && vsSetup !== 'No COM' && vsSetup.InstallationPath) {
136+
command = vsSetup.InstallationPath + '\\MSBuild\\15.0\\Bin\\MSBuild.exe'
137+
copyNodeLib()
138+
} else {
139+
log.verbose('COM server not found')
140+
findMsbuild()
141+
}
142+
}
125143

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

lib/configure.js

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ var fs = require('graceful-fs')
1919
, cp = require('child_process')
2020
, extend = require('util')._extend
2121
, processRelease = require('./process-release')
22-
, win = process.platform == 'win32'
22+
, win = process.platform === 'win32'
2323
, findNodeDirectory = require('./find-node-directory')
2424
, msgFormat = require('util').format
2525

@@ -90,6 +90,33 @@ function configure (gyp, argv, callback) {
9090
})
9191
}
9292

93+
function findVisualStudio2017 (config) {
94+
if (gyp.opts.msvs_version && gyp.opts.msvs_version !== '2017')
95+
return
96+
97+
try {
98+
log.verbose('looking for VS2017')
99+
var cmdPath = '"' + __dirname + '\\..\\tools\\try_powershell.cmd"'
100+
var vsSetupRaw = cp.execSync(cmdPath).toString()
101+
if (!vsSetupRaw) return
102+
var vsSetup = JSON.parse(vsSetupRaw)[0]
103+
} catch (_) {
104+
log.verbose('failed looking for VS2017')
105+
return
106+
}
107+
108+
if (!vsSetup || vsSetup === "No COM") {
109+
log.verbose('COM server not found')
110+
return
111+
}
112+
113+
gyp.opts.msvs_version = '2015'
114+
process.env['GYP_MSVS_VERSION'] = 2015
115+
process.env['GYP_MSVS_OVERRIDE_PATH'] = vsSetup.InstallationPath
116+
config['msbuild_toolset'] = 'v141'
117+
config['msvs_windows_target_platform_version'] = vsSetup.SDK
118+
}
119+
93120
function createConfigFile (err) {
94121
if (err) return callback(err)
95122

@@ -137,6 +164,9 @@ function configure (gyp, argv, callback) {
137164
// disable -T "thin" static archives by default
138165
variables.standalone_static_library = gyp.opts.thin ? 0 : 1
139166

167+
if (win)
168+
findVisualStudio2017(defaults)
169+
140170
// loop through the rest of the opts and add the unknown ones as variables.
141171
// this allows for module-specific configure flags like:
142172
//
@@ -317,9 +347,9 @@ function configure (gyp, argv, callback) {
317347
}
318348

319349
/**
320-
* Returns the first file or directory from an array of candidates that is
350+
* Returns the first file or directory from an array of candidates that is
321351
* readable by the current user, or undefined if none of the candidates are
322-
* readable.
352+
* readable.
323353
*/
324354
function findAccessibleSync (logprefix, dir, candidates) {
325355
for (var next = 0; next < candidates.length; next++) {

tools/Get-VS7.cs

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
// powershell -ExecutionPolicy Unrestricted -Version "2.0" -Command "&{ Add-Type -Path Program.cs; [VisualStudioConfiguration.Program]::Main(@())}"
2+
using System;
3+
using System.Runtime.InteropServices;
4+
5+
namespace VisualStudioConfiguration
6+
{
7+
[Flags]
8+
public enum InstanceState : uint
9+
{
10+
None = 0,
11+
Local = 1,
12+
Registered = 2,
13+
NoRebootRequired = 4,
14+
NoErrors = 8,
15+
Complete = 4294967295,
16+
}
17+
18+
[Guid("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848")]
19+
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
20+
[ComImport]
21+
public interface IEnumSetupInstances
22+
{
23+
24+
void Next([MarshalAs(UnmanagedType.U4), In] int celt,
25+
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Interface), Out] ISetupInstance[] rgelt,
26+
[MarshalAs(UnmanagedType.U4)] out int pceltFetched);
27+
28+
void Skip([MarshalAs(UnmanagedType.U4), In] int celt);
29+
30+
void Reset();
31+
32+
[return: MarshalAs(UnmanagedType.Interface)]
33+
IEnumSetupInstances Clone();
34+
}
35+
36+
[Guid("42843719-DB4C-46C2-8E7C-64F1816EFD5B")]
37+
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
38+
[ComImport]
39+
public interface ISetupConfiguration
40+
{
41+
}
42+
43+
[Guid("26AAB78C-4A60-49D6-AF3B-3C35BC93365D")]
44+
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
45+
[ComImport]
46+
public interface ISetupConfiguration2 : ISetupConfiguration
47+
{
48+
49+
[return: MarshalAs(UnmanagedType.Interface)]
50+
IEnumSetupInstances EnumInstances();
51+
52+
[return: MarshalAs(UnmanagedType.Interface)]
53+
ISetupInstance GetInstanceForCurrentProcess();
54+
55+
[return: MarshalAs(UnmanagedType.Interface)]
56+
ISetupInstance GetInstanceForPath([MarshalAs(UnmanagedType.LPWStr), In] string path);
57+
58+
[return: MarshalAs(UnmanagedType.Interface)]
59+
IEnumSetupInstances EnumAllInstances();
60+
}
61+
62+
[Guid("B41463C3-8866-43B5-BC33-2B0676F7F42E")]
63+
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
64+
[ComImport]
65+
public interface ISetupInstance
66+
{
67+
}
68+
69+
[Guid("89143C9A-05AF-49B0-B717-72E218A2185C")]
70+
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
71+
[ComImport]
72+
public interface ISetupInstance2 : ISetupInstance
73+
{
74+
[return: MarshalAs(UnmanagedType.BStr)]
75+
string GetInstanceId();
76+
77+
[return: MarshalAs(UnmanagedType.Struct)]
78+
System.Runtime.InteropServices.ComTypes.FILETIME GetInstallDate();
79+
80+
[return: MarshalAs(UnmanagedType.BStr)]
81+
string GetInstallationName();
82+
83+
[return: MarshalAs(UnmanagedType.BStr)]
84+
string GetInstallationPath();
85+
86+
[return: MarshalAs(UnmanagedType.BStr)]
87+
string GetInstallationVersion();
88+
89+
[return: MarshalAs(UnmanagedType.BStr)]
90+
string GetDisplayName([MarshalAs(UnmanagedType.U4), In] int lcid);
91+
92+
[return: MarshalAs(UnmanagedType.BStr)]
93+
string GetDescription([MarshalAs(UnmanagedType.U4), In] int lcid);
94+
95+
[return: MarshalAs(UnmanagedType.BStr)]
96+
string ResolvePath([MarshalAs(UnmanagedType.LPWStr), In] string pwszRelativePath);
97+
98+
[return: MarshalAs(UnmanagedType.U4)]
99+
InstanceState GetState();
100+
101+
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)]
102+
ISetupPackageReference[] GetPackages();
103+
104+
ISetupPackageReference GetProduct();
105+
106+
[return: MarshalAs(UnmanagedType.BStr)]
107+
string GetProductPath();
108+
109+
[return: MarshalAs(UnmanagedType.VariantBool)]
110+
bool IsLaunchable();
111+
112+
[return: MarshalAs(UnmanagedType.VariantBool)]
113+
bool IsComplete();
114+
115+
ISetupPropertyStore GetProperties();
116+
117+
[return: MarshalAs(UnmanagedType.BStr)]
118+
string GetEnginePath();
119+
}
120+
121+
[Guid("DA8D8A16-B2B6-4487-A2F1-594CCCCD6BF5")]
122+
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
123+
[ComImport]
124+
public interface ISetupPackageReference
125+
{
126+
127+
[return: MarshalAs(UnmanagedType.BStr)]
128+
string GetId();
129+
130+
[return: MarshalAs(UnmanagedType.BStr)]
131+
string GetVersion();
132+
133+
[return: MarshalAs(UnmanagedType.BStr)]
134+
string GetChip();
135+
136+
[return: MarshalAs(UnmanagedType.BStr)]
137+
string GetLanguage();
138+
139+
[return: MarshalAs(UnmanagedType.BStr)]
140+
string GetBranch();
141+
142+
[return: MarshalAs(UnmanagedType.BStr)]
143+
string GetType();
144+
145+
[return: MarshalAs(UnmanagedType.BStr)]
146+
string GetUniqueId();
147+
148+
[return: MarshalAs(UnmanagedType.VariantBool)]
149+
bool GetIsExtension();
150+
}
151+
152+
[Guid("c601c175-a3be-44bc-91f6-4568d230fc83")]
153+
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
154+
[ComImport]
155+
public interface ISetupPropertyStore
156+
{
157+
158+
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
159+
string[] GetNames();
160+
161+
object GetValue([MarshalAs(UnmanagedType.LPWStr), In] string pwszName);
162+
}
163+
164+
[Guid("42843719-DB4C-46C2-8E7C-64F1816EFD5B")]
165+
[CoClass(typeof(SetupConfigurationClass))]
166+
[ComImport]
167+
public interface SetupConfiguration : ISetupConfiguration2, ISetupConfiguration
168+
{
169+
}
170+
171+
[Guid("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D")]
172+
[ClassInterface(ClassInterfaceType.None)]
173+
[ComImport]
174+
public class SetupConfigurationClass
175+
{
176+
}
177+
178+
public static class Main
179+
{
180+
public static void Query()
181+
{
182+
ISetupConfiguration query = new SetupConfiguration();
183+
ISetupConfiguration2 query2 = (ISetupConfiguration2) query;
184+
IEnumSetupInstances e = query2.EnumAllInstances();
185+
ISetupInstance2[] rgelt = new ISetupInstance2[1];
186+
int pceltFetched;
187+
Console.Write("[");
188+
e.Next(1, rgelt, out pceltFetched);
189+
while (pceltFetched > 0)
190+
{
191+
PrintInstance(rgelt[0]);
192+
e.Next(1, rgelt, out pceltFetched);
193+
if (pceltFetched > 0)
194+
Console.Write(",");
195+
}
196+
Console.Write("]");
197+
}
198+
199+
private static void PrintInstance(ISetupInstance2 setupInstance2)
200+
{
201+
Console.Write("{\n");
202+
string[] prodParts = setupInstance2.GetProduct().GetId().Split('.');
203+
Array.Reverse(prodParts);
204+
string prod = prodParts[0];
205+
string instPath = setupInstance2.GetInstallationPath().Replace("\\", "\\\\");
206+
Console.Write(String.Format("\"Product\": \"{0}\",\n", prod));
207+
Console.Write(String.Format("\"InstallationPath\": \"{0}\",\n", instPath));
208+
Console.Write(String.Format("\"Version\": \"{0}\",\n", setupInstance2.GetInstallationVersion()));
209+
foreach (ISetupPackageReference package in setupInstance2.GetPackages())
210+
{
211+
if (package.GetType() != "Exe") continue;
212+
string id = package.GetId();
213+
if (id.IndexOf("SDK", StringComparison.Ordinal) == -1) continue;
214+
string[] parts = id.Split('_');
215+
if (parts.Length < 2) continue;
216+
string sdkVer = parts[1];
217+
char[] chars = {'1', '0', '8'};
218+
if (sdkVer.IndexOfAny(chars) == -1) continue;
219+
Console.Write(String.Format("\"SDKFull\": \"{0}\",\n", sdkVer));
220+
string[] sdkParts = sdkVer.Split('.');
221+
sdkParts[sdkParts.Length - 1] = "0";
222+
Console.Write(String.Format("\"SDK\": \"{0}\",\n", String.Join(".", sdkParts)));
223+
}
224+
String cmd = (setupInstance2.GetInstallationPath() + "\\Common7\\Tools\\VsDevCmd.bat");
225+
cmd = cmd.Replace("\\", "\\\\");
226+
Console.Write(String.Format("\"CmdPath\": \"{0}\"\n", cmd));
227+
Console.Write("}");
228+
}
229+
}
230+
231+
}
232+
233+
public static class Program
234+
{
235+
public static int Main(string[] args)
236+
{
237+
VisualStudioConfiguration.Main.Query();
238+
return 0;
239+
}
240+
}

tools/try_powershell.cmd

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@IF NOT DEFINED DEBUG_GETTER @echo off
2+
SET CSFILE=%~dp0Get-VS7.cs
3+
SET COM_TEST="if (-NOT (Test-Path 'Registry::HKEY_CLASSES_ROOT\CLSID\{177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D}'))"
4+
SET JIT_AND_RUN="Add-Type -Path '%CSFILE%'; [VisualStudioConfiguration.Main]::Query()"
5+
powershell -ExecutionPolicy Unrestricted -Command "%COM_TEST% { Write '[\"No COM\"]'} else {%JIT_AND_RUN%}"

0 commit comments

Comments
 (0)