Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
keewenaw
GitHub Repository: keewenaw/ethereum-wallet-cracker
Path: blob/main/test/lib/python3.9/site-packages/setuptools/msvc.py
4798 views
1
"""
2
Improved support for Microsoft Visual C++ compilers.
3
4
Known supported compilers:
5
--------------------------
6
Microsoft Visual C++ 9.0:
7
Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64)
8
Microsoft Windows SDK 6.1 (x86, x64, ia64)
9
Microsoft Windows SDK 7.0 (x86, x64, ia64)
10
11
Microsoft Visual C++ 10.0:
12
Microsoft Windows SDK 7.1 (x86, x64, ia64)
13
14
Microsoft Visual C++ 14.X:
15
Microsoft Visual C++ Build Tools 2015 (x86, x64, arm)
16
Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64)
17
Microsoft Visual Studio Build Tools 2019 (x86, x64, arm, arm64)
18
19
This may also support compilers shipped with compatible Visual Studio versions.
20
"""
21
22
import json
23
from io import open
24
from os import listdir, pathsep
25
from os.path import join, isfile, isdir, dirname
26
import sys
27
import contextlib
28
import platform
29
import itertools
30
import subprocess
31
import distutils.errors
32
from setuptools.extern.packaging.version import LegacyVersion
33
from setuptools.extern.more_itertools import unique_everseen
34
35
from .monkey import get_unpatched
36
37
if platform.system() == 'Windows':
38
import winreg
39
from os import environ
40
else:
41
# Mock winreg and environ so the module can be imported on this platform.
42
43
class winreg:
44
HKEY_USERS = None
45
HKEY_CURRENT_USER = None
46
HKEY_LOCAL_MACHINE = None
47
HKEY_CLASSES_ROOT = None
48
49
environ = dict()
50
51
_msvc9_suppress_errors = (
52
# msvc9compiler isn't available on some platforms
53
ImportError,
54
55
# msvc9compiler raises DistutilsPlatformError in some
56
# environments. See #1118.
57
distutils.errors.DistutilsPlatformError,
58
)
59
60
try:
61
from distutils.msvc9compiler import Reg
62
except _msvc9_suppress_errors:
63
pass
64
65
66
def msvc9_find_vcvarsall(version):
67
"""
68
Patched "distutils.msvc9compiler.find_vcvarsall" to use the standalone
69
compiler build for Python
70
(VCForPython / Microsoft Visual C++ Compiler for Python 2.7).
71
72
Fall back to original behavior when the standalone compiler is not
73
available.
74
75
Redirect the path of "vcvarsall.bat".
76
77
Parameters
78
----------
79
version: float
80
Required Microsoft Visual C++ version.
81
82
Return
83
------
84
str
85
vcvarsall.bat path
86
"""
87
vc_base = r'Software\%sMicrosoft\DevDiv\VCForPython\%0.1f'
88
key = vc_base % ('', version)
89
try:
90
# Per-user installs register the compiler path here
91
productdir = Reg.get_value(key, "installdir")
92
except KeyError:
93
try:
94
# All-user installs on a 64-bit system register here
95
key = vc_base % ('Wow6432Node\\', version)
96
productdir = Reg.get_value(key, "installdir")
97
except KeyError:
98
productdir = None
99
100
if productdir:
101
vcvarsall = join(productdir, "vcvarsall.bat")
102
if isfile(vcvarsall):
103
return vcvarsall
104
105
return get_unpatched(msvc9_find_vcvarsall)(version)
106
107
108
def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs):
109
"""
110
Patched "distutils.msvc9compiler.query_vcvarsall" for support extra
111
Microsoft Visual C++ 9.0 and 10.0 compilers.
112
113
Set environment without use of "vcvarsall.bat".
114
115
Parameters
116
----------
117
ver: float
118
Required Microsoft Visual C++ version.
119
arch: str
120
Target architecture.
121
122
Return
123
------
124
dict
125
environment
126
"""
127
# Try to get environment from vcvarsall.bat (Classical way)
128
try:
129
orig = get_unpatched(msvc9_query_vcvarsall)
130
return orig(ver, arch, *args, **kwargs)
131
except distutils.errors.DistutilsPlatformError:
132
# Pass error if Vcvarsall.bat is missing
133
pass
134
except ValueError:
135
# Pass error if environment not set after executing vcvarsall.bat
136
pass
137
138
# If error, try to set environment directly
139
try:
140
return EnvironmentInfo(arch, ver).return_env()
141
except distutils.errors.DistutilsPlatformError as exc:
142
_augment_exception(exc, ver, arch)
143
raise
144
145
146
def _msvc14_find_vc2015():
147
"""Python 3.8 "distutils/_msvccompiler.py" backport"""
148
try:
149
key = winreg.OpenKey(
150
winreg.HKEY_LOCAL_MACHINE,
151
r"Software\Microsoft\VisualStudio\SxS\VC7",
152
0,
153
winreg.KEY_READ | winreg.KEY_WOW64_32KEY
154
)
155
except OSError:
156
return None, None
157
158
best_version = 0
159
best_dir = None
160
with key:
161
for i in itertools.count():
162
try:
163
v, vc_dir, vt = winreg.EnumValue(key, i)
164
except OSError:
165
break
166
if v and vt == winreg.REG_SZ and isdir(vc_dir):
167
try:
168
version = int(float(v))
169
except (ValueError, TypeError):
170
continue
171
if version >= 14 and version > best_version:
172
best_version, best_dir = version, vc_dir
173
return best_version, best_dir
174
175
176
def _msvc14_find_vc2017():
177
"""Python 3.8 "distutils/_msvccompiler.py" backport
178
179
Returns "15, path" based on the result of invoking vswhere.exe
180
If no install is found, returns "None, None"
181
182
The version is returned to avoid unnecessarily changing the function
183
result. It may be ignored when the path is not None.
184
185
If vswhere.exe is not available, by definition, VS 2017 is not
186
installed.
187
"""
188
root = environ.get("ProgramFiles(x86)") or environ.get("ProgramFiles")
189
if not root:
190
return None, None
191
192
try:
193
path = subprocess.check_output([
194
join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"),
195
"-latest",
196
"-prerelease",
197
"-requiresAny",
198
"-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
199
"-requires", "Microsoft.VisualStudio.Workload.WDExpress",
200
"-property", "installationPath",
201
"-products", "*",
202
]).decode(encoding="mbcs", errors="strict").strip()
203
except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):
204
return None, None
205
206
path = join(path, "VC", "Auxiliary", "Build")
207
if isdir(path):
208
return 15, path
209
210
return None, None
211
212
213
PLAT_SPEC_TO_RUNTIME = {
214
'x86': 'x86',
215
'x86_amd64': 'x64',
216
'x86_arm': 'arm',
217
'x86_arm64': 'arm64'
218
}
219
220
221
def _msvc14_find_vcvarsall(plat_spec):
222
"""Python 3.8 "distutils/_msvccompiler.py" backport"""
223
_, best_dir = _msvc14_find_vc2017()
224
vcruntime = None
225
226
if plat_spec in PLAT_SPEC_TO_RUNTIME:
227
vcruntime_plat = PLAT_SPEC_TO_RUNTIME[plat_spec]
228
else:
229
vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86'
230
231
if best_dir:
232
vcredist = join(best_dir, "..", "..", "redist", "MSVC", "**",
233
vcruntime_plat, "Microsoft.VC14*.CRT",
234
"vcruntime140.dll")
235
try:
236
import glob
237
vcruntime = glob.glob(vcredist, recursive=True)[-1]
238
except (ImportError, OSError, LookupError):
239
vcruntime = None
240
241
if not best_dir:
242
best_version, best_dir = _msvc14_find_vc2015()
243
if best_version:
244
vcruntime = join(best_dir, 'redist', vcruntime_plat,
245
"Microsoft.VC140.CRT", "vcruntime140.dll")
246
247
if not best_dir:
248
return None, None
249
250
vcvarsall = join(best_dir, "vcvarsall.bat")
251
if not isfile(vcvarsall):
252
return None, None
253
254
if not vcruntime or not isfile(vcruntime):
255
vcruntime = None
256
257
return vcvarsall, vcruntime
258
259
260
def _msvc14_get_vc_env(plat_spec):
261
"""Python 3.8 "distutils/_msvccompiler.py" backport"""
262
if "DISTUTILS_USE_SDK" in environ:
263
return {
264
key.lower(): value
265
for key, value in environ.items()
266
}
267
268
vcvarsall, vcruntime = _msvc14_find_vcvarsall(plat_spec)
269
if not vcvarsall:
270
raise distutils.errors.DistutilsPlatformError(
271
"Unable to find vcvarsall.bat"
272
)
273
274
try:
275
out = subprocess.check_output(
276
'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec),
277
stderr=subprocess.STDOUT,
278
).decode('utf-16le', errors='replace')
279
except subprocess.CalledProcessError as exc:
280
raise distutils.errors.DistutilsPlatformError(
281
"Error executing {}".format(exc.cmd)
282
) from exc
283
284
env = {
285
key.lower(): value
286
for key, _, value in
287
(line.partition('=') for line in out.splitlines())
288
if key and value
289
}
290
291
if vcruntime:
292
env['py_vcruntime_redist'] = vcruntime
293
return env
294
295
296
def msvc14_get_vc_env(plat_spec):
297
"""
298
Patched "distutils._msvccompiler._get_vc_env" for support extra
299
Microsoft Visual C++ 14.X compilers.
300
301
Set environment without use of "vcvarsall.bat".
302
303
Parameters
304
----------
305
plat_spec: str
306
Target architecture.
307
308
Return
309
------
310
dict
311
environment
312
"""
313
314
# Always use backport from CPython 3.8
315
try:
316
return _msvc14_get_vc_env(plat_spec)
317
except distutils.errors.DistutilsPlatformError as exc:
318
_augment_exception(exc, 14.0)
319
raise
320
321
322
def msvc14_gen_lib_options(*args, **kwargs):
323
"""
324
Patched "distutils._msvccompiler.gen_lib_options" for fix
325
compatibility between "numpy.distutils" and "distutils._msvccompiler"
326
(for Numpy < 1.11.2)
327
"""
328
if "numpy.distutils" in sys.modules:
329
import numpy as np
330
if LegacyVersion(np.__version__) < LegacyVersion('1.11.2'):
331
return np.distutils.ccompiler.gen_lib_options(*args, **kwargs)
332
return get_unpatched(msvc14_gen_lib_options)(*args, **kwargs)
333
334
335
def _augment_exception(exc, version, arch=''):
336
"""
337
Add details to the exception message to help guide the user
338
as to what action will resolve it.
339
"""
340
# Error if MSVC++ directory not found or environment not set
341
message = exc.args[0]
342
343
if "vcvarsall" in message.lower() or "visual c" in message.lower():
344
# Special error message if MSVC++ not installed
345
tmpl = 'Microsoft Visual C++ {version:0.1f} or greater is required.'
346
message = tmpl.format(**locals())
347
msdownload = 'www.microsoft.com/download/details.aspx?id=%d'
348
if version == 9.0:
349
if arch.lower().find('ia64') > -1:
350
# For VC++ 9.0, if IA64 support is needed, redirect user
351
# to Windows SDK 7.0.
352
# Note: No download link available from Microsoft.
353
message += ' Get it with "Microsoft Windows SDK 7.0"'
354
else:
355
# For VC++ 9.0 redirect user to Vc++ for Python 2.7 :
356
# This redirection link is maintained by Microsoft.
357
# Contact [email protected] if it needs updating.
358
message += ' Get it from http://aka.ms/vcpython27'
359
elif version == 10.0:
360
# For VC++ 10.0 Redirect user to Windows SDK 7.1
361
message += ' Get it with "Microsoft Windows SDK 7.1": '
362
message += msdownload % 8279
363
elif version >= 14.0:
364
# For VC++ 14.X Redirect user to latest Visual C++ Build Tools
365
message += (' Get it with "Microsoft C++ Build Tools": '
366
r'https://visualstudio.microsoft.com'
367
r'/visual-cpp-build-tools/')
368
369
exc.args = (message, )
370
371
372
class PlatformInfo:
373
"""
374
Current and Target Architectures information.
375
376
Parameters
377
----------
378
arch: str
379
Target architecture.
380
"""
381
current_cpu = environ.get('processor_architecture', '').lower()
382
383
def __init__(self, arch):
384
self.arch = arch.lower().replace('x64', 'amd64')
385
386
@property
387
def target_cpu(self):
388
"""
389
Return Target CPU architecture.
390
391
Return
392
------
393
str
394
Target CPU
395
"""
396
return self.arch[self.arch.find('_') + 1:]
397
398
def target_is_x86(self):
399
"""
400
Return True if target CPU is x86 32 bits..
401
402
Return
403
------
404
bool
405
CPU is x86 32 bits
406
"""
407
return self.target_cpu == 'x86'
408
409
def current_is_x86(self):
410
"""
411
Return True if current CPU is x86 32 bits..
412
413
Return
414
------
415
bool
416
CPU is x86 32 bits
417
"""
418
return self.current_cpu == 'x86'
419
420
def current_dir(self, hidex86=False, x64=False):
421
"""
422
Current platform specific subfolder.
423
424
Parameters
425
----------
426
hidex86: bool
427
return '' and not '\x86' if architecture is x86.
428
x64: bool
429
return '\x64' and not '\amd64' if architecture is amd64.
430
431
Return
432
------
433
str
434
subfolder: '\target', or '' (see hidex86 parameter)
435
"""
436
return (
437
'' if (self.current_cpu == 'x86' and hidex86) else
438
r'\x64' if (self.current_cpu == 'amd64' and x64) else
439
r'\%s' % self.current_cpu
440
)
441
442
def target_dir(self, hidex86=False, x64=False):
443
r"""
444
Target platform specific subfolder.
445
446
Parameters
447
----------
448
hidex86: bool
449
return '' and not '\x86' if architecture is x86.
450
x64: bool
451
return '\x64' and not '\amd64' if architecture is amd64.
452
453
Return
454
------
455
str
456
subfolder: '\current', or '' (see hidex86 parameter)
457
"""
458
return (
459
'' if (self.target_cpu == 'x86' and hidex86) else
460
r'\x64' if (self.target_cpu == 'amd64' and x64) else
461
r'\%s' % self.target_cpu
462
)
463
464
def cross_dir(self, forcex86=False):
465
r"""
466
Cross platform specific subfolder.
467
468
Parameters
469
----------
470
forcex86: bool
471
Use 'x86' as current architecture even if current architecture is
472
not x86.
473
474
Return
475
------
476
str
477
subfolder: '' if target architecture is current architecture,
478
'\current_target' if not.
479
"""
480
current = 'x86' if forcex86 else self.current_cpu
481
return (
482
'' if self.target_cpu == current else
483
self.target_dir().replace('\\', '\\%s_' % current)
484
)
485
486
487
class RegistryInfo:
488
"""
489
Microsoft Visual Studio related registry information.
490
491
Parameters
492
----------
493
platform_info: PlatformInfo
494
"PlatformInfo" instance.
495
"""
496
HKEYS = (winreg.HKEY_USERS,
497
winreg.HKEY_CURRENT_USER,
498
winreg.HKEY_LOCAL_MACHINE,
499
winreg.HKEY_CLASSES_ROOT)
500
501
def __init__(self, platform_info):
502
self.pi = platform_info
503
504
@property
505
def visualstudio(self):
506
"""
507
Microsoft Visual Studio root registry key.
508
509
Return
510
------
511
str
512
Registry key
513
"""
514
return 'VisualStudio'
515
516
@property
517
def sxs(self):
518
"""
519
Microsoft Visual Studio SxS registry key.
520
521
Return
522
------
523
str
524
Registry key
525
"""
526
return join(self.visualstudio, 'SxS')
527
528
@property
529
def vc(self):
530
"""
531
Microsoft Visual C++ VC7 registry key.
532
533
Return
534
------
535
str
536
Registry key
537
"""
538
return join(self.sxs, 'VC7')
539
540
@property
541
def vs(self):
542
"""
543
Microsoft Visual Studio VS7 registry key.
544
545
Return
546
------
547
str
548
Registry key
549
"""
550
return join(self.sxs, 'VS7')
551
552
@property
553
def vc_for_python(self):
554
"""
555
Microsoft Visual C++ for Python registry key.
556
557
Return
558
------
559
str
560
Registry key
561
"""
562
return r'DevDiv\VCForPython'
563
564
@property
565
def microsoft_sdk(self):
566
"""
567
Microsoft SDK registry key.
568
569
Return
570
------
571
str
572
Registry key
573
"""
574
return 'Microsoft SDKs'
575
576
@property
577
def windows_sdk(self):
578
"""
579
Microsoft Windows/Platform SDK registry key.
580
581
Return
582
------
583
str
584
Registry key
585
"""
586
return join(self.microsoft_sdk, 'Windows')
587
588
@property
589
def netfx_sdk(self):
590
"""
591
Microsoft .NET Framework SDK registry key.
592
593
Return
594
------
595
str
596
Registry key
597
"""
598
return join(self.microsoft_sdk, 'NETFXSDK')
599
600
@property
601
def windows_kits_roots(self):
602
"""
603
Microsoft Windows Kits Roots registry key.
604
605
Return
606
------
607
str
608
Registry key
609
"""
610
return r'Windows Kits\Installed Roots'
611
612
def microsoft(self, key, x86=False):
613
"""
614
Return key in Microsoft software registry.
615
616
Parameters
617
----------
618
key: str
619
Registry key path where look.
620
x86: str
621
Force x86 software registry.
622
623
Return
624
------
625
str
626
Registry key
627
"""
628
node64 = '' if self.pi.current_is_x86() or x86 else 'Wow6432Node'
629
return join('Software', node64, 'Microsoft', key)
630
631
def lookup(self, key, name):
632
"""
633
Look for values in registry in Microsoft software registry.
634
635
Parameters
636
----------
637
key: str
638
Registry key path where look.
639
name: str
640
Value name to find.
641
642
Return
643
------
644
str
645
value
646
"""
647
key_read = winreg.KEY_READ
648
openkey = winreg.OpenKey
649
closekey = winreg.CloseKey
650
ms = self.microsoft
651
for hkey in self.HKEYS:
652
bkey = None
653
try:
654
bkey = openkey(hkey, ms(key), 0, key_read)
655
except (OSError, IOError):
656
if not self.pi.current_is_x86():
657
try:
658
bkey = openkey(hkey, ms(key, True), 0, key_read)
659
except (OSError, IOError):
660
continue
661
else:
662
continue
663
try:
664
return winreg.QueryValueEx(bkey, name)[0]
665
except (OSError, IOError):
666
pass
667
finally:
668
if bkey:
669
closekey(bkey)
670
671
672
class SystemInfo:
673
"""
674
Microsoft Windows and Visual Studio related system information.
675
676
Parameters
677
----------
678
registry_info: RegistryInfo
679
"RegistryInfo" instance.
680
vc_ver: float
681
Required Microsoft Visual C++ version.
682
"""
683
684
# Variables and properties in this class use originals CamelCase variables
685
# names from Microsoft source files for more easy comparison.
686
WinDir = environ.get('WinDir', '')
687
ProgramFiles = environ.get('ProgramFiles', '')
688
ProgramFilesx86 = environ.get('ProgramFiles(x86)', ProgramFiles)
689
690
def __init__(self, registry_info, vc_ver=None):
691
self.ri = registry_info
692
self.pi = self.ri.pi
693
694
self.known_vs_paths = self.find_programdata_vs_vers()
695
696
# Except for VS15+, VC version is aligned with VS version
697
self.vs_ver = self.vc_ver = (
698
vc_ver or self._find_latest_available_vs_ver())
699
700
def _find_latest_available_vs_ver(self):
701
"""
702
Find the latest VC version
703
704
Return
705
------
706
float
707
version
708
"""
709
reg_vc_vers = self.find_reg_vs_vers()
710
711
if not (reg_vc_vers or self.known_vs_paths):
712
raise distutils.errors.DistutilsPlatformError(
713
'No Microsoft Visual C++ version found')
714
715
vc_vers = set(reg_vc_vers)
716
vc_vers.update(self.known_vs_paths)
717
return sorted(vc_vers)[-1]
718
719
def find_reg_vs_vers(self):
720
"""
721
Find Microsoft Visual Studio versions available in registry.
722
723
Return
724
------
725
list of float
726
Versions
727
"""
728
ms = self.ri.microsoft
729
vckeys = (self.ri.vc, self.ri.vc_for_python, self.ri.vs)
730
vs_vers = []
731
for hkey, key in itertools.product(self.ri.HKEYS, vckeys):
732
try:
733
bkey = winreg.OpenKey(hkey, ms(key), 0, winreg.KEY_READ)
734
except (OSError, IOError):
735
continue
736
with bkey:
737
subkeys, values, _ = winreg.QueryInfoKey(bkey)
738
for i in range(values):
739
with contextlib.suppress(ValueError):
740
ver = float(winreg.EnumValue(bkey, i)[0])
741
if ver not in vs_vers:
742
vs_vers.append(ver)
743
for i in range(subkeys):
744
with contextlib.suppress(ValueError):
745
ver = float(winreg.EnumKey(bkey, i))
746
if ver not in vs_vers:
747
vs_vers.append(ver)
748
return sorted(vs_vers)
749
750
def find_programdata_vs_vers(self):
751
r"""
752
Find Visual studio 2017+ versions from information in
753
"C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances".
754
755
Return
756
------
757
dict
758
float version as key, path as value.
759
"""
760
vs_versions = {}
761
instances_dir = \
762
r'C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances'
763
764
try:
765
hashed_names = listdir(instances_dir)
766
767
except (OSError, IOError):
768
# Directory not exists with all Visual Studio versions
769
return vs_versions
770
771
for name in hashed_names:
772
try:
773
# Get VS installation path from "state.json" file
774
state_path = join(instances_dir, name, 'state.json')
775
with open(state_path, 'rt', encoding='utf-8') as state_file:
776
state = json.load(state_file)
777
vs_path = state['installationPath']
778
779
# Raises OSError if this VS installation does not contain VC
780
listdir(join(vs_path, r'VC\Tools\MSVC'))
781
782
# Store version and path
783
vs_versions[self._as_float_version(
784
state['installationVersion'])] = vs_path
785
786
except (OSError, IOError, KeyError):
787
# Skip if "state.json" file is missing or bad format
788
continue
789
790
return vs_versions
791
792
@staticmethod
793
def _as_float_version(version):
794
"""
795
Return a string version as a simplified float version (major.minor)
796
797
Parameters
798
----------
799
version: str
800
Version.
801
802
Return
803
------
804
float
805
version
806
"""
807
return float('.'.join(version.split('.')[:2]))
808
809
@property
810
def VSInstallDir(self):
811
"""
812
Microsoft Visual Studio directory.
813
814
Return
815
------
816
str
817
path
818
"""
819
# Default path
820
default = join(self.ProgramFilesx86,
821
'Microsoft Visual Studio %0.1f' % self.vs_ver)
822
823
# Try to get path from registry, if fail use default path
824
return self.ri.lookup(self.ri.vs, '%0.1f' % self.vs_ver) or default
825
826
@property
827
def VCInstallDir(self):
828
"""
829
Microsoft Visual C++ directory.
830
831
Return
832
------
833
str
834
path
835
"""
836
path = self._guess_vc() or self._guess_vc_legacy()
837
838
if not isdir(path):
839
msg = 'Microsoft Visual C++ directory not found'
840
raise distutils.errors.DistutilsPlatformError(msg)
841
842
return path
843
844
def _guess_vc(self):
845
"""
846
Locate Visual C++ for VS2017+.
847
848
Return
849
------
850
str
851
path
852
"""
853
if self.vs_ver <= 14.0:
854
return ''
855
856
try:
857
# First search in known VS paths
858
vs_dir = self.known_vs_paths[self.vs_ver]
859
except KeyError:
860
# Else, search with path from registry
861
vs_dir = self.VSInstallDir
862
863
guess_vc = join(vs_dir, r'VC\Tools\MSVC')
864
865
# Subdir with VC exact version as name
866
try:
867
# Update the VC version with real one instead of VS version
868
vc_ver = listdir(guess_vc)[-1]
869
self.vc_ver = self._as_float_version(vc_ver)
870
return join(guess_vc, vc_ver)
871
except (OSError, IOError, IndexError):
872
return ''
873
874
def _guess_vc_legacy(self):
875
"""
876
Locate Visual C++ for versions prior to 2017.
877
878
Return
879
------
880
str
881
path
882
"""
883
default = join(self.ProgramFilesx86,
884
r'Microsoft Visual Studio %0.1f\VC' % self.vs_ver)
885
886
# Try to get "VC++ for Python" path from registry as default path
887
reg_path = join(self.ri.vc_for_python, '%0.1f' % self.vs_ver)
888
python_vc = self.ri.lookup(reg_path, 'installdir')
889
default_vc = join(python_vc, 'VC') if python_vc else default
890
891
# Try to get path from registry, if fail use default path
892
return self.ri.lookup(self.ri.vc, '%0.1f' % self.vs_ver) or default_vc
893
894
@property
895
def WindowsSdkVersion(self):
896
"""
897
Microsoft Windows SDK versions for specified MSVC++ version.
898
899
Return
900
------
901
tuple of str
902
versions
903
"""
904
if self.vs_ver <= 9.0:
905
return '7.0', '6.1', '6.0a'
906
elif self.vs_ver == 10.0:
907
return '7.1', '7.0a'
908
elif self.vs_ver == 11.0:
909
return '8.0', '8.0a'
910
elif self.vs_ver == 12.0:
911
return '8.1', '8.1a'
912
elif self.vs_ver >= 14.0:
913
return '10.0', '8.1'
914
915
@property
916
def WindowsSdkLastVersion(self):
917
"""
918
Microsoft Windows SDK last version.
919
920
Return
921
------
922
str
923
version
924
"""
925
return self._use_last_dir_name(join(self.WindowsSdkDir, 'lib'))
926
927
@property # noqa: C901
928
def WindowsSdkDir(self): # noqa: C901 # is too complex (12) # FIXME
929
"""
930
Microsoft Windows SDK directory.
931
932
Return
933
------
934
str
935
path
936
"""
937
sdkdir = ''
938
for ver in self.WindowsSdkVersion:
939
# Try to get it from registry
940
loc = join(self.ri.windows_sdk, 'v%s' % ver)
941
sdkdir = self.ri.lookup(loc, 'installationfolder')
942
if sdkdir:
943
break
944
if not sdkdir or not isdir(sdkdir):
945
# Try to get "VC++ for Python" version from registry
946
path = join(self.ri.vc_for_python, '%0.1f' % self.vc_ver)
947
install_base = self.ri.lookup(path, 'installdir')
948
if install_base:
949
sdkdir = join(install_base, 'WinSDK')
950
if not sdkdir or not isdir(sdkdir):
951
# If fail, use default new path
952
for ver in self.WindowsSdkVersion:
953
intver = ver[:ver.rfind('.')]
954
path = r'Microsoft SDKs\Windows Kits\%s' % intver
955
d = join(self.ProgramFiles, path)
956
if isdir(d):
957
sdkdir = d
958
if not sdkdir or not isdir(sdkdir):
959
# If fail, use default old path
960
for ver in self.WindowsSdkVersion:
961
path = r'Microsoft SDKs\Windows\v%s' % ver
962
d = join(self.ProgramFiles, path)
963
if isdir(d):
964
sdkdir = d
965
if not sdkdir:
966
# If fail, use Platform SDK
967
sdkdir = join(self.VCInstallDir, 'PlatformSDK')
968
return sdkdir
969
970
@property
971
def WindowsSDKExecutablePath(self):
972
"""
973
Microsoft Windows SDK executable directory.
974
975
Return
976
------
977
str
978
path
979
"""
980
# Find WinSDK NetFx Tools registry dir name
981
if self.vs_ver <= 11.0:
982
netfxver = 35
983
arch = ''
984
else:
985
netfxver = 40
986
hidex86 = True if self.vs_ver <= 12.0 else False
987
arch = self.pi.current_dir(x64=True, hidex86=hidex86)
988
fx = 'WinSDK-NetFx%dTools%s' % (netfxver, arch.replace('\\', '-'))
989
990
# list all possibles registry paths
991
regpaths = []
992
if self.vs_ver >= 14.0:
993
for ver in self.NetFxSdkVersion:
994
regpaths += [join(self.ri.netfx_sdk, ver, fx)]
995
996
for ver in self.WindowsSdkVersion:
997
regpaths += [join(self.ri.windows_sdk, 'v%sA' % ver, fx)]
998
999
# Return installation folder from the more recent path
1000
for path in regpaths:
1001
execpath = self.ri.lookup(path, 'installationfolder')
1002
if execpath:
1003
return execpath
1004
1005
@property
1006
def FSharpInstallDir(self):
1007
"""
1008
Microsoft Visual F# directory.
1009
1010
Return
1011
------
1012
str
1013
path
1014
"""
1015
path = join(self.ri.visualstudio, r'%0.1f\Setup\F#' % self.vs_ver)
1016
return self.ri.lookup(path, 'productdir') or ''
1017
1018
@property
1019
def UniversalCRTSdkDir(self):
1020
"""
1021
Microsoft Universal CRT SDK directory.
1022
1023
Return
1024
------
1025
str
1026
path
1027
"""
1028
# Set Kit Roots versions for specified MSVC++ version
1029
vers = ('10', '81') if self.vs_ver >= 14.0 else ()
1030
1031
# Find path of the more recent Kit
1032
for ver in vers:
1033
sdkdir = self.ri.lookup(self.ri.windows_kits_roots,
1034
'kitsroot%s' % ver)
1035
if sdkdir:
1036
return sdkdir or ''
1037
1038
@property
1039
def UniversalCRTSdkLastVersion(self):
1040
"""
1041
Microsoft Universal C Runtime SDK last version.
1042
1043
Return
1044
------
1045
str
1046
version
1047
"""
1048
return self._use_last_dir_name(join(self.UniversalCRTSdkDir, 'lib'))
1049
1050
@property
1051
def NetFxSdkVersion(self):
1052
"""
1053
Microsoft .NET Framework SDK versions.
1054
1055
Return
1056
------
1057
tuple of str
1058
versions
1059
"""
1060
# Set FxSdk versions for specified VS version
1061
return (('4.7.2', '4.7.1', '4.7',
1062
'4.6.2', '4.6.1', '4.6',
1063
'4.5.2', '4.5.1', '4.5')
1064
if self.vs_ver >= 14.0 else ())
1065
1066
@property
1067
def NetFxSdkDir(self):
1068
"""
1069
Microsoft .NET Framework SDK directory.
1070
1071
Return
1072
------
1073
str
1074
path
1075
"""
1076
sdkdir = ''
1077
for ver in self.NetFxSdkVersion:
1078
loc = join(self.ri.netfx_sdk, ver)
1079
sdkdir = self.ri.lookup(loc, 'kitsinstallationfolder')
1080
if sdkdir:
1081
break
1082
return sdkdir
1083
1084
@property
1085
def FrameworkDir32(self):
1086
"""
1087
Microsoft .NET Framework 32bit directory.
1088
1089
Return
1090
------
1091
str
1092
path
1093
"""
1094
# Default path
1095
guess_fw = join(self.WinDir, r'Microsoft.NET\Framework')
1096
1097
# Try to get path from registry, if fail use default path
1098
return self.ri.lookup(self.ri.vc, 'frameworkdir32') or guess_fw
1099
1100
@property
1101
def FrameworkDir64(self):
1102
"""
1103
Microsoft .NET Framework 64bit directory.
1104
1105
Return
1106
------
1107
str
1108
path
1109
"""
1110
# Default path
1111
guess_fw = join(self.WinDir, r'Microsoft.NET\Framework64')
1112
1113
# Try to get path from registry, if fail use default path
1114
return self.ri.lookup(self.ri.vc, 'frameworkdir64') or guess_fw
1115
1116
@property
1117
def FrameworkVersion32(self):
1118
"""
1119
Microsoft .NET Framework 32bit versions.
1120
1121
Return
1122
------
1123
tuple of str
1124
versions
1125
"""
1126
return self._find_dot_net_versions(32)
1127
1128
@property
1129
def FrameworkVersion64(self):
1130
"""
1131
Microsoft .NET Framework 64bit versions.
1132
1133
Return
1134
------
1135
tuple of str
1136
versions
1137
"""
1138
return self._find_dot_net_versions(64)
1139
1140
def _find_dot_net_versions(self, bits):
1141
"""
1142
Find Microsoft .NET Framework versions.
1143
1144
Parameters
1145
----------
1146
bits: int
1147
Platform number of bits: 32 or 64.
1148
1149
Return
1150
------
1151
tuple of str
1152
versions
1153
"""
1154
# Find actual .NET version in registry
1155
reg_ver = self.ri.lookup(self.ri.vc, 'frameworkver%d' % bits)
1156
dot_net_dir = getattr(self, 'FrameworkDir%d' % bits)
1157
ver = reg_ver or self._use_last_dir_name(dot_net_dir, 'v') or ''
1158
1159
# Set .NET versions for specified MSVC++ version
1160
if self.vs_ver >= 12.0:
1161
return ver, 'v4.0'
1162
elif self.vs_ver >= 10.0:
1163
return 'v4.0.30319' if ver.lower()[:2] != 'v4' else ver, 'v3.5'
1164
elif self.vs_ver == 9.0:
1165
return 'v3.5', 'v2.0.50727'
1166
elif self.vs_ver == 8.0:
1167
return 'v3.0', 'v2.0.50727'
1168
1169
@staticmethod
1170
def _use_last_dir_name(path, prefix=''):
1171
"""
1172
Return name of the last dir in path or '' if no dir found.
1173
1174
Parameters
1175
----------
1176
path: str
1177
Use dirs in this path
1178
prefix: str
1179
Use only dirs starting by this prefix
1180
1181
Return
1182
------
1183
str
1184
name
1185
"""
1186
matching_dirs = (
1187
dir_name
1188
for dir_name in reversed(listdir(path))
1189
if isdir(join(path, dir_name)) and
1190
dir_name.startswith(prefix)
1191
)
1192
return next(matching_dirs, None) or ''
1193
1194
1195
class EnvironmentInfo:
1196
"""
1197
Return environment variables for specified Microsoft Visual C++ version
1198
and platform : Lib, Include, Path and libpath.
1199
1200
This function is compatible with Microsoft Visual C++ 9.0 to 14.X.
1201
1202
Script created by analysing Microsoft environment configuration files like
1203
"vcvars[...].bat", "SetEnv.Cmd", "vcbuildtools.bat", ...
1204
1205
Parameters
1206
----------
1207
arch: str
1208
Target architecture.
1209
vc_ver: float
1210
Required Microsoft Visual C++ version. If not set, autodetect the last
1211
version.
1212
vc_min_ver: float
1213
Minimum Microsoft Visual C++ version.
1214
"""
1215
1216
# Variables and properties in this class use originals CamelCase variables
1217
# names from Microsoft source files for more easy comparison.
1218
1219
def __init__(self, arch, vc_ver=None, vc_min_ver=0):
1220
self.pi = PlatformInfo(arch)
1221
self.ri = RegistryInfo(self.pi)
1222
self.si = SystemInfo(self.ri, vc_ver)
1223
1224
if self.vc_ver < vc_min_ver:
1225
err = 'No suitable Microsoft Visual C++ version found'
1226
raise distutils.errors.DistutilsPlatformError(err)
1227
1228
@property
1229
def vs_ver(self):
1230
"""
1231
Microsoft Visual Studio.
1232
1233
Return
1234
------
1235
float
1236
version
1237
"""
1238
return self.si.vs_ver
1239
1240
@property
1241
def vc_ver(self):
1242
"""
1243
Microsoft Visual C++ version.
1244
1245
Return
1246
------
1247
float
1248
version
1249
"""
1250
return self.si.vc_ver
1251
1252
@property
1253
def VSTools(self):
1254
"""
1255
Microsoft Visual Studio Tools.
1256
1257
Return
1258
------
1259
list of str
1260
paths
1261
"""
1262
paths = [r'Common7\IDE', r'Common7\Tools']
1263
1264
if self.vs_ver >= 14.0:
1265
arch_subdir = self.pi.current_dir(hidex86=True, x64=True)
1266
paths += [r'Common7\IDE\CommonExtensions\Microsoft\TestWindow']
1267
paths += [r'Team Tools\Performance Tools']
1268
paths += [r'Team Tools\Performance Tools%s' % arch_subdir]
1269
1270
return [join(self.si.VSInstallDir, path) for path in paths]
1271
1272
@property
1273
def VCIncludes(self):
1274
"""
1275
Microsoft Visual C++ & Microsoft Foundation Class Includes.
1276
1277
Return
1278
------
1279
list of str
1280
paths
1281
"""
1282
return [join(self.si.VCInstallDir, 'Include'),
1283
join(self.si.VCInstallDir, r'ATLMFC\Include')]
1284
1285
@property
1286
def VCLibraries(self):
1287
"""
1288
Microsoft Visual C++ & Microsoft Foundation Class Libraries.
1289
1290
Return
1291
------
1292
list of str
1293
paths
1294
"""
1295
if self.vs_ver >= 15.0:
1296
arch_subdir = self.pi.target_dir(x64=True)
1297
else:
1298
arch_subdir = self.pi.target_dir(hidex86=True)
1299
paths = ['Lib%s' % arch_subdir, r'ATLMFC\Lib%s' % arch_subdir]
1300
1301
if self.vs_ver >= 14.0:
1302
paths += [r'Lib\store%s' % arch_subdir]
1303
1304
return [join(self.si.VCInstallDir, path) for path in paths]
1305
1306
@property
1307
def VCStoreRefs(self):
1308
"""
1309
Microsoft Visual C++ store references Libraries.
1310
1311
Return
1312
------
1313
list of str
1314
paths
1315
"""
1316
if self.vs_ver < 14.0:
1317
return []
1318
return [join(self.si.VCInstallDir, r'Lib\store\references')]
1319
1320
@property
1321
def VCTools(self):
1322
"""
1323
Microsoft Visual C++ Tools.
1324
1325
Return
1326
------
1327
list of str
1328
paths
1329
"""
1330
si = self.si
1331
tools = [join(si.VCInstallDir, 'VCPackages')]
1332
1333
forcex86 = True if self.vs_ver <= 10.0 else False
1334
arch_subdir = self.pi.cross_dir(forcex86)
1335
if arch_subdir:
1336
tools += [join(si.VCInstallDir, 'Bin%s' % arch_subdir)]
1337
1338
if self.vs_ver == 14.0:
1339
path = 'Bin%s' % self.pi.current_dir(hidex86=True)
1340
tools += [join(si.VCInstallDir, path)]
1341
1342
elif self.vs_ver >= 15.0:
1343
host_dir = (r'bin\HostX86%s' if self.pi.current_is_x86() else
1344
r'bin\HostX64%s')
1345
tools += [join(
1346
si.VCInstallDir, host_dir % self.pi.target_dir(x64=True))]
1347
1348
if self.pi.current_cpu != self.pi.target_cpu:
1349
tools += [join(
1350
si.VCInstallDir, host_dir % self.pi.current_dir(x64=True))]
1351
1352
else:
1353
tools += [join(si.VCInstallDir, 'Bin')]
1354
1355
return tools
1356
1357
@property
1358
def OSLibraries(self):
1359
"""
1360
Microsoft Windows SDK Libraries.
1361
1362
Return
1363
------
1364
list of str
1365
paths
1366
"""
1367
if self.vs_ver <= 10.0:
1368
arch_subdir = self.pi.target_dir(hidex86=True, x64=True)
1369
return [join(self.si.WindowsSdkDir, 'Lib%s' % arch_subdir)]
1370
1371
else:
1372
arch_subdir = self.pi.target_dir(x64=True)
1373
lib = join(self.si.WindowsSdkDir, 'lib')
1374
libver = self._sdk_subdir
1375
return [join(lib, '%sum%s' % (libver, arch_subdir))]
1376
1377
@property
1378
def OSIncludes(self):
1379
"""
1380
Microsoft Windows SDK Include.
1381
1382
Return
1383
------
1384
list of str
1385
paths
1386
"""
1387
include = join(self.si.WindowsSdkDir, 'include')
1388
1389
if self.vs_ver <= 10.0:
1390
return [include, join(include, 'gl')]
1391
1392
else:
1393
if self.vs_ver >= 14.0:
1394
sdkver = self._sdk_subdir
1395
else:
1396
sdkver = ''
1397
return [join(include, '%sshared' % sdkver),
1398
join(include, '%sum' % sdkver),
1399
join(include, '%swinrt' % sdkver)]
1400
1401
@property
1402
def OSLibpath(self):
1403
"""
1404
Microsoft Windows SDK Libraries Paths.
1405
1406
Return
1407
------
1408
list of str
1409
paths
1410
"""
1411
ref = join(self.si.WindowsSdkDir, 'References')
1412
libpath = []
1413
1414
if self.vs_ver <= 9.0:
1415
libpath += self.OSLibraries
1416
1417
if self.vs_ver >= 11.0:
1418
libpath += [join(ref, r'CommonConfiguration\Neutral')]
1419
1420
if self.vs_ver >= 14.0:
1421
libpath += [
1422
ref,
1423
join(self.si.WindowsSdkDir, 'UnionMetadata'),
1424
join(
1425
ref, 'Windows.Foundation.UniversalApiContract', '1.0.0.0'),
1426
join(ref, 'Windows.Foundation.FoundationContract', '1.0.0.0'),
1427
join(
1428
ref, 'Windows.Networking.Connectivity.WwanContract',
1429
'1.0.0.0'),
1430
join(
1431
self.si.WindowsSdkDir, 'ExtensionSDKs', 'Microsoft.VCLibs',
1432
'%0.1f' % self.vs_ver, 'References', 'CommonConfiguration',
1433
'neutral'),
1434
]
1435
return libpath
1436
1437
@property
1438
def SdkTools(self):
1439
"""
1440
Microsoft Windows SDK Tools.
1441
1442
Return
1443
------
1444
list of str
1445
paths
1446
"""
1447
return list(self._sdk_tools())
1448
1449
def _sdk_tools(self):
1450
"""
1451
Microsoft Windows SDK Tools paths generator.
1452
1453
Return
1454
------
1455
generator of str
1456
paths
1457
"""
1458
if self.vs_ver < 15.0:
1459
bin_dir = 'Bin' if self.vs_ver <= 11.0 else r'Bin\x86'
1460
yield join(self.si.WindowsSdkDir, bin_dir)
1461
1462
if not self.pi.current_is_x86():
1463
arch_subdir = self.pi.current_dir(x64=True)
1464
path = 'Bin%s' % arch_subdir
1465
yield join(self.si.WindowsSdkDir, path)
1466
1467
if self.vs_ver in (10.0, 11.0):
1468
if self.pi.target_is_x86():
1469
arch_subdir = ''
1470
else:
1471
arch_subdir = self.pi.current_dir(hidex86=True, x64=True)
1472
path = r'Bin\NETFX 4.0 Tools%s' % arch_subdir
1473
yield join(self.si.WindowsSdkDir, path)
1474
1475
elif self.vs_ver >= 15.0:
1476
path = join(self.si.WindowsSdkDir, 'Bin')
1477
arch_subdir = self.pi.current_dir(x64=True)
1478
sdkver = self.si.WindowsSdkLastVersion
1479
yield join(path, '%s%s' % (sdkver, arch_subdir))
1480
1481
if self.si.WindowsSDKExecutablePath:
1482
yield self.si.WindowsSDKExecutablePath
1483
1484
@property
1485
def _sdk_subdir(self):
1486
"""
1487
Microsoft Windows SDK version subdir.
1488
1489
Return
1490
------
1491
str
1492
subdir
1493
"""
1494
ucrtver = self.si.WindowsSdkLastVersion
1495
return ('%s\\' % ucrtver) if ucrtver else ''
1496
1497
@property
1498
def SdkSetup(self):
1499
"""
1500
Microsoft Windows SDK Setup.
1501
1502
Return
1503
------
1504
list of str
1505
paths
1506
"""
1507
if self.vs_ver > 9.0:
1508
return []
1509
1510
return [join(self.si.WindowsSdkDir, 'Setup')]
1511
1512
@property
1513
def FxTools(self):
1514
"""
1515
Microsoft .NET Framework Tools.
1516
1517
Return
1518
------
1519
list of str
1520
paths
1521
"""
1522
pi = self.pi
1523
si = self.si
1524
1525
if self.vs_ver <= 10.0:
1526
include32 = True
1527
include64 = not pi.target_is_x86() and not pi.current_is_x86()
1528
else:
1529
include32 = pi.target_is_x86() or pi.current_is_x86()
1530
include64 = pi.current_cpu == 'amd64' or pi.target_cpu == 'amd64'
1531
1532
tools = []
1533
if include32:
1534
tools += [join(si.FrameworkDir32, ver)
1535
for ver in si.FrameworkVersion32]
1536
if include64:
1537
tools += [join(si.FrameworkDir64, ver)
1538
for ver in si.FrameworkVersion64]
1539
return tools
1540
1541
@property
1542
def NetFxSDKLibraries(self):
1543
"""
1544
Microsoft .Net Framework SDK Libraries.
1545
1546
Return
1547
------
1548
list of str
1549
paths
1550
"""
1551
if self.vs_ver < 14.0 or not self.si.NetFxSdkDir:
1552
return []
1553
1554
arch_subdir = self.pi.target_dir(x64=True)
1555
return [join(self.si.NetFxSdkDir, r'lib\um%s' % arch_subdir)]
1556
1557
@property
1558
def NetFxSDKIncludes(self):
1559
"""
1560
Microsoft .Net Framework SDK Includes.
1561
1562
Return
1563
------
1564
list of str
1565
paths
1566
"""
1567
if self.vs_ver < 14.0 or not self.si.NetFxSdkDir:
1568
return []
1569
1570
return [join(self.si.NetFxSdkDir, r'include\um')]
1571
1572
@property
1573
def VsTDb(self):
1574
"""
1575
Microsoft Visual Studio Team System Database.
1576
1577
Return
1578
------
1579
list of str
1580
paths
1581
"""
1582
return [join(self.si.VSInstallDir, r'VSTSDB\Deploy')]
1583
1584
@property
1585
def MSBuild(self):
1586
"""
1587
Microsoft Build Engine.
1588
1589
Return
1590
------
1591
list of str
1592
paths
1593
"""
1594
if self.vs_ver < 12.0:
1595
return []
1596
elif self.vs_ver < 15.0:
1597
base_path = self.si.ProgramFilesx86
1598
arch_subdir = self.pi.current_dir(hidex86=True)
1599
else:
1600
base_path = self.si.VSInstallDir
1601
arch_subdir = ''
1602
1603
path = r'MSBuild\%0.1f\bin%s' % (self.vs_ver, arch_subdir)
1604
build = [join(base_path, path)]
1605
1606
if self.vs_ver >= 15.0:
1607
# Add Roslyn C# & Visual Basic Compiler
1608
build += [join(base_path, path, 'Roslyn')]
1609
1610
return build
1611
1612
@property
1613
def HTMLHelpWorkshop(self):
1614
"""
1615
Microsoft HTML Help Workshop.
1616
1617
Return
1618
------
1619
list of str
1620
paths
1621
"""
1622
if self.vs_ver < 11.0:
1623
return []
1624
1625
return [join(self.si.ProgramFilesx86, 'HTML Help Workshop')]
1626
1627
@property
1628
def UCRTLibraries(self):
1629
"""
1630
Microsoft Universal C Runtime SDK Libraries.
1631
1632
Return
1633
------
1634
list of str
1635
paths
1636
"""
1637
if self.vs_ver < 14.0:
1638
return []
1639
1640
arch_subdir = self.pi.target_dir(x64=True)
1641
lib = join(self.si.UniversalCRTSdkDir, 'lib')
1642
ucrtver = self._ucrt_subdir
1643
return [join(lib, '%sucrt%s' % (ucrtver, arch_subdir))]
1644
1645
@property
1646
def UCRTIncludes(self):
1647
"""
1648
Microsoft Universal C Runtime SDK Include.
1649
1650
Return
1651
------
1652
list of str
1653
paths
1654
"""
1655
if self.vs_ver < 14.0:
1656
return []
1657
1658
include = join(self.si.UniversalCRTSdkDir, 'include')
1659
return [join(include, '%sucrt' % self._ucrt_subdir)]
1660
1661
@property
1662
def _ucrt_subdir(self):
1663
"""
1664
Microsoft Universal C Runtime SDK version subdir.
1665
1666
Return
1667
------
1668
str
1669
subdir
1670
"""
1671
ucrtver = self.si.UniversalCRTSdkLastVersion
1672
return ('%s\\' % ucrtver) if ucrtver else ''
1673
1674
@property
1675
def FSharp(self):
1676
"""
1677
Microsoft Visual F#.
1678
1679
Return
1680
------
1681
list of str
1682
paths
1683
"""
1684
if 11.0 > self.vs_ver > 12.0:
1685
return []
1686
1687
return [self.si.FSharpInstallDir]
1688
1689
@property
1690
def VCRuntimeRedist(self):
1691
"""
1692
Microsoft Visual C++ runtime redistributable dll.
1693
1694
Return
1695
------
1696
str
1697
path
1698
"""
1699
vcruntime = 'vcruntime%d0.dll' % self.vc_ver
1700
arch_subdir = self.pi.target_dir(x64=True).strip('\\')
1701
1702
# Installation prefixes candidates
1703
prefixes = []
1704
tools_path = self.si.VCInstallDir
1705
redist_path = dirname(tools_path.replace(r'\Tools', r'\Redist'))
1706
if isdir(redist_path):
1707
# Redist version may not be exactly the same as tools
1708
redist_path = join(redist_path, listdir(redist_path)[-1])
1709
prefixes += [redist_path, join(redist_path, 'onecore')]
1710
1711
prefixes += [join(tools_path, 'redist')] # VS14 legacy path
1712
1713
# CRT directory
1714
crt_dirs = ('Microsoft.VC%d.CRT' % (self.vc_ver * 10),
1715
# Sometime store in directory with VS version instead of VC
1716
'Microsoft.VC%d.CRT' % (int(self.vs_ver) * 10))
1717
1718
# vcruntime path
1719
for prefix, crt_dir in itertools.product(prefixes, crt_dirs):
1720
path = join(prefix, arch_subdir, crt_dir, vcruntime)
1721
if isfile(path):
1722
return path
1723
1724
def return_env(self, exists=True):
1725
"""
1726
Return environment dict.
1727
1728
Parameters
1729
----------
1730
exists: bool
1731
It True, only return existing paths.
1732
1733
Return
1734
------
1735
dict
1736
environment
1737
"""
1738
env = dict(
1739
include=self._build_paths('include',
1740
[self.VCIncludes,
1741
self.OSIncludes,
1742
self.UCRTIncludes,
1743
self.NetFxSDKIncludes],
1744
exists),
1745
lib=self._build_paths('lib',
1746
[self.VCLibraries,
1747
self.OSLibraries,
1748
self.FxTools,
1749
self.UCRTLibraries,
1750
self.NetFxSDKLibraries],
1751
exists),
1752
libpath=self._build_paths('libpath',
1753
[self.VCLibraries,
1754
self.FxTools,
1755
self.VCStoreRefs,
1756
self.OSLibpath],
1757
exists),
1758
path=self._build_paths('path',
1759
[self.VCTools,
1760
self.VSTools,
1761
self.VsTDb,
1762
self.SdkTools,
1763
self.SdkSetup,
1764
self.FxTools,
1765
self.MSBuild,
1766
self.HTMLHelpWorkshop,
1767
self.FSharp],
1768
exists),
1769
)
1770
if self.vs_ver >= 14 and isfile(self.VCRuntimeRedist):
1771
env['py_vcruntime_redist'] = self.VCRuntimeRedist
1772
return env
1773
1774
def _build_paths(self, name, spec_path_lists, exists):
1775
"""
1776
Given an environment variable name and specified paths,
1777
return a pathsep-separated string of paths containing
1778
unique, extant, directories from those paths and from
1779
the environment variable. Raise an error if no paths
1780
are resolved.
1781
1782
Parameters
1783
----------
1784
name: str
1785
Environment variable name
1786
spec_path_lists: list of str
1787
Paths
1788
exists: bool
1789
It True, only return existing paths.
1790
1791
Return
1792
------
1793
str
1794
Pathsep-separated paths
1795
"""
1796
# flatten spec_path_lists
1797
spec_paths = itertools.chain.from_iterable(spec_path_lists)
1798
env_paths = environ.get(name, '').split(pathsep)
1799
paths = itertools.chain(spec_paths, env_paths)
1800
extant_paths = list(filter(isdir, paths)) if exists else paths
1801
if not extant_paths:
1802
msg = "%s environment variable is empty" % name.upper()
1803
raise distutils.errors.DistutilsPlatformError(msg)
1804
unique_paths = unique_everseen(extant_paths)
1805
return pathsep.join(unique_paths)
1806
1807