jpayne@68
|
1 """
|
jpayne@68
|
2 Environment info about Microsoft Compilers.
|
jpayne@68
|
3
|
jpayne@68
|
4 >>> getfixture('windows_only')
|
jpayne@68
|
5 >>> ei = EnvironmentInfo('amd64')
|
jpayne@68
|
6 """
|
jpayne@68
|
7
|
jpayne@68
|
8 from __future__ import annotations
|
jpayne@68
|
9
|
jpayne@68
|
10 import contextlib
|
jpayne@68
|
11 import itertools
|
jpayne@68
|
12 import json
|
jpayne@68
|
13 import os
|
jpayne@68
|
14 import os.path
|
jpayne@68
|
15 import platform
|
jpayne@68
|
16 from typing import TYPE_CHECKING
|
jpayne@68
|
17
|
jpayne@68
|
18 from more_itertools import unique_everseen
|
jpayne@68
|
19
|
jpayne@68
|
20 import distutils.errors
|
jpayne@68
|
21
|
jpayne@68
|
22 # https://github.com/python/mypy/issues/8166
|
jpayne@68
|
23 if not TYPE_CHECKING and platform.system() == 'Windows':
|
jpayne@68
|
24 import winreg
|
jpayne@68
|
25 from os import environ
|
jpayne@68
|
26 else:
|
jpayne@68
|
27 # Mock winreg and environ so the module can be imported on this platform.
|
jpayne@68
|
28
|
jpayne@68
|
29 class winreg:
|
jpayne@68
|
30 HKEY_USERS = None
|
jpayne@68
|
31 HKEY_CURRENT_USER = None
|
jpayne@68
|
32 HKEY_LOCAL_MACHINE = None
|
jpayne@68
|
33 HKEY_CLASSES_ROOT = None
|
jpayne@68
|
34
|
jpayne@68
|
35 environ: dict[str, str] = dict()
|
jpayne@68
|
36
|
jpayne@68
|
37
|
jpayne@68
|
38 class PlatformInfo:
|
jpayne@68
|
39 """
|
jpayne@68
|
40 Current and Target Architectures information.
|
jpayne@68
|
41
|
jpayne@68
|
42 Parameters
|
jpayne@68
|
43 ----------
|
jpayne@68
|
44 arch: str
|
jpayne@68
|
45 Target architecture.
|
jpayne@68
|
46 """
|
jpayne@68
|
47
|
jpayne@68
|
48 current_cpu = environ.get('processor_architecture', '').lower()
|
jpayne@68
|
49
|
jpayne@68
|
50 def __init__(self, arch):
|
jpayne@68
|
51 self.arch = arch.lower().replace('x64', 'amd64')
|
jpayne@68
|
52
|
jpayne@68
|
53 @property
|
jpayne@68
|
54 def target_cpu(self):
|
jpayne@68
|
55 """
|
jpayne@68
|
56 Return Target CPU architecture.
|
jpayne@68
|
57
|
jpayne@68
|
58 Return
|
jpayne@68
|
59 ------
|
jpayne@68
|
60 str
|
jpayne@68
|
61 Target CPU
|
jpayne@68
|
62 """
|
jpayne@68
|
63 return self.arch[self.arch.find('_') + 1 :]
|
jpayne@68
|
64
|
jpayne@68
|
65 def target_is_x86(self):
|
jpayne@68
|
66 """
|
jpayne@68
|
67 Return True if target CPU is x86 32 bits..
|
jpayne@68
|
68
|
jpayne@68
|
69 Return
|
jpayne@68
|
70 ------
|
jpayne@68
|
71 bool
|
jpayne@68
|
72 CPU is x86 32 bits
|
jpayne@68
|
73 """
|
jpayne@68
|
74 return self.target_cpu == 'x86'
|
jpayne@68
|
75
|
jpayne@68
|
76 def current_is_x86(self):
|
jpayne@68
|
77 """
|
jpayne@68
|
78 Return True if current CPU is x86 32 bits..
|
jpayne@68
|
79
|
jpayne@68
|
80 Return
|
jpayne@68
|
81 ------
|
jpayne@68
|
82 bool
|
jpayne@68
|
83 CPU is x86 32 bits
|
jpayne@68
|
84 """
|
jpayne@68
|
85 return self.current_cpu == 'x86'
|
jpayne@68
|
86
|
jpayne@68
|
87 def current_dir(self, hidex86=False, x64=False):
|
jpayne@68
|
88 """
|
jpayne@68
|
89 Current platform specific subfolder.
|
jpayne@68
|
90
|
jpayne@68
|
91 Parameters
|
jpayne@68
|
92 ----------
|
jpayne@68
|
93 hidex86: bool
|
jpayne@68
|
94 return '' and not '\x86' if architecture is x86.
|
jpayne@68
|
95 x64: bool
|
jpayne@68
|
96 return '\x64' and not '\amd64' if architecture is amd64.
|
jpayne@68
|
97
|
jpayne@68
|
98 Return
|
jpayne@68
|
99 ------
|
jpayne@68
|
100 str
|
jpayne@68
|
101 subfolder: '\target', or '' (see hidex86 parameter)
|
jpayne@68
|
102 """
|
jpayne@68
|
103 return (
|
jpayne@68
|
104 ''
|
jpayne@68
|
105 if (self.current_cpu == 'x86' and hidex86)
|
jpayne@68
|
106 else r'\x64'
|
jpayne@68
|
107 if (self.current_cpu == 'amd64' and x64)
|
jpayne@68
|
108 else r'\%s' % self.current_cpu
|
jpayne@68
|
109 )
|
jpayne@68
|
110
|
jpayne@68
|
111 def target_dir(self, hidex86=False, x64=False):
|
jpayne@68
|
112 r"""
|
jpayne@68
|
113 Target platform specific subfolder.
|
jpayne@68
|
114
|
jpayne@68
|
115 Parameters
|
jpayne@68
|
116 ----------
|
jpayne@68
|
117 hidex86: bool
|
jpayne@68
|
118 return '' and not '\x86' if architecture is x86.
|
jpayne@68
|
119 x64: bool
|
jpayne@68
|
120 return '\x64' and not '\amd64' if architecture is amd64.
|
jpayne@68
|
121
|
jpayne@68
|
122 Return
|
jpayne@68
|
123 ------
|
jpayne@68
|
124 str
|
jpayne@68
|
125 subfolder: '\current', or '' (see hidex86 parameter)
|
jpayne@68
|
126 """
|
jpayne@68
|
127 return (
|
jpayne@68
|
128 ''
|
jpayne@68
|
129 if (self.target_cpu == 'x86' and hidex86)
|
jpayne@68
|
130 else r'\x64'
|
jpayne@68
|
131 if (self.target_cpu == 'amd64' and x64)
|
jpayne@68
|
132 else r'\%s' % self.target_cpu
|
jpayne@68
|
133 )
|
jpayne@68
|
134
|
jpayne@68
|
135 def cross_dir(self, forcex86=False):
|
jpayne@68
|
136 r"""
|
jpayne@68
|
137 Cross platform specific subfolder.
|
jpayne@68
|
138
|
jpayne@68
|
139 Parameters
|
jpayne@68
|
140 ----------
|
jpayne@68
|
141 forcex86: bool
|
jpayne@68
|
142 Use 'x86' as current architecture even if current architecture is
|
jpayne@68
|
143 not x86.
|
jpayne@68
|
144
|
jpayne@68
|
145 Return
|
jpayne@68
|
146 ------
|
jpayne@68
|
147 str
|
jpayne@68
|
148 subfolder: '' if target architecture is current architecture,
|
jpayne@68
|
149 '\current_target' if not.
|
jpayne@68
|
150 """
|
jpayne@68
|
151 current = 'x86' if forcex86 else self.current_cpu
|
jpayne@68
|
152 return (
|
jpayne@68
|
153 ''
|
jpayne@68
|
154 if self.target_cpu == current
|
jpayne@68
|
155 else self.target_dir().replace('\\', '\\%s_' % current)
|
jpayne@68
|
156 )
|
jpayne@68
|
157
|
jpayne@68
|
158
|
jpayne@68
|
159 class RegistryInfo:
|
jpayne@68
|
160 """
|
jpayne@68
|
161 Microsoft Visual Studio related registry information.
|
jpayne@68
|
162
|
jpayne@68
|
163 Parameters
|
jpayne@68
|
164 ----------
|
jpayne@68
|
165 platform_info: PlatformInfo
|
jpayne@68
|
166 "PlatformInfo" instance.
|
jpayne@68
|
167 """
|
jpayne@68
|
168
|
jpayne@68
|
169 HKEYS = (
|
jpayne@68
|
170 winreg.HKEY_USERS,
|
jpayne@68
|
171 winreg.HKEY_CURRENT_USER,
|
jpayne@68
|
172 winreg.HKEY_LOCAL_MACHINE,
|
jpayne@68
|
173 winreg.HKEY_CLASSES_ROOT,
|
jpayne@68
|
174 )
|
jpayne@68
|
175
|
jpayne@68
|
176 def __init__(self, platform_info):
|
jpayne@68
|
177 self.pi = platform_info
|
jpayne@68
|
178
|
jpayne@68
|
179 @property
|
jpayne@68
|
180 def visualstudio(self):
|
jpayne@68
|
181 """
|
jpayne@68
|
182 Microsoft Visual Studio root registry key.
|
jpayne@68
|
183
|
jpayne@68
|
184 Return
|
jpayne@68
|
185 ------
|
jpayne@68
|
186 str
|
jpayne@68
|
187 Registry key
|
jpayne@68
|
188 """
|
jpayne@68
|
189 return 'VisualStudio'
|
jpayne@68
|
190
|
jpayne@68
|
191 @property
|
jpayne@68
|
192 def sxs(self):
|
jpayne@68
|
193 """
|
jpayne@68
|
194 Microsoft Visual Studio SxS registry key.
|
jpayne@68
|
195
|
jpayne@68
|
196 Return
|
jpayne@68
|
197 ------
|
jpayne@68
|
198 str
|
jpayne@68
|
199 Registry key
|
jpayne@68
|
200 """
|
jpayne@68
|
201 return os.path.join(self.visualstudio, 'SxS')
|
jpayne@68
|
202
|
jpayne@68
|
203 @property
|
jpayne@68
|
204 def vc(self):
|
jpayne@68
|
205 """
|
jpayne@68
|
206 Microsoft Visual C++ VC7 registry key.
|
jpayne@68
|
207
|
jpayne@68
|
208 Return
|
jpayne@68
|
209 ------
|
jpayne@68
|
210 str
|
jpayne@68
|
211 Registry key
|
jpayne@68
|
212 """
|
jpayne@68
|
213 return os.path.join(self.sxs, 'VC7')
|
jpayne@68
|
214
|
jpayne@68
|
215 @property
|
jpayne@68
|
216 def vs(self):
|
jpayne@68
|
217 """
|
jpayne@68
|
218 Microsoft Visual Studio VS7 registry key.
|
jpayne@68
|
219
|
jpayne@68
|
220 Return
|
jpayne@68
|
221 ------
|
jpayne@68
|
222 str
|
jpayne@68
|
223 Registry key
|
jpayne@68
|
224 """
|
jpayne@68
|
225 return os.path.join(self.sxs, 'VS7')
|
jpayne@68
|
226
|
jpayne@68
|
227 @property
|
jpayne@68
|
228 def vc_for_python(self):
|
jpayne@68
|
229 """
|
jpayne@68
|
230 Microsoft Visual C++ for Python registry key.
|
jpayne@68
|
231
|
jpayne@68
|
232 Return
|
jpayne@68
|
233 ------
|
jpayne@68
|
234 str
|
jpayne@68
|
235 Registry key
|
jpayne@68
|
236 """
|
jpayne@68
|
237 return r'DevDiv\VCForPython'
|
jpayne@68
|
238
|
jpayne@68
|
239 @property
|
jpayne@68
|
240 def microsoft_sdk(self):
|
jpayne@68
|
241 """
|
jpayne@68
|
242 Microsoft SDK registry key.
|
jpayne@68
|
243
|
jpayne@68
|
244 Return
|
jpayne@68
|
245 ------
|
jpayne@68
|
246 str
|
jpayne@68
|
247 Registry key
|
jpayne@68
|
248 """
|
jpayne@68
|
249 return 'Microsoft SDKs'
|
jpayne@68
|
250
|
jpayne@68
|
251 @property
|
jpayne@68
|
252 def windows_sdk(self):
|
jpayne@68
|
253 """
|
jpayne@68
|
254 Microsoft Windows/Platform SDK registry key.
|
jpayne@68
|
255
|
jpayne@68
|
256 Return
|
jpayne@68
|
257 ------
|
jpayne@68
|
258 str
|
jpayne@68
|
259 Registry key
|
jpayne@68
|
260 """
|
jpayne@68
|
261 return os.path.join(self.microsoft_sdk, 'Windows')
|
jpayne@68
|
262
|
jpayne@68
|
263 @property
|
jpayne@68
|
264 def netfx_sdk(self):
|
jpayne@68
|
265 """
|
jpayne@68
|
266 Microsoft .NET Framework SDK registry key.
|
jpayne@68
|
267
|
jpayne@68
|
268 Return
|
jpayne@68
|
269 ------
|
jpayne@68
|
270 str
|
jpayne@68
|
271 Registry key
|
jpayne@68
|
272 """
|
jpayne@68
|
273 return os.path.join(self.microsoft_sdk, 'NETFXSDK')
|
jpayne@68
|
274
|
jpayne@68
|
275 @property
|
jpayne@68
|
276 def windows_kits_roots(self):
|
jpayne@68
|
277 """
|
jpayne@68
|
278 Microsoft Windows Kits Roots registry key.
|
jpayne@68
|
279
|
jpayne@68
|
280 Return
|
jpayne@68
|
281 ------
|
jpayne@68
|
282 str
|
jpayne@68
|
283 Registry key
|
jpayne@68
|
284 """
|
jpayne@68
|
285 return r'Windows Kits\Installed Roots'
|
jpayne@68
|
286
|
jpayne@68
|
287 def microsoft(self, key, x86=False):
|
jpayne@68
|
288 """
|
jpayne@68
|
289 Return key in Microsoft software registry.
|
jpayne@68
|
290
|
jpayne@68
|
291 Parameters
|
jpayne@68
|
292 ----------
|
jpayne@68
|
293 key: str
|
jpayne@68
|
294 Registry key path where look.
|
jpayne@68
|
295 x86: str
|
jpayne@68
|
296 Force x86 software registry.
|
jpayne@68
|
297
|
jpayne@68
|
298 Return
|
jpayne@68
|
299 ------
|
jpayne@68
|
300 str
|
jpayne@68
|
301 Registry key
|
jpayne@68
|
302 """
|
jpayne@68
|
303 node64 = '' if self.pi.current_is_x86() or x86 else 'Wow6432Node'
|
jpayne@68
|
304 return os.path.join('Software', node64, 'Microsoft', key)
|
jpayne@68
|
305
|
jpayne@68
|
306 def lookup(self, key, name):
|
jpayne@68
|
307 """
|
jpayne@68
|
308 Look for values in registry in Microsoft software registry.
|
jpayne@68
|
309
|
jpayne@68
|
310 Parameters
|
jpayne@68
|
311 ----------
|
jpayne@68
|
312 key: str
|
jpayne@68
|
313 Registry key path where look.
|
jpayne@68
|
314 name: str
|
jpayne@68
|
315 Value name to find.
|
jpayne@68
|
316
|
jpayne@68
|
317 Return
|
jpayne@68
|
318 ------
|
jpayne@68
|
319 str
|
jpayne@68
|
320 value
|
jpayne@68
|
321 """
|
jpayne@68
|
322 key_read = winreg.KEY_READ
|
jpayne@68
|
323 openkey = winreg.OpenKey
|
jpayne@68
|
324 closekey = winreg.CloseKey
|
jpayne@68
|
325 ms = self.microsoft
|
jpayne@68
|
326 for hkey in self.HKEYS:
|
jpayne@68
|
327 bkey = None
|
jpayne@68
|
328 try:
|
jpayne@68
|
329 bkey = openkey(hkey, ms(key), 0, key_read)
|
jpayne@68
|
330 except OSError:
|
jpayne@68
|
331 if not self.pi.current_is_x86():
|
jpayne@68
|
332 try:
|
jpayne@68
|
333 bkey = openkey(hkey, ms(key, True), 0, key_read)
|
jpayne@68
|
334 except OSError:
|
jpayne@68
|
335 continue
|
jpayne@68
|
336 else:
|
jpayne@68
|
337 continue
|
jpayne@68
|
338 try:
|
jpayne@68
|
339 return winreg.QueryValueEx(bkey, name)[0]
|
jpayne@68
|
340 except OSError:
|
jpayne@68
|
341 pass
|
jpayne@68
|
342 finally:
|
jpayne@68
|
343 if bkey:
|
jpayne@68
|
344 closekey(bkey)
|
jpayne@68
|
345 return None
|
jpayne@68
|
346
|
jpayne@68
|
347
|
jpayne@68
|
348 class SystemInfo:
|
jpayne@68
|
349 """
|
jpayne@68
|
350 Microsoft Windows and Visual Studio related system information.
|
jpayne@68
|
351
|
jpayne@68
|
352 Parameters
|
jpayne@68
|
353 ----------
|
jpayne@68
|
354 registry_info: RegistryInfo
|
jpayne@68
|
355 "RegistryInfo" instance.
|
jpayne@68
|
356 vc_ver: float
|
jpayne@68
|
357 Required Microsoft Visual C++ version.
|
jpayne@68
|
358 """
|
jpayne@68
|
359
|
jpayne@68
|
360 # Variables and properties in this class use originals CamelCase variables
|
jpayne@68
|
361 # names from Microsoft source files for more easy comparison.
|
jpayne@68
|
362 WinDir = environ.get('WinDir', '')
|
jpayne@68
|
363 ProgramFiles = environ.get('ProgramFiles', '')
|
jpayne@68
|
364 ProgramFilesx86 = environ.get('ProgramFiles(x86)', ProgramFiles)
|
jpayne@68
|
365
|
jpayne@68
|
366 def __init__(self, registry_info, vc_ver=None):
|
jpayne@68
|
367 self.ri = registry_info
|
jpayne@68
|
368 self.pi = self.ri.pi
|
jpayne@68
|
369
|
jpayne@68
|
370 self.known_vs_paths = self.find_programdata_vs_vers()
|
jpayne@68
|
371
|
jpayne@68
|
372 # Except for VS15+, VC version is aligned with VS version
|
jpayne@68
|
373 self.vs_ver = self.vc_ver = vc_ver or self._find_latest_available_vs_ver()
|
jpayne@68
|
374
|
jpayne@68
|
375 def _find_latest_available_vs_ver(self):
|
jpayne@68
|
376 """
|
jpayne@68
|
377 Find the latest VC version
|
jpayne@68
|
378
|
jpayne@68
|
379 Return
|
jpayne@68
|
380 ------
|
jpayne@68
|
381 float
|
jpayne@68
|
382 version
|
jpayne@68
|
383 """
|
jpayne@68
|
384 reg_vc_vers = self.find_reg_vs_vers()
|
jpayne@68
|
385
|
jpayne@68
|
386 if not (reg_vc_vers or self.known_vs_paths):
|
jpayne@68
|
387 raise distutils.errors.DistutilsPlatformError(
|
jpayne@68
|
388 'No Microsoft Visual C++ version found'
|
jpayne@68
|
389 )
|
jpayne@68
|
390
|
jpayne@68
|
391 vc_vers = set(reg_vc_vers)
|
jpayne@68
|
392 vc_vers.update(self.known_vs_paths)
|
jpayne@68
|
393 return sorted(vc_vers)[-1]
|
jpayne@68
|
394
|
jpayne@68
|
395 def find_reg_vs_vers(self):
|
jpayne@68
|
396 """
|
jpayne@68
|
397 Find Microsoft Visual Studio versions available in registry.
|
jpayne@68
|
398
|
jpayne@68
|
399 Return
|
jpayne@68
|
400 ------
|
jpayne@68
|
401 list of float
|
jpayne@68
|
402 Versions
|
jpayne@68
|
403 """
|
jpayne@68
|
404 ms = self.ri.microsoft
|
jpayne@68
|
405 vckeys = (self.ri.vc, self.ri.vc_for_python, self.ri.vs)
|
jpayne@68
|
406 vs_vers = []
|
jpayne@68
|
407 for hkey, key in itertools.product(self.ri.HKEYS, vckeys):
|
jpayne@68
|
408 try:
|
jpayne@68
|
409 bkey = winreg.OpenKey(hkey, ms(key), 0, winreg.KEY_READ)
|
jpayne@68
|
410 except OSError:
|
jpayne@68
|
411 continue
|
jpayne@68
|
412 with bkey:
|
jpayne@68
|
413 subkeys, values, _ = winreg.QueryInfoKey(bkey)
|
jpayne@68
|
414 for i in range(values):
|
jpayne@68
|
415 with contextlib.suppress(ValueError):
|
jpayne@68
|
416 ver = float(winreg.EnumValue(bkey, i)[0])
|
jpayne@68
|
417 if ver not in vs_vers:
|
jpayne@68
|
418 vs_vers.append(ver)
|
jpayne@68
|
419 for i in range(subkeys):
|
jpayne@68
|
420 with contextlib.suppress(ValueError):
|
jpayne@68
|
421 ver = float(winreg.EnumKey(bkey, i))
|
jpayne@68
|
422 if ver not in vs_vers:
|
jpayne@68
|
423 vs_vers.append(ver)
|
jpayne@68
|
424 return sorted(vs_vers)
|
jpayne@68
|
425
|
jpayne@68
|
426 def find_programdata_vs_vers(self):
|
jpayne@68
|
427 r"""
|
jpayne@68
|
428 Find Visual studio 2017+ versions from information in
|
jpayne@68
|
429 "C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances".
|
jpayne@68
|
430
|
jpayne@68
|
431 Return
|
jpayne@68
|
432 ------
|
jpayne@68
|
433 dict
|
jpayne@68
|
434 float version as key, path as value.
|
jpayne@68
|
435 """
|
jpayne@68
|
436 vs_versions = {}
|
jpayne@68
|
437 instances_dir = r'C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances'
|
jpayne@68
|
438
|
jpayne@68
|
439 try:
|
jpayne@68
|
440 hashed_names = os.listdir(instances_dir)
|
jpayne@68
|
441
|
jpayne@68
|
442 except OSError:
|
jpayne@68
|
443 # Directory not exists with all Visual Studio versions
|
jpayne@68
|
444 return vs_versions
|
jpayne@68
|
445
|
jpayne@68
|
446 for name in hashed_names:
|
jpayne@68
|
447 try:
|
jpayne@68
|
448 # Get VS installation path from "state.json" file
|
jpayne@68
|
449 state_path = os.path.join(instances_dir, name, 'state.json')
|
jpayne@68
|
450 with open(state_path, 'rt', encoding='utf-8') as state_file:
|
jpayne@68
|
451 state = json.load(state_file)
|
jpayne@68
|
452 vs_path = state['installationPath']
|
jpayne@68
|
453
|
jpayne@68
|
454 # Raises OSError if this VS installation does not contain VC
|
jpayne@68
|
455 os.listdir(os.path.join(vs_path, r'VC\Tools\MSVC'))
|
jpayne@68
|
456
|
jpayne@68
|
457 # Store version and path
|
jpayne@68
|
458 vs_versions[self._as_float_version(state['installationVersion'])] = (
|
jpayne@68
|
459 vs_path
|
jpayne@68
|
460 )
|
jpayne@68
|
461
|
jpayne@68
|
462 except (OSError, KeyError):
|
jpayne@68
|
463 # Skip if "state.json" file is missing or bad format
|
jpayne@68
|
464 continue
|
jpayne@68
|
465
|
jpayne@68
|
466 return vs_versions
|
jpayne@68
|
467
|
jpayne@68
|
468 @staticmethod
|
jpayne@68
|
469 def _as_float_version(version):
|
jpayne@68
|
470 """
|
jpayne@68
|
471 Return a string version as a simplified float version (major.minor)
|
jpayne@68
|
472
|
jpayne@68
|
473 Parameters
|
jpayne@68
|
474 ----------
|
jpayne@68
|
475 version: str
|
jpayne@68
|
476 Version.
|
jpayne@68
|
477
|
jpayne@68
|
478 Return
|
jpayne@68
|
479 ------
|
jpayne@68
|
480 float
|
jpayne@68
|
481 version
|
jpayne@68
|
482 """
|
jpayne@68
|
483 return float('.'.join(version.split('.')[:2]))
|
jpayne@68
|
484
|
jpayne@68
|
485 @property
|
jpayne@68
|
486 def VSInstallDir(self):
|
jpayne@68
|
487 """
|
jpayne@68
|
488 Microsoft Visual Studio directory.
|
jpayne@68
|
489
|
jpayne@68
|
490 Return
|
jpayne@68
|
491 ------
|
jpayne@68
|
492 str
|
jpayne@68
|
493 path
|
jpayne@68
|
494 """
|
jpayne@68
|
495 # Default path
|
jpayne@68
|
496 default = os.path.join(
|
jpayne@68
|
497 self.ProgramFilesx86, 'Microsoft Visual Studio %0.1f' % self.vs_ver
|
jpayne@68
|
498 )
|
jpayne@68
|
499
|
jpayne@68
|
500 # Try to get path from registry, if fail use default path
|
jpayne@68
|
501 return self.ri.lookup(self.ri.vs, '%0.1f' % self.vs_ver) or default
|
jpayne@68
|
502
|
jpayne@68
|
503 @property
|
jpayne@68
|
504 def VCInstallDir(self):
|
jpayne@68
|
505 """
|
jpayne@68
|
506 Microsoft Visual C++ directory.
|
jpayne@68
|
507
|
jpayne@68
|
508 Return
|
jpayne@68
|
509 ------
|
jpayne@68
|
510 str
|
jpayne@68
|
511 path
|
jpayne@68
|
512 """
|
jpayne@68
|
513 path = self._guess_vc() or self._guess_vc_legacy()
|
jpayne@68
|
514
|
jpayne@68
|
515 if not os.path.isdir(path):
|
jpayne@68
|
516 msg = 'Microsoft Visual C++ directory not found'
|
jpayne@68
|
517 raise distutils.errors.DistutilsPlatformError(msg)
|
jpayne@68
|
518
|
jpayne@68
|
519 return path
|
jpayne@68
|
520
|
jpayne@68
|
521 def _guess_vc(self):
|
jpayne@68
|
522 """
|
jpayne@68
|
523 Locate Visual C++ for VS2017+.
|
jpayne@68
|
524
|
jpayne@68
|
525 Return
|
jpayne@68
|
526 ------
|
jpayne@68
|
527 str
|
jpayne@68
|
528 path
|
jpayne@68
|
529 """
|
jpayne@68
|
530 if self.vs_ver <= 14.0:
|
jpayne@68
|
531 return ''
|
jpayne@68
|
532
|
jpayne@68
|
533 try:
|
jpayne@68
|
534 # First search in known VS paths
|
jpayne@68
|
535 vs_dir = self.known_vs_paths[self.vs_ver]
|
jpayne@68
|
536 except KeyError:
|
jpayne@68
|
537 # Else, search with path from registry
|
jpayne@68
|
538 vs_dir = self.VSInstallDir
|
jpayne@68
|
539
|
jpayne@68
|
540 guess_vc = os.path.join(vs_dir, r'VC\Tools\MSVC')
|
jpayne@68
|
541
|
jpayne@68
|
542 # Subdir with VC exact version as name
|
jpayne@68
|
543 try:
|
jpayne@68
|
544 # Update the VC version with real one instead of VS version
|
jpayne@68
|
545 vc_ver = os.listdir(guess_vc)[-1]
|
jpayne@68
|
546 self.vc_ver = self._as_float_version(vc_ver)
|
jpayne@68
|
547 return os.path.join(guess_vc, vc_ver)
|
jpayne@68
|
548 except (OSError, IndexError):
|
jpayne@68
|
549 return ''
|
jpayne@68
|
550
|
jpayne@68
|
551 def _guess_vc_legacy(self):
|
jpayne@68
|
552 """
|
jpayne@68
|
553 Locate Visual C++ for versions prior to 2017.
|
jpayne@68
|
554
|
jpayne@68
|
555 Return
|
jpayne@68
|
556 ------
|
jpayne@68
|
557 str
|
jpayne@68
|
558 path
|
jpayne@68
|
559 """
|
jpayne@68
|
560 default = os.path.join(
|
jpayne@68
|
561 self.ProgramFilesx86, r'Microsoft Visual Studio %0.1f\VC' % self.vs_ver
|
jpayne@68
|
562 )
|
jpayne@68
|
563
|
jpayne@68
|
564 # Try to get "VC++ for Python" path from registry as default path
|
jpayne@68
|
565 reg_path = os.path.join(self.ri.vc_for_python, '%0.1f' % self.vs_ver)
|
jpayne@68
|
566 python_vc = self.ri.lookup(reg_path, 'installdir')
|
jpayne@68
|
567 default_vc = os.path.join(python_vc, 'VC') if python_vc else default
|
jpayne@68
|
568
|
jpayne@68
|
569 # Try to get path from registry, if fail use default path
|
jpayne@68
|
570 return self.ri.lookup(self.ri.vc, '%0.1f' % self.vs_ver) or default_vc
|
jpayne@68
|
571
|
jpayne@68
|
572 @property
|
jpayne@68
|
573 def WindowsSdkVersion(self):
|
jpayne@68
|
574 """
|
jpayne@68
|
575 Microsoft Windows SDK versions for specified MSVC++ version.
|
jpayne@68
|
576
|
jpayne@68
|
577 Return
|
jpayne@68
|
578 ------
|
jpayne@68
|
579 tuple of str
|
jpayne@68
|
580 versions
|
jpayne@68
|
581 """
|
jpayne@68
|
582 if self.vs_ver <= 9.0:
|
jpayne@68
|
583 return '7.0', '6.1', '6.0a'
|
jpayne@68
|
584 elif self.vs_ver == 10.0:
|
jpayne@68
|
585 return '7.1', '7.0a'
|
jpayne@68
|
586 elif self.vs_ver == 11.0:
|
jpayne@68
|
587 return '8.0', '8.0a'
|
jpayne@68
|
588 elif self.vs_ver == 12.0:
|
jpayne@68
|
589 return '8.1', '8.1a'
|
jpayne@68
|
590 elif self.vs_ver >= 14.0:
|
jpayne@68
|
591 return '10.0', '8.1'
|
jpayne@68
|
592 return None
|
jpayne@68
|
593
|
jpayne@68
|
594 @property
|
jpayne@68
|
595 def WindowsSdkLastVersion(self):
|
jpayne@68
|
596 """
|
jpayne@68
|
597 Microsoft Windows SDK last version.
|
jpayne@68
|
598
|
jpayne@68
|
599 Return
|
jpayne@68
|
600 ------
|
jpayne@68
|
601 str
|
jpayne@68
|
602 version
|
jpayne@68
|
603 """
|
jpayne@68
|
604 return self._use_last_dir_name(os.path.join(self.WindowsSdkDir, 'lib'))
|
jpayne@68
|
605
|
jpayne@68
|
606 @property
|
jpayne@68
|
607 def WindowsSdkDir(self): # noqa: C901 # is too complex (12) # FIXME
|
jpayne@68
|
608 """
|
jpayne@68
|
609 Microsoft Windows SDK directory.
|
jpayne@68
|
610
|
jpayne@68
|
611 Return
|
jpayne@68
|
612 ------
|
jpayne@68
|
613 str
|
jpayne@68
|
614 path
|
jpayne@68
|
615 """
|
jpayne@68
|
616 sdkdir = ''
|
jpayne@68
|
617 for ver in self.WindowsSdkVersion:
|
jpayne@68
|
618 # Try to get it from registry
|
jpayne@68
|
619 loc = os.path.join(self.ri.windows_sdk, 'v%s' % ver)
|
jpayne@68
|
620 sdkdir = self.ri.lookup(loc, 'installationfolder')
|
jpayne@68
|
621 if sdkdir:
|
jpayne@68
|
622 break
|
jpayne@68
|
623 if not sdkdir or not os.path.isdir(sdkdir):
|
jpayne@68
|
624 # Try to get "VC++ for Python" version from registry
|
jpayne@68
|
625 path = os.path.join(self.ri.vc_for_python, '%0.1f' % self.vc_ver)
|
jpayne@68
|
626 install_base = self.ri.lookup(path, 'installdir')
|
jpayne@68
|
627 if install_base:
|
jpayne@68
|
628 sdkdir = os.path.join(install_base, 'WinSDK')
|
jpayne@68
|
629 if not sdkdir or not os.path.isdir(sdkdir):
|
jpayne@68
|
630 # If fail, use default new path
|
jpayne@68
|
631 for ver in self.WindowsSdkVersion:
|
jpayne@68
|
632 intver = ver[: ver.rfind('.')]
|
jpayne@68
|
633 path = r'Microsoft SDKs\Windows Kits\%s' % intver
|
jpayne@68
|
634 d = os.path.join(self.ProgramFiles, path)
|
jpayne@68
|
635 if os.path.isdir(d):
|
jpayne@68
|
636 sdkdir = d
|
jpayne@68
|
637 if not sdkdir or not os.path.isdir(sdkdir):
|
jpayne@68
|
638 # If fail, use default old path
|
jpayne@68
|
639 for ver in self.WindowsSdkVersion:
|
jpayne@68
|
640 path = r'Microsoft SDKs\Windows\v%s' % ver
|
jpayne@68
|
641 d = os.path.join(self.ProgramFiles, path)
|
jpayne@68
|
642 if os.path.isdir(d):
|
jpayne@68
|
643 sdkdir = d
|
jpayne@68
|
644 if not sdkdir:
|
jpayne@68
|
645 # If fail, use Platform SDK
|
jpayne@68
|
646 sdkdir = os.path.join(self.VCInstallDir, 'PlatformSDK')
|
jpayne@68
|
647 return sdkdir
|
jpayne@68
|
648
|
jpayne@68
|
649 @property
|
jpayne@68
|
650 def WindowsSDKExecutablePath(self):
|
jpayne@68
|
651 """
|
jpayne@68
|
652 Microsoft Windows SDK executable directory.
|
jpayne@68
|
653
|
jpayne@68
|
654 Return
|
jpayne@68
|
655 ------
|
jpayne@68
|
656 str
|
jpayne@68
|
657 path
|
jpayne@68
|
658 """
|
jpayne@68
|
659 # Find WinSDK NetFx Tools registry dir name
|
jpayne@68
|
660 if self.vs_ver <= 11.0:
|
jpayne@68
|
661 netfxver = 35
|
jpayne@68
|
662 arch = ''
|
jpayne@68
|
663 else:
|
jpayne@68
|
664 netfxver = 40
|
jpayne@68
|
665 hidex86 = True if self.vs_ver <= 12.0 else False
|
jpayne@68
|
666 arch = self.pi.current_dir(x64=True, hidex86=hidex86)
|
jpayne@68
|
667 fx = 'WinSDK-NetFx%dTools%s' % (netfxver, arch.replace('\\', '-'))
|
jpayne@68
|
668
|
jpayne@68
|
669 # list all possibles registry paths
|
jpayne@68
|
670 regpaths = []
|
jpayne@68
|
671 if self.vs_ver >= 14.0:
|
jpayne@68
|
672 for ver in self.NetFxSdkVersion:
|
jpayne@68
|
673 regpaths += [os.path.join(self.ri.netfx_sdk, ver, fx)]
|
jpayne@68
|
674
|
jpayne@68
|
675 for ver in self.WindowsSdkVersion:
|
jpayne@68
|
676 regpaths += [os.path.join(self.ri.windows_sdk, 'v%sA' % ver, fx)]
|
jpayne@68
|
677
|
jpayne@68
|
678 # Return installation folder from the more recent path
|
jpayne@68
|
679 for path in regpaths:
|
jpayne@68
|
680 execpath = self.ri.lookup(path, 'installationfolder')
|
jpayne@68
|
681 if execpath:
|
jpayne@68
|
682 return execpath
|
jpayne@68
|
683
|
jpayne@68
|
684 return None
|
jpayne@68
|
685
|
jpayne@68
|
686 @property
|
jpayne@68
|
687 def FSharpInstallDir(self):
|
jpayne@68
|
688 """
|
jpayne@68
|
689 Microsoft Visual F# directory.
|
jpayne@68
|
690
|
jpayne@68
|
691 Return
|
jpayne@68
|
692 ------
|
jpayne@68
|
693 str
|
jpayne@68
|
694 path
|
jpayne@68
|
695 """
|
jpayne@68
|
696 path = os.path.join(self.ri.visualstudio, r'%0.1f\Setup\F#' % self.vs_ver)
|
jpayne@68
|
697 return self.ri.lookup(path, 'productdir') or ''
|
jpayne@68
|
698
|
jpayne@68
|
699 @property
|
jpayne@68
|
700 def UniversalCRTSdkDir(self):
|
jpayne@68
|
701 """
|
jpayne@68
|
702 Microsoft Universal CRT SDK directory.
|
jpayne@68
|
703
|
jpayne@68
|
704 Return
|
jpayne@68
|
705 ------
|
jpayne@68
|
706 str
|
jpayne@68
|
707 path
|
jpayne@68
|
708 """
|
jpayne@68
|
709 # Set Kit Roots versions for specified MSVC++ version
|
jpayne@68
|
710 vers = ('10', '81') if self.vs_ver >= 14.0 else ()
|
jpayne@68
|
711
|
jpayne@68
|
712 # Find path of the more recent Kit
|
jpayne@68
|
713 for ver in vers:
|
jpayne@68
|
714 sdkdir = self.ri.lookup(self.ri.windows_kits_roots, 'kitsroot%s' % ver)
|
jpayne@68
|
715 if sdkdir:
|
jpayne@68
|
716 return sdkdir or ''
|
jpayne@68
|
717
|
jpayne@68
|
718 return None
|
jpayne@68
|
719
|
jpayne@68
|
720 @property
|
jpayne@68
|
721 def UniversalCRTSdkLastVersion(self):
|
jpayne@68
|
722 """
|
jpayne@68
|
723 Microsoft Universal C Runtime SDK last version.
|
jpayne@68
|
724
|
jpayne@68
|
725 Return
|
jpayne@68
|
726 ------
|
jpayne@68
|
727 str
|
jpayne@68
|
728 version
|
jpayne@68
|
729 """
|
jpayne@68
|
730 return self._use_last_dir_name(os.path.join(self.UniversalCRTSdkDir, 'lib'))
|
jpayne@68
|
731
|
jpayne@68
|
732 @property
|
jpayne@68
|
733 def NetFxSdkVersion(self):
|
jpayne@68
|
734 """
|
jpayne@68
|
735 Microsoft .NET Framework SDK versions.
|
jpayne@68
|
736
|
jpayne@68
|
737 Return
|
jpayne@68
|
738 ------
|
jpayne@68
|
739 tuple of str
|
jpayne@68
|
740 versions
|
jpayne@68
|
741 """
|
jpayne@68
|
742 # Set FxSdk versions for specified VS version
|
jpayne@68
|
743 return (
|
jpayne@68
|
744 ('4.7.2', '4.7.1', '4.7', '4.6.2', '4.6.1', '4.6', '4.5.2', '4.5.1', '4.5')
|
jpayne@68
|
745 if self.vs_ver >= 14.0
|
jpayne@68
|
746 else ()
|
jpayne@68
|
747 )
|
jpayne@68
|
748
|
jpayne@68
|
749 @property
|
jpayne@68
|
750 def NetFxSdkDir(self):
|
jpayne@68
|
751 """
|
jpayne@68
|
752 Microsoft .NET Framework SDK directory.
|
jpayne@68
|
753
|
jpayne@68
|
754 Return
|
jpayne@68
|
755 ------
|
jpayne@68
|
756 str
|
jpayne@68
|
757 path
|
jpayne@68
|
758 """
|
jpayne@68
|
759 sdkdir = ''
|
jpayne@68
|
760 for ver in self.NetFxSdkVersion:
|
jpayne@68
|
761 loc = os.path.join(self.ri.netfx_sdk, ver)
|
jpayne@68
|
762 sdkdir = self.ri.lookup(loc, 'kitsinstallationfolder')
|
jpayne@68
|
763 if sdkdir:
|
jpayne@68
|
764 break
|
jpayne@68
|
765 return sdkdir
|
jpayne@68
|
766
|
jpayne@68
|
767 @property
|
jpayne@68
|
768 def FrameworkDir32(self):
|
jpayne@68
|
769 """
|
jpayne@68
|
770 Microsoft .NET Framework 32bit directory.
|
jpayne@68
|
771
|
jpayne@68
|
772 Return
|
jpayne@68
|
773 ------
|
jpayne@68
|
774 str
|
jpayne@68
|
775 path
|
jpayne@68
|
776 """
|
jpayne@68
|
777 # Default path
|
jpayne@68
|
778 guess_fw = os.path.join(self.WinDir, r'Microsoft.NET\Framework')
|
jpayne@68
|
779
|
jpayne@68
|
780 # Try to get path from registry, if fail use default path
|
jpayne@68
|
781 return self.ri.lookup(self.ri.vc, 'frameworkdir32') or guess_fw
|
jpayne@68
|
782
|
jpayne@68
|
783 @property
|
jpayne@68
|
784 def FrameworkDir64(self):
|
jpayne@68
|
785 """
|
jpayne@68
|
786 Microsoft .NET Framework 64bit directory.
|
jpayne@68
|
787
|
jpayne@68
|
788 Return
|
jpayne@68
|
789 ------
|
jpayne@68
|
790 str
|
jpayne@68
|
791 path
|
jpayne@68
|
792 """
|
jpayne@68
|
793 # Default path
|
jpayne@68
|
794 guess_fw = os.path.join(self.WinDir, r'Microsoft.NET\Framework64')
|
jpayne@68
|
795
|
jpayne@68
|
796 # Try to get path from registry, if fail use default path
|
jpayne@68
|
797 return self.ri.lookup(self.ri.vc, 'frameworkdir64') or guess_fw
|
jpayne@68
|
798
|
jpayne@68
|
799 @property
|
jpayne@68
|
800 def FrameworkVersion32(self):
|
jpayne@68
|
801 """
|
jpayne@68
|
802 Microsoft .NET Framework 32bit versions.
|
jpayne@68
|
803
|
jpayne@68
|
804 Return
|
jpayne@68
|
805 ------
|
jpayne@68
|
806 tuple of str
|
jpayne@68
|
807 versions
|
jpayne@68
|
808 """
|
jpayne@68
|
809 return self._find_dot_net_versions(32)
|
jpayne@68
|
810
|
jpayne@68
|
811 @property
|
jpayne@68
|
812 def FrameworkVersion64(self):
|
jpayne@68
|
813 """
|
jpayne@68
|
814 Microsoft .NET Framework 64bit versions.
|
jpayne@68
|
815
|
jpayne@68
|
816 Return
|
jpayne@68
|
817 ------
|
jpayne@68
|
818 tuple of str
|
jpayne@68
|
819 versions
|
jpayne@68
|
820 """
|
jpayne@68
|
821 return self._find_dot_net_versions(64)
|
jpayne@68
|
822
|
jpayne@68
|
823 def _find_dot_net_versions(self, bits):
|
jpayne@68
|
824 """
|
jpayne@68
|
825 Find Microsoft .NET Framework versions.
|
jpayne@68
|
826
|
jpayne@68
|
827 Parameters
|
jpayne@68
|
828 ----------
|
jpayne@68
|
829 bits: int
|
jpayne@68
|
830 Platform number of bits: 32 or 64.
|
jpayne@68
|
831
|
jpayne@68
|
832 Return
|
jpayne@68
|
833 ------
|
jpayne@68
|
834 tuple of str
|
jpayne@68
|
835 versions
|
jpayne@68
|
836 """
|
jpayne@68
|
837 # Find actual .NET version in registry
|
jpayne@68
|
838 reg_ver = self.ri.lookup(self.ri.vc, 'frameworkver%d' % bits)
|
jpayne@68
|
839 dot_net_dir = getattr(self, 'FrameworkDir%d' % bits)
|
jpayne@68
|
840 ver = reg_ver or self._use_last_dir_name(dot_net_dir, 'v') or ''
|
jpayne@68
|
841
|
jpayne@68
|
842 # Set .NET versions for specified MSVC++ version
|
jpayne@68
|
843 if self.vs_ver >= 12.0:
|
jpayne@68
|
844 return ver, 'v4.0'
|
jpayne@68
|
845 elif self.vs_ver >= 10.0:
|
jpayne@68
|
846 return 'v4.0.30319' if ver.lower()[:2] != 'v4' else ver, 'v3.5'
|
jpayne@68
|
847 elif self.vs_ver == 9.0:
|
jpayne@68
|
848 return 'v3.5', 'v2.0.50727'
|
jpayne@68
|
849 elif self.vs_ver == 8.0:
|
jpayne@68
|
850 return 'v3.0', 'v2.0.50727'
|
jpayne@68
|
851 return None
|
jpayne@68
|
852
|
jpayne@68
|
853 @staticmethod
|
jpayne@68
|
854 def _use_last_dir_name(path, prefix=''):
|
jpayne@68
|
855 """
|
jpayne@68
|
856 Return name of the last dir in path or '' if no dir found.
|
jpayne@68
|
857
|
jpayne@68
|
858 Parameters
|
jpayne@68
|
859 ----------
|
jpayne@68
|
860 path: str
|
jpayne@68
|
861 Use dirs in this path
|
jpayne@68
|
862 prefix: str
|
jpayne@68
|
863 Use only dirs starting by this prefix
|
jpayne@68
|
864
|
jpayne@68
|
865 Return
|
jpayne@68
|
866 ------
|
jpayne@68
|
867 str
|
jpayne@68
|
868 name
|
jpayne@68
|
869 """
|
jpayne@68
|
870 matching_dirs = (
|
jpayne@68
|
871 dir_name
|
jpayne@68
|
872 for dir_name in reversed(os.listdir(path))
|
jpayne@68
|
873 if os.path.isdir(os.path.join(path, dir_name))
|
jpayne@68
|
874 and dir_name.startswith(prefix)
|
jpayne@68
|
875 )
|
jpayne@68
|
876 return next(matching_dirs, None) or ''
|
jpayne@68
|
877
|
jpayne@68
|
878
|
jpayne@68
|
879 class EnvironmentInfo:
|
jpayne@68
|
880 """
|
jpayne@68
|
881 Return environment variables for specified Microsoft Visual C++ version
|
jpayne@68
|
882 and platform : Lib, Include, Path and libpath.
|
jpayne@68
|
883
|
jpayne@68
|
884 This function is compatible with Microsoft Visual C++ 9.0 to 14.X.
|
jpayne@68
|
885
|
jpayne@68
|
886 Script created by analysing Microsoft environment configuration files like
|
jpayne@68
|
887 "vcvars[...].bat", "SetEnv.Cmd", "vcbuildtools.bat", ...
|
jpayne@68
|
888
|
jpayne@68
|
889 Parameters
|
jpayne@68
|
890 ----------
|
jpayne@68
|
891 arch: str
|
jpayne@68
|
892 Target architecture.
|
jpayne@68
|
893 vc_ver: float
|
jpayne@68
|
894 Required Microsoft Visual C++ version. If not set, autodetect the last
|
jpayne@68
|
895 version.
|
jpayne@68
|
896 vc_min_ver: float
|
jpayne@68
|
897 Minimum Microsoft Visual C++ version.
|
jpayne@68
|
898 """
|
jpayne@68
|
899
|
jpayne@68
|
900 # Variables and properties in this class use originals CamelCase variables
|
jpayne@68
|
901 # names from Microsoft source files for more easy comparison.
|
jpayne@68
|
902
|
jpayne@68
|
903 def __init__(self, arch, vc_ver=None, vc_min_ver=0):
|
jpayne@68
|
904 self.pi = PlatformInfo(arch)
|
jpayne@68
|
905 self.ri = RegistryInfo(self.pi)
|
jpayne@68
|
906 self.si = SystemInfo(self.ri, vc_ver)
|
jpayne@68
|
907
|
jpayne@68
|
908 if self.vc_ver < vc_min_ver:
|
jpayne@68
|
909 err = 'No suitable Microsoft Visual C++ version found'
|
jpayne@68
|
910 raise distutils.errors.DistutilsPlatformError(err)
|
jpayne@68
|
911
|
jpayne@68
|
912 @property
|
jpayne@68
|
913 def vs_ver(self):
|
jpayne@68
|
914 """
|
jpayne@68
|
915 Microsoft Visual Studio.
|
jpayne@68
|
916
|
jpayne@68
|
917 Return
|
jpayne@68
|
918 ------
|
jpayne@68
|
919 float
|
jpayne@68
|
920 version
|
jpayne@68
|
921 """
|
jpayne@68
|
922 return self.si.vs_ver
|
jpayne@68
|
923
|
jpayne@68
|
924 @property
|
jpayne@68
|
925 def vc_ver(self):
|
jpayne@68
|
926 """
|
jpayne@68
|
927 Microsoft Visual C++ version.
|
jpayne@68
|
928
|
jpayne@68
|
929 Return
|
jpayne@68
|
930 ------
|
jpayne@68
|
931 float
|
jpayne@68
|
932 version
|
jpayne@68
|
933 """
|
jpayne@68
|
934 return self.si.vc_ver
|
jpayne@68
|
935
|
jpayne@68
|
936 @property
|
jpayne@68
|
937 def VSTools(self):
|
jpayne@68
|
938 """
|
jpayne@68
|
939 Microsoft Visual Studio Tools.
|
jpayne@68
|
940
|
jpayne@68
|
941 Return
|
jpayne@68
|
942 ------
|
jpayne@68
|
943 list of str
|
jpayne@68
|
944 paths
|
jpayne@68
|
945 """
|
jpayne@68
|
946 paths = [r'Common7\IDE', r'Common7\Tools']
|
jpayne@68
|
947
|
jpayne@68
|
948 if self.vs_ver >= 14.0:
|
jpayne@68
|
949 arch_subdir = self.pi.current_dir(hidex86=True, x64=True)
|
jpayne@68
|
950 paths += [r'Common7\IDE\CommonExtensions\Microsoft\TestWindow']
|
jpayne@68
|
951 paths += [r'Team Tools\Performance Tools']
|
jpayne@68
|
952 paths += [r'Team Tools\Performance Tools%s' % arch_subdir]
|
jpayne@68
|
953
|
jpayne@68
|
954 return [os.path.join(self.si.VSInstallDir, path) for path in paths]
|
jpayne@68
|
955
|
jpayne@68
|
956 @property
|
jpayne@68
|
957 def VCIncludes(self):
|
jpayne@68
|
958 """
|
jpayne@68
|
959 Microsoft Visual C++ & Microsoft Foundation Class Includes.
|
jpayne@68
|
960
|
jpayne@68
|
961 Return
|
jpayne@68
|
962 ------
|
jpayne@68
|
963 list of str
|
jpayne@68
|
964 paths
|
jpayne@68
|
965 """
|
jpayne@68
|
966 return [
|
jpayne@68
|
967 os.path.join(self.si.VCInstallDir, 'Include'),
|
jpayne@68
|
968 os.path.join(self.si.VCInstallDir, r'ATLMFC\Include'),
|
jpayne@68
|
969 ]
|
jpayne@68
|
970
|
jpayne@68
|
971 @property
|
jpayne@68
|
972 def VCLibraries(self):
|
jpayne@68
|
973 """
|
jpayne@68
|
974 Microsoft Visual C++ & Microsoft Foundation Class Libraries.
|
jpayne@68
|
975
|
jpayne@68
|
976 Return
|
jpayne@68
|
977 ------
|
jpayne@68
|
978 list of str
|
jpayne@68
|
979 paths
|
jpayne@68
|
980 """
|
jpayne@68
|
981 if self.vs_ver >= 15.0:
|
jpayne@68
|
982 arch_subdir = self.pi.target_dir(x64=True)
|
jpayne@68
|
983 else:
|
jpayne@68
|
984 arch_subdir = self.pi.target_dir(hidex86=True)
|
jpayne@68
|
985 paths = ['Lib%s' % arch_subdir, r'ATLMFC\Lib%s' % arch_subdir]
|
jpayne@68
|
986
|
jpayne@68
|
987 if self.vs_ver >= 14.0:
|
jpayne@68
|
988 paths += [r'Lib\store%s' % arch_subdir]
|
jpayne@68
|
989
|
jpayne@68
|
990 return [os.path.join(self.si.VCInstallDir, path) for path in paths]
|
jpayne@68
|
991
|
jpayne@68
|
992 @property
|
jpayne@68
|
993 def VCStoreRefs(self):
|
jpayne@68
|
994 """
|
jpayne@68
|
995 Microsoft Visual C++ store references Libraries.
|
jpayne@68
|
996
|
jpayne@68
|
997 Return
|
jpayne@68
|
998 ------
|
jpayne@68
|
999 list of str
|
jpayne@68
|
1000 paths
|
jpayne@68
|
1001 """
|
jpayne@68
|
1002 if self.vs_ver < 14.0:
|
jpayne@68
|
1003 return []
|
jpayne@68
|
1004 return [os.path.join(self.si.VCInstallDir, r'Lib\store\references')]
|
jpayne@68
|
1005
|
jpayne@68
|
1006 @property
|
jpayne@68
|
1007 def VCTools(self):
|
jpayne@68
|
1008 """
|
jpayne@68
|
1009 Microsoft Visual C++ Tools.
|
jpayne@68
|
1010
|
jpayne@68
|
1011 Return
|
jpayne@68
|
1012 ------
|
jpayne@68
|
1013 list of str
|
jpayne@68
|
1014 paths
|
jpayne@68
|
1015 """
|
jpayne@68
|
1016 si = self.si
|
jpayne@68
|
1017 tools = [os.path.join(si.VCInstallDir, 'VCPackages')]
|
jpayne@68
|
1018
|
jpayne@68
|
1019 forcex86 = True if self.vs_ver <= 10.0 else False
|
jpayne@68
|
1020 arch_subdir = self.pi.cross_dir(forcex86)
|
jpayne@68
|
1021 if arch_subdir:
|
jpayne@68
|
1022 tools += [os.path.join(si.VCInstallDir, 'Bin%s' % arch_subdir)]
|
jpayne@68
|
1023
|
jpayne@68
|
1024 if self.vs_ver == 14.0:
|
jpayne@68
|
1025 path = 'Bin%s' % self.pi.current_dir(hidex86=True)
|
jpayne@68
|
1026 tools += [os.path.join(si.VCInstallDir, path)]
|
jpayne@68
|
1027
|
jpayne@68
|
1028 elif self.vs_ver >= 15.0:
|
jpayne@68
|
1029 host_dir = (
|
jpayne@68
|
1030 r'bin\HostX86%s' if self.pi.current_is_x86() else r'bin\HostX64%s'
|
jpayne@68
|
1031 )
|
jpayne@68
|
1032 tools += [
|
jpayne@68
|
1033 os.path.join(si.VCInstallDir, host_dir % self.pi.target_dir(x64=True))
|
jpayne@68
|
1034 ]
|
jpayne@68
|
1035
|
jpayne@68
|
1036 if self.pi.current_cpu != self.pi.target_cpu:
|
jpayne@68
|
1037 tools += [
|
jpayne@68
|
1038 os.path.join(
|
jpayne@68
|
1039 si.VCInstallDir, host_dir % self.pi.current_dir(x64=True)
|
jpayne@68
|
1040 )
|
jpayne@68
|
1041 ]
|
jpayne@68
|
1042
|
jpayne@68
|
1043 else:
|
jpayne@68
|
1044 tools += [os.path.join(si.VCInstallDir, 'Bin')]
|
jpayne@68
|
1045
|
jpayne@68
|
1046 return tools
|
jpayne@68
|
1047
|
jpayne@68
|
1048 @property
|
jpayne@68
|
1049 def OSLibraries(self):
|
jpayne@68
|
1050 """
|
jpayne@68
|
1051 Microsoft Windows SDK Libraries.
|
jpayne@68
|
1052
|
jpayne@68
|
1053 Return
|
jpayne@68
|
1054 ------
|
jpayne@68
|
1055 list of str
|
jpayne@68
|
1056 paths
|
jpayne@68
|
1057 """
|
jpayne@68
|
1058 if self.vs_ver <= 10.0:
|
jpayne@68
|
1059 arch_subdir = self.pi.target_dir(hidex86=True, x64=True)
|
jpayne@68
|
1060 return [os.path.join(self.si.WindowsSdkDir, 'Lib%s' % arch_subdir)]
|
jpayne@68
|
1061
|
jpayne@68
|
1062 else:
|
jpayne@68
|
1063 arch_subdir = self.pi.target_dir(x64=True)
|
jpayne@68
|
1064 lib = os.path.join(self.si.WindowsSdkDir, 'lib')
|
jpayne@68
|
1065 libver = self._sdk_subdir
|
jpayne@68
|
1066 return [os.path.join(lib, '%sum%s' % (libver, arch_subdir))]
|
jpayne@68
|
1067
|
jpayne@68
|
1068 @property
|
jpayne@68
|
1069 def OSIncludes(self):
|
jpayne@68
|
1070 """
|
jpayne@68
|
1071 Microsoft Windows SDK Include.
|
jpayne@68
|
1072
|
jpayne@68
|
1073 Return
|
jpayne@68
|
1074 ------
|
jpayne@68
|
1075 list of str
|
jpayne@68
|
1076 paths
|
jpayne@68
|
1077 """
|
jpayne@68
|
1078 include = os.path.join(self.si.WindowsSdkDir, 'include')
|
jpayne@68
|
1079
|
jpayne@68
|
1080 if self.vs_ver <= 10.0:
|
jpayne@68
|
1081 return [include, os.path.join(include, 'gl')]
|
jpayne@68
|
1082
|
jpayne@68
|
1083 else:
|
jpayne@68
|
1084 if self.vs_ver >= 14.0:
|
jpayne@68
|
1085 sdkver = self._sdk_subdir
|
jpayne@68
|
1086 else:
|
jpayne@68
|
1087 sdkver = ''
|
jpayne@68
|
1088 return [
|
jpayne@68
|
1089 os.path.join(include, '%sshared' % sdkver),
|
jpayne@68
|
1090 os.path.join(include, '%sum' % sdkver),
|
jpayne@68
|
1091 os.path.join(include, '%swinrt' % sdkver),
|
jpayne@68
|
1092 ]
|
jpayne@68
|
1093
|
jpayne@68
|
1094 @property
|
jpayne@68
|
1095 def OSLibpath(self):
|
jpayne@68
|
1096 """
|
jpayne@68
|
1097 Microsoft Windows SDK Libraries Paths.
|
jpayne@68
|
1098
|
jpayne@68
|
1099 Return
|
jpayne@68
|
1100 ------
|
jpayne@68
|
1101 list of str
|
jpayne@68
|
1102 paths
|
jpayne@68
|
1103 """
|
jpayne@68
|
1104 ref = os.path.join(self.si.WindowsSdkDir, 'References')
|
jpayne@68
|
1105 libpath = []
|
jpayne@68
|
1106
|
jpayne@68
|
1107 if self.vs_ver <= 9.0:
|
jpayne@68
|
1108 libpath += self.OSLibraries
|
jpayne@68
|
1109
|
jpayne@68
|
1110 if self.vs_ver >= 11.0:
|
jpayne@68
|
1111 libpath += [os.path.join(ref, r'CommonConfiguration\Neutral')]
|
jpayne@68
|
1112
|
jpayne@68
|
1113 if self.vs_ver >= 14.0:
|
jpayne@68
|
1114 libpath += [
|
jpayne@68
|
1115 ref,
|
jpayne@68
|
1116 os.path.join(self.si.WindowsSdkDir, 'UnionMetadata'),
|
jpayne@68
|
1117 os.path.join(ref, 'Windows.Foundation.UniversalApiContract', '1.0.0.0'),
|
jpayne@68
|
1118 os.path.join(ref, 'Windows.Foundation.FoundationContract', '1.0.0.0'),
|
jpayne@68
|
1119 os.path.join(
|
jpayne@68
|
1120 ref, 'Windows.Networking.Connectivity.WwanContract', '1.0.0.0'
|
jpayne@68
|
1121 ),
|
jpayne@68
|
1122 os.path.join(
|
jpayne@68
|
1123 self.si.WindowsSdkDir,
|
jpayne@68
|
1124 'ExtensionSDKs',
|
jpayne@68
|
1125 'Microsoft.VCLibs',
|
jpayne@68
|
1126 '%0.1f' % self.vs_ver,
|
jpayne@68
|
1127 'References',
|
jpayne@68
|
1128 'CommonConfiguration',
|
jpayne@68
|
1129 'neutral',
|
jpayne@68
|
1130 ),
|
jpayne@68
|
1131 ]
|
jpayne@68
|
1132 return libpath
|
jpayne@68
|
1133
|
jpayne@68
|
1134 @property
|
jpayne@68
|
1135 def SdkTools(self):
|
jpayne@68
|
1136 """
|
jpayne@68
|
1137 Microsoft Windows SDK Tools.
|
jpayne@68
|
1138
|
jpayne@68
|
1139 Return
|
jpayne@68
|
1140 ------
|
jpayne@68
|
1141 list of str
|
jpayne@68
|
1142 paths
|
jpayne@68
|
1143 """
|
jpayne@68
|
1144 return list(self._sdk_tools())
|
jpayne@68
|
1145
|
jpayne@68
|
1146 def _sdk_tools(self):
|
jpayne@68
|
1147 """
|
jpayne@68
|
1148 Microsoft Windows SDK Tools paths generator.
|
jpayne@68
|
1149
|
jpayne@68
|
1150 Return
|
jpayne@68
|
1151 ------
|
jpayne@68
|
1152 generator of str
|
jpayne@68
|
1153 paths
|
jpayne@68
|
1154 """
|
jpayne@68
|
1155 if self.vs_ver < 15.0:
|
jpayne@68
|
1156 bin_dir = 'Bin' if self.vs_ver <= 11.0 else r'Bin\x86'
|
jpayne@68
|
1157 yield os.path.join(self.si.WindowsSdkDir, bin_dir)
|
jpayne@68
|
1158
|
jpayne@68
|
1159 if not self.pi.current_is_x86():
|
jpayne@68
|
1160 arch_subdir = self.pi.current_dir(x64=True)
|
jpayne@68
|
1161 path = 'Bin%s' % arch_subdir
|
jpayne@68
|
1162 yield os.path.join(self.si.WindowsSdkDir, path)
|
jpayne@68
|
1163
|
jpayne@68
|
1164 if self.vs_ver in (10.0, 11.0):
|
jpayne@68
|
1165 if self.pi.target_is_x86():
|
jpayne@68
|
1166 arch_subdir = ''
|
jpayne@68
|
1167 else:
|
jpayne@68
|
1168 arch_subdir = self.pi.current_dir(hidex86=True, x64=True)
|
jpayne@68
|
1169 path = r'Bin\NETFX 4.0 Tools%s' % arch_subdir
|
jpayne@68
|
1170 yield os.path.join(self.si.WindowsSdkDir, path)
|
jpayne@68
|
1171
|
jpayne@68
|
1172 elif self.vs_ver >= 15.0:
|
jpayne@68
|
1173 path = os.path.join(self.si.WindowsSdkDir, 'Bin')
|
jpayne@68
|
1174 arch_subdir = self.pi.current_dir(x64=True)
|
jpayne@68
|
1175 sdkver = self.si.WindowsSdkLastVersion
|
jpayne@68
|
1176 yield os.path.join(path, '%s%s' % (sdkver, arch_subdir))
|
jpayne@68
|
1177
|
jpayne@68
|
1178 if self.si.WindowsSDKExecutablePath:
|
jpayne@68
|
1179 yield self.si.WindowsSDKExecutablePath
|
jpayne@68
|
1180
|
jpayne@68
|
1181 @property
|
jpayne@68
|
1182 def _sdk_subdir(self):
|
jpayne@68
|
1183 """
|
jpayne@68
|
1184 Microsoft Windows SDK version subdir.
|
jpayne@68
|
1185
|
jpayne@68
|
1186 Return
|
jpayne@68
|
1187 ------
|
jpayne@68
|
1188 str
|
jpayne@68
|
1189 subdir
|
jpayne@68
|
1190 """
|
jpayne@68
|
1191 ucrtver = self.si.WindowsSdkLastVersion
|
jpayne@68
|
1192 return ('%s\\' % ucrtver) if ucrtver else ''
|
jpayne@68
|
1193
|
jpayne@68
|
1194 @property
|
jpayne@68
|
1195 def SdkSetup(self):
|
jpayne@68
|
1196 """
|
jpayne@68
|
1197 Microsoft Windows SDK Setup.
|
jpayne@68
|
1198
|
jpayne@68
|
1199 Return
|
jpayne@68
|
1200 ------
|
jpayne@68
|
1201 list of str
|
jpayne@68
|
1202 paths
|
jpayne@68
|
1203 """
|
jpayne@68
|
1204 if self.vs_ver > 9.0:
|
jpayne@68
|
1205 return []
|
jpayne@68
|
1206
|
jpayne@68
|
1207 return [os.path.join(self.si.WindowsSdkDir, 'Setup')]
|
jpayne@68
|
1208
|
jpayne@68
|
1209 @property
|
jpayne@68
|
1210 def FxTools(self):
|
jpayne@68
|
1211 """
|
jpayne@68
|
1212 Microsoft .NET Framework Tools.
|
jpayne@68
|
1213
|
jpayne@68
|
1214 Return
|
jpayne@68
|
1215 ------
|
jpayne@68
|
1216 list of str
|
jpayne@68
|
1217 paths
|
jpayne@68
|
1218 """
|
jpayne@68
|
1219 pi = self.pi
|
jpayne@68
|
1220 si = self.si
|
jpayne@68
|
1221
|
jpayne@68
|
1222 if self.vs_ver <= 10.0:
|
jpayne@68
|
1223 include32 = True
|
jpayne@68
|
1224 include64 = not pi.target_is_x86() and not pi.current_is_x86()
|
jpayne@68
|
1225 else:
|
jpayne@68
|
1226 include32 = pi.target_is_x86() or pi.current_is_x86()
|
jpayne@68
|
1227 include64 = pi.current_cpu == 'amd64' or pi.target_cpu == 'amd64'
|
jpayne@68
|
1228
|
jpayne@68
|
1229 tools = []
|
jpayne@68
|
1230 if include32:
|
jpayne@68
|
1231 tools += [
|
jpayne@68
|
1232 os.path.join(si.FrameworkDir32, ver) for ver in si.FrameworkVersion32
|
jpayne@68
|
1233 ]
|
jpayne@68
|
1234 if include64:
|
jpayne@68
|
1235 tools += [
|
jpayne@68
|
1236 os.path.join(si.FrameworkDir64, ver) for ver in si.FrameworkVersion64
|
jpayne@68
|
1237 ]
|
jpayne@68
|
1238 return tools
|
jpayne@68
|
1239
|
jpayne@68
|
1240 @property
|
jpayne@68
|
1241 def NetFxSDKLibraries(self):
|
jpayne@68
|
1242 """
|
jpayne@68
|
1243 Microsoft .Net Framework SDK Libraries.
|
jpayne@68
|
1244
|
jpayne@68
|
1245 Return
|
jpayne@68
|
1246 ------
|
jpayne@68
|
1247 list of str
|
jpayne@68
|
1248 paths
|
jpayne@68
|
1249 """
|
jpayne@68
|
1250 if self.vs_ver < 14.0 or not self.si.NetFxSdkDir:
|
jpayne@68
|
1251 return []
|
jpayne@68
|
1252
|
jpayne@68
|
1253 arch_subdir = self.pi.target_dir(x64=True)
|
jpayne@68
|
1254 return [os.path.join(self.si.NetFxSdkDir, r'lib\um%s' % arch_subdir)]
|
jpayne@68
|
1255
|
jpayne@68
|
1256 @property
|
jpayne@68
|
1257 def NetFxSDKIncludes(self):
|
jpayne@68
|
1258 """
|
jpayne@68
|
1259 Microsoft .Net Framework SDK Includes.
|
jpayne@68
|
1260
|
jpayne@68
|
1261 Return
|
jpayne@68
|
1262 ------
|
jpayne@68
|
1263 list of str
|
jpayne@68
|
1264 paths
|
jpayne@68
|
1265 """
|
jpayne@68
|
1266 if self.vs_ver < 14.0 or not self.si.NetFxSdkDir:
|
jpayne@68
|
1267 return []
|
jpayne@68
|
1268
|
jpayne@68
|
1269 return [os.path.join(self.si.NetFxSdkDir, r'include\um')]
|
jpayne@68
|
1270
|
jpayne@68
|
1271 @property
|
jpayne@68
|
1272 def VsTDb(self):
|
jpayne@68
|
1273 """
|
jpayne@68
|
1274 Microsoft Visual Studio Team System Database.
|
jpayne@68
|
1275
|
jpayne@68
|
1276 Return
|
jpayne@68
|
1277 ------
|
jpayne@68
|
1278 list of str
|
jpayne@68
|
1279 paths
|
jpayne@68
|
1280 """
|
jpayne@68
|
1281 return [os.path.join(self.si.VSInstallDir, r'VSTSDB\Deploy')]
|
jpayne@68
|
1282
|
jpayne@68
|
1283 @property
|
jpayne@68
|
1284 def MSBuild(self):
|
jpayne@68
|
1285 """
|
jpayne@68
|
1286 Microsoft Build Engine.
|
jpayne@68
|
1287
|
jpayne@68
|
1288 Return
|
jpayne@68
|
1289 ------
|
jpayne@68
|
1290 list of str
|
jpayne@68
|
1291 paths
|
jpayne@68
|
1292 """
|
jpayne@68
|
1293 if self.vs_ver < 12.0:
|
jpayne@68
|
1294 return []
|
jpayne@68
|
1295 elif self.vs_ver < 15.0:
|
jpayne@68
|
1296 base_path = self.si.ProgramFilesx86
|
jpayne@68
|
1297 arch_subdir = self.pi.current_dir(hidex86=True)
|
jpayne@68
|
1298 else:
|
jpayne@68
|
1299 base_path = self.si.VSInstallDir
|
jpayne@68
|
1300 arch_subdir = ''
|
jpayne@68
|
1301
|
jpayne@68
|
1302 path = r'MSBuild\%0.1f\bin%s' % (self.vs_ver, arch_subdir)
|
jpayne@68
|
1303 build = [os.path.join(base_path, path)]
|
jpayne@68
|
1304
|
jpayne@68
|
1305 if self.vs_ver >= 15.0:
|
jpayne@68
|
1306 # Add Roslyn C# & Visual Basic Compiler
|
jpayne@68
|
1307 build += [os.path.join(base_path, path, 'Roslyn')]
|
jpayne@68
|
1308
|
jpayne@68
|
1309 return build
|
jpayne@68
|
1310
|
jpayne@68
|
1311 @property
|
jpayne@68
|
1312 def HTMLHelpWorkshop(self):
|
jpayne@68
|
1313 """
|
jpayne@68
|
1314 Microsoft HTML Help Workshop.
|
jpayne@68
|
1315
|
jpayne@68
|
1316 Return
|
jpayne@68
|
1317 ------
|
jpayne@68
|
1318 list of str
|
jpayne@68
|
1319 paths
|
jpayne@68
|
1320 """
|
jpayne@68
|
1321 if self.vs_ver < 11.0:
|
jpayne@68
|
1322 return []
|
jpayne@68
|
1323
|
jpayne@68
|
1324 return [os.path.join(self.si.ProgramFilesx86, 'HTML Help Workshop')]
|
jpayne@68
|
1325
|
jpayne@68
|
1326 @property
|
jpayne@68
|
1327 def UCRTLibraries(self):
|
jpayne@68
|
1328 """
|
jpayne@68
|
1329 Microsoft Universal C Runtime SDK Libraries.
|
jpayne@68
|
1330
|
jpayne@68
|
1331 Return
|
jpayne@68
|
1332 ------
|
jpayne@68
|
1333 list of str
|
jpayne@68
|
1334 paths
|
jpayne@68
|
1335 """
|
jpayne@68
|
1336 if self.vs_ver < 14.0:
|
jpayne@68
|
1337 return []
|
jpayne@68
|
1338
|
jpayne@68
|
1339 arch_subdir = self.pi.target_dir(x64=True)
|
jpayne@68
|
1340 lib = os.path.join(self.si.UniversalCRTSdkDir, 'lib')
|
jpayne@68
|
1341 ucrtver = self._ucrt_subdir
|
jpayne@68
|
1342 return [os.path.join(lib, '%sucrt%s' % (ucrtver, arch_subdir))]
|
jpayne@68
|
1343
|
jpayne@68
|
1344 @property
|
jpayne@68
|
1345 def UCRTIncludes(self):
|
jpayne@68
|
1346 """
|
jpayne@68
|
1347 Microsoft Universal C Runtime SDK Include.
|
jpayne@68
|
1348
|
jpayne@68
|
1349 Return
|
jpayne@68
|
1350 ------
|
jpayne@68
|
1351 list of str
|
jpayne@68
|
1352 paths
|
jpayne@68
|
1353 """
|
jpayne@68
|
1354 if self.vs_ver < 14.0:
|
jpayne@68
|
1355 return []
|
jpayne@68
|
1356
|
jpayne@68
|
1357 include = os.path.join(self.si.UniversalCRTSdkDir, 'include')
|
jpayne@68
|
1358 return [os.path.join(include, '%sucrt' % self._ucrt_subdir)]
|
jpayne@68
|
1359
|
jpayne@68
|
1360 @property
|
jpayne@68
|
1361 def _ucrt_subdir(self):
|
jpayne@68
|
1362 """
|
jpayne@68
|
1363 Microsoft Universal C Runtime SDK version subdir.
|
jpayne@68
|
1364
|
jpayne@68
|
1365 Return
|
jpayne@68
|
1366 ------
|
jpayne@68
|
1367 str
|
jpayne@68
|
1368 subdir
|
jpayne@68
|
1369 """
|
jpayne@68
|
1370 ucrtver = self.si.UniversalCRTSdkLastVersion
|
jpayne@68
|
1371 return ('%s\\' % ucrtver) if ucrtver else ''
|
jpayne@68
|
1372
|
jpayne@68
|
1373 @property
|
jpayne@68
|
1374 def FSharp(self):
|
jpayne@68
|
1375 """
|
jpayne@68
|
1376 Microsoft Visual F#.
|
jpayne@68
|
1377
|
jpayne@68
|
1378 Return
|
jpayne@68
|
1379 ------
|
jpayne@68
|
1380 list of str
|
jpayne@68
|
1381 paths
|
jpayne@68
|
1382 """
|
jpayne@68
|
1383 if 11.0 > self.vs_ver > 12.0:
|
jpayne@68
|
1384 return []
|
jpayne@68
|
1385
|
jpayne@68
|
1386 return [self.si.FSharpInstallDir]
|
jpayne@68
|
1387
|
jpayne@68
|
1388 @property
|
jpayne@68
|
1389 def VCRuntimeRedist(self) -> str | None:
|
jpayne@68
|
1390 """
|
jpayne@68
|
1391 Microsoft Visual C++ runtime redistributable dll.
|
jpayne@68
|
1392
|
jpayne@68
|
1393 Returns the first suitable path found or None.
|
jpayne@68
|
1394 """
|
jpayne@68
|
1395 vcruntime = 'vcruntime%d0.dll' % self.vc_ver
|
jpayne@68
|
1396 arch_subdir = self.pi.target_dir(x64=True).strip('\\')
|
jpayne@68
|
1397
|
jpayne@68
|
1398 # Installation prefixes candidates
|
jpayne@68
|
1399 prefixes = []
|
jpayne@68
|
1400 tools_path = self.si.VCInstallDir
|
jpayne@68
|
1401 redist_path = os.path.dirname(tools_path.replace(r'\Tools', r'\Redist'))
|
jpayne@68
|
1402 if os.path.isdir(redist_path):
|
jpayne@68
|
1403 # Redist version may not be exactly the same as tools
|
jpayne@68
|
1404 redist_path = os.path.join(redist_path, os.listdir(redist_path)[-1])
|
jpayne@68
|
1405 prefixes += [redist_path, os.path.join(redist_path, 'onecore')]
|
jpayne@68
|
1406
|
jpayne@68
|
1407 prefixes += [os.path.join(tools_path, 'redist')] # VS14 legacy path
|
jpayne@68
|
1408
|
jpayne@68
|
1409 # CRT directory
|
jpayne@68
|
1410 crt_dirs = (
|
jpayne@68
|
1411 'Microsoft.VC%d.CRT' % (self.vc_ver * 10),
|
jpayne@68
|
1412 # Sometime store in directory with VS version instead of VC
|
jpayne@68
|
1413 'Microsoft.VC%d.CRT' % (int(self.vs_ver) * 10),
|
jpayne@68
|
1414 )
|
jpayne@68
|
1415
|
jpayne@68
|
1416 # vcruntime path
|
jpayne@68
|
1417 candidate_paths = (
|
jpayne@68
|
1418 os.path.join(prefix, arch_subdir, crt_dir, vcruntime)
|
jpayne@68
|
1419 for (prefix, crt_dir) in itertools.product(prefixes, crt_dirs)
|
jpayne@68
|
1420 )
|
jpayne@68
|
1421 return next(filter(os.path.isfile, candidate_paths), None) # type: ignore[arg-type] #python/mypy#12682
|
jpayne@68
|
1422
|
jpayne@68
|
1423 def return_env(self, exists=True):
|
jpayne@68
|
1424 """
|
jpayne@68
|
1425 Return environment dict.
|
jpayne@68
|
1426
|
jpayne@68
|
1427 Parameters
|
jpayne@68
|
1428 ----------
|
jpayne@68
|
1429 exists: bool
|
jpayne@68
|
1430 It True, only return existing paths.
|
jpayne@68
|
1431
|
jpayne@68
|
1432 Return
|
jpayne@68
|
1433 ------
|
jpayne@68
|
1434 dict
|
jpayne@68
|
1435 environment
|
jpayne@68
|
1436 """
|
jpayne@68
|
1437 env = dict(
|
jpayne@68
|
1438 include=self._build_paths(
|
jpayne@68
|
1439 'include',
|
jpayne@68
|
1440 [
|
jpayne@68
|
1441 self.VCIncludes,
|
jpayne@68
|
1442 self.OSIncludes,
|
jpayne@68
|
1443 self.UCRTIncludes,
|
jpayne@68
|
1444 self.NetFxSDKIncludes,
|
jpayne@68
|
1445 ],
|
jpayne@68
|
1446 exists,
|
jpayne@68
|
1447 ),
|
jpayne@68
|
1448 lib=self._build_paths(
|
jpayne@68
|
1449 'lib',
|
jpayne@68
|
1450 [
|
jpayne@68
|
1451 self.VCLibraries,
|
jpayne@68
|
1452 self.OSLibraries,
|
jpayne@68
|
1453 self.FxTools,
|
jpayne@68
|
1454 self.UCRTLibraries,
|
jpayne@68
|
1455 self.NetFxSDKLibraries,
|
jpayne@68
|
1456 ],
|
jpayne@68
|
1457 exists,
|
jpayne@68
|
1458 ),
|
jpayne@68
|
1459 libpath=self._build_paths(
|
jpayne@68
|
1460 'libpath',
|
jpayne@68
|
1461 [self.VCLibraries, self.FxTools, self.VCStoreRefs, self.OSLibpath],
|
jpayne@68
|
1462 exists,
|
jpayne@68
|
1463 ),
|
jpayne@68
|
1464 path=self._build_paths(
|
jpayne@68
|
1465 'path',
|
jpayne@68
|
1466 [
|
jpayne@68
|
1467 self.VCTools,
|
jpayne@68
|
1468 self.VSTools,
|
jpayne@68
|
1469 self.VsTDb,
|
jpayne@68
|
1470 self.SdkTools,
|
jpayne@68
|
1471 self.SdkSetup,
|
jpayne@68
|
1472 self.FxTools,
|
jpayne@68
|
1473 self.MSBuild,
|
jpayne@68
|
1474 self.HTMLHelpWorkshop,
|
jpayne@68
|
1475 self.FSharp,
|
jpayne@68
|
1476 ],
|
jpayne@68
|
1477 exists,
|
jpayne@68
|
1478 ),
|
jpayne@68
|
1479 )
|
jpayne@68
|
1480 if self.vs_ver >= 14 and self.VCRuntimeRedist:
|
jpayne@68
|
1481 env['py_vcruntime_redist'] = self.VCRuntimeRedist
|
jpayne@68
|
1482 return env
|
jpayne@68
|
1483
|
jpayne@68
|
1484 def _build_paths(self, name, spec_path_lists, exists):
|
jpayne@68
|
1485 """
|
jpayne@68
|
1486 Given an environment variable name and specified paths,
|
jpayne@68
|
1487 return a pathsep-separated string of paths containing
|
jpayne@68
|
1488 unique, extant, directories from those paths and from
|
jpayne@68
|
1489 the environment variable. Raise an error if no paths
|
jpayne@68
|
1490 are resolved.
|
jpayne@68
|
1491
|
jpayne@68
|
1492 Parameters
|
jpayne@68
|
1493 ----------
|
jpayne@68
|
1494 name: str
|
jpayne@68
|
1495 Environment variable name
|
jpayne@68
|
1496 spec_path_lists: list of str
|
jpayne@68
|
1497 Paths
|
jpayne@68
|
1498 exists: bool
|
jpayne@68
|
1499 It True, only return existing paths.
|
jpayne@68
|
1500
|
jpayne@68
|
1501 Return
|
jpayne@68
|
1502 ------
|
jpayne@68
|
1503 str
|
jpayne@68
|
1504 Pathsep-separated paths
|
jpayne@68
|
1505 """
|
jpayne@68
|
1506 # flatten spec_path_lists
|
jpayne@68
|
1507 spec_paths = itertools.chain.from_iterable(spec_path_lists)
|
jpayne@68
|
1508 env_paths = environ.get(name, '').split(os.pathsep)
|
jpayne@68
|
1509 paths = itertools.chain(spec_paths, env_paths)
|
jpayne@68
|
1510 extant_paths = list(filter(os.path.isdir, paths)) if exists else paths
|
jpayne@68
|
1511 if not extant_paths:
|
jpayne@68
|
1512 msg = "%s environment variable is empty" % name.upper()
|
jpayne@68
|
1513 raise distutils.errors.DistutilsPlatformError(msg)
|
jpayne@68
|
1514 unique_paths = unique_everseen(extant_paths)
|
jpayne@68
|
1515 return os.pathsep.join(unique_paths)
|