Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
setuptools
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jérome Perrin
setuptools
Commits
230d1f74
Commit
230d1f74
authored
Oct 27, 2019
by
Jason R. Coombs
Committed by
GitHub
Oct 27, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1811 from JGoutin/msvc_update
Improve Visual C++ 14.X support
parents
297f2adc
7e1b1934
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
700 additions
and
322 deletions
+700
-322
changelog.d/1811.change.rst
changelog.d/1811.change.rst
+1
-0
setuptools/msvc.py
setuptools/msvc.py
+699
-322
No files found.
changelog.d/1811.change.rst
0 → 100644
View file @
230d1f74
Improve Visual C++ 14.X support, mainly for Visual Studio 2017 and 2019.
\ No newline at end of file
setuptools/msvc.py
View file @
230d1f74
...
@@ -11,13 +11,17 @@ Microsoft Visual C++ 9.0:
...
@@ -11,13 +11,17 @@ Microsoft Visual C++ 9.0:
Microsoft Visual C++ 10.0:
Microsoft Visual C++ 10.0:
Microsoft Windows SDK 7.1 (x86, x64, ia64)
Microsoft Windows SDK 7.1 (x86, x64, ia64)
Microsoft Visual C++ 14.
0
:
Microsoft Visual C++ 14.
X
:
Microsoft Visual C++ Build Tools 2015 (x86, x64, arm)
Microsoft Visual C++ Build Tools 2015 (x86, x64, arm)
Microsoft Visual Studio 2017 (x86, x64, arm, arm64)
Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64)
Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64)
Microsoft Visual Studio Build Tools 2019 (x86, x64, arm, arm64)
This may also support compilers shipped with compatible Visual Studio versions.
"""
"""
import
os
import
json
from
os
import
listdir
,
pathsep
from
os.path
import
join
,
isfile
,
isdir
,
dirname
import
sys
import
sys
import
platform
import
platform
import
itertools
import
itertools
...
@@ -30,12 +34,9 @@ from .monkey import get_unpatched
...
@@ -30,12 +34,9 @@ from .monkey import get_unpatched
if
platform
.
system
()
==
'Windows'
:
if
platform
.
system
()
==
'Windows'
:
from
setuptools.extern.six.moves
import
winreg
from
setuptools.extern.six.moves
import
winreg
safe_env
=
os
.
environ
from
os
import
environ
else
:
else
:
"""
# Mock winreg and environ so the module can be imported on this platform.
Mock winreg and environ so the module can be imported
on this platform.
"""
class
winreg
:
class
winreg
:
HKEY_USERS
=
None
HKEY_USERS
=
None
...
@@ -43,7 +44,7 @@ else:
...
@@ -43,7 +44,7 @@ else:
HKEY_LOCAL_MACHINE
=
None
HKEY_LOCAL_MACHINE
=
None
HKEY_CLASSES_ROOT
=
None
HKEY_CLASSES_ROOT
=
None
safe_env
=
dict
()
environ
=
dict
()
_msvc9_suppress_errors
=
(
_msvc9_suppress_errors
=
(
# msvc9compiler isn't available on some platforms
# msvc9compiler isn't available on some platforms
...
@@ -63,15 +64,13 @@ except _msvc9_suppress_errors:
...
@@ -63,15 +64,13 @@ except _msvc9_suppress_errors:
def
msvc9_find_vcvarsall
(
version
):
def
msvc9_find_vcvarsall
(
version
):
"""
"""
Patched "distutils.msvc9compiler.find_vcvarsall" to use the standalone
Patched "distutils.msvc9compiler.find_vcvarsall" to use the standalone
compiler build for Python
(VCForPython). Fall back to original behavior
compiler build for Python
when the standalone compiler is not available
.
(VCForPython / Microsoft Visual C++ Compiler for Python 2.7)
.
Redirect the path of "vcvarsall.bat".
Fall back to original behavior when the standalone compiler is not
available.
Known supported compilers
Redirect the path of "vcvarsall.bat".
-------------------------
Microsoft Visual C++ 9.0:
Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64)
Parameters
Parameters
----------
----------
...
@@ -80,24 +79,25 @@ def msvc9_find_vcvarsall(version):
...
@@ -80,24 +79,25 @@ def msvc9_find_vcvarsall(version):
Return
Return
------
------
vcvarsall.bat path: str
str
vcvarsall.bat path
"""
"""
VC_BASE
=
r'Software\
%sMic
rosoft\
De
vDiv\
VCFo
rPython\
%
0.1f'
vc_base
=
r'Software\
%sMic
rosoft\
De
vDiv\
VCFo
rPython\
%
0.1f'
key
=
VC_BASE
%
(
''
,
version
)
key
=
vc_base
%
(
''
,
version
)
try
:
try
:
# Per-user installs register the compiler path here
# Per-user installs register the compiler path here
productdir
=
Reg
.
get_value
(
key
,
"installdir"
)
productdir
=
Reg
.
get_value
(
key
,
"installdir"
)
except
KeyError
:
except
KeyError
:
try
:
try
:
# All-user installs on a 64-bit system register here
# All-user installs on a 64-bit system register here
key
=
VC_BASE
%
(
'Wow6432Node
\
\
'
,
version
)
key
=
vc_base
%
(
'Wow6432Node
\
\
'
,
version
)
productdir
=
Reg
.
get_value
(
key
,
"installdir"
)
productdir
=
Reg
.
get_value
(
key
,
"installdir"
)
except
KeyError
:
except
KeyError
:
productdir
=
None
productdir
=
None
if
productdir
:
if
productdir
:
vcvarsall
=
os
.
path
.
os
.
path
.
join
(
productdir
,
"vcvarsall.bat"
)
vcvarsall
=
join
(
productdir
,
"vcvarsall.bat"
)
if
os
.
path
.
isfile
(
vcvarsall
):
if
isfile
(
vcvarsall
):
return
vcvarsall
return
vcvarsall
return
get_unpatched
(
msvc9_find_vcvarsall
)(
version
)
return
get_unpatched
(
msvc9_find_vcvarsall
)(
version
)
...
@@ -106,20 +106,10 @@ def msvc9_find_vcvarsall(version):
...
@@ -106,20 +106,10 @@ def msvc9_find_vcvarsall(version):
def
msvc9_query_vcvarsall
(
ver
,
arch
=
'x86'
,
*
args
,
**
kwargs
):
def
msvc9_query_vcvarsall
(
ver
,
arch
=
'x86'
,
*
args
,
**
kwargs
):
"""
"""
Patched "distutils.msvc9compiler.query_vcvarsall" for support extra
Patched "distutils.msvc9compiler.query_vcvarsall" for support extra
compilers.
Microsoft Visual C++ 9.0 and 10.0
compilers.
Set environment without use of "vcvarsall.bat".
Set environment without use of "vcvarsall.bat".
Known supported compilers
-------------------------
Microsoft Visual C++ 9.0:
Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64)
Microsoft Windows SDK 6.1 (x86, x64, ia64)
Microsoft Windows SDK 7.0 (x86, x64, ia64)
Microsoft Visual C++ 10.0:
Microsoft Windows SDK 7.1 (x86, x64, ia64)
Parameters
Parameters
----------
----------
ver: float
ver: float
...
@@ -129,9 +119,10 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs):
...
@@ -129,9 +119,10 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs):
Return
Return
------
------
environment: dict
dict
environment
"""
"""
# Try to get environ
e
ment from vcvarsall.bat (Classical way)
# Try to get environment from vcvarsall.bat (Classical way)
try
:
try
:
orig
=
get_unpatched
(
msvc9_query_vcvarsall
)
orig
=
get_unpatched
(
msvc9_query_vcvarsall
)
return
orig
(
ver
,
arch
,
*
args
,
**
kwargs
)
return
orig
(
ver
,
arch
,
*
args
,
**
kwargs
)
...
@@ -153,17 +144,10 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs):
...
@@ -153,17 +144,10 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs):
def
msvc14_get_vc_env
(
plat_spec
):
def
msvc14_get_vc_env
(
plat_spec
):
"""
"""
Patched "distutils._msvccompiler._get_vc_env" for support extra
Patched "distutils._msvccompiler._get_vc_env" for support extra
compilers.
Microsoft Visual C++ 14.X
compilers.
Set environment without use of "vcvarsall.bat".
Set environment without use of "vcvarsall.bat".
Known supported compilers
-------------------------
Microsoft Visual C++ 14.0:
Microsoft Visual C++ Build Tools 2015 (x86, x64, arm)
Microsoft Visual Studio 2017 (x86, x64, arm, arm64)
Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64)
Parameters
Parameters
----------
----------
plat_spec: str
plat_spec: str
...
@@ -171,7 +155,8 @@ def msvc14_get_vc_env(plat_spec):
...
@@ -171,7 +155,8 @@ def msvc14_get_vc_env(plat_spec):
Return
Return
------
------
environment: dict
dict
environment
"""
"""
# Try to get environment from vcvarsall.bat (Classical way)
# Try to get environment from vcvarsall.bat (Classical way)
try
:
try
:
...
@@ -217,9 +202,9 @@ def _augment_exception(exc, version, arch=''):
...
@@ -217,9 +202,9 @@ def _augment_exception(exc, version, arch=''):
if
version
==
9.0
:
if
version
==
9.0
:
if
arch
.
lower
().
find
(
'ia64'
)
>
-
1
:
if
arch
.
lower
().
find
(
'ia64'
)
>
-
1
:
# For VC++ 9.0, if IA64 support is needed, redirect user
# For VC++ 9.0, if IA64 support is needed, redirect user
# to Windows SDK 7.0
# to Windows SDK 7.0
.
message
+=
' Get it with "Microsoft Windows SDK 7.0": '
# Note: No download link available from Microsoft.
message
+=
msdownload
%
3138
message
+=
' Get it with "Microsoft Windows SDK 7.0"'
else
:
else
:
# For VC++ 9.0 redirect user to Vc++ for Python 2.7 :
# For VC++ 9.0 redirect user to Vc++ for Python 2.7 :
# This redirection link is maintained by Microsoft.
# This redirection link is maintained by Microsoft.
...
@@ -230,8 +215,8 @@ def _augment_exception(exc, version, arch=''):
...
@@ -230,8 +215,8 @@ def _augment_exception(exc, version, arch=''):
message
+=
' Get it with "Microsoft Windows SDK 7.1": '
message
+=
' Get it with "Microsoft Windows SDK 7.1": '
message
+=
msdownload
%
8279
message
+=
msdownload
%
8279
elif
version
>=
14.0
:
elif
version
>=
14.0
:
# For VC++ 14.
0 Redirect user to
Visual C++ Build Tools
# For VC++ 14.
X Redirect user to latest
Visual C++ Build Tools
message
+=
(
' Get it with "
Microsoft Visual C++ Build Tools
": '
message
+=
(
' Get it with "
Build Tools for Visual Studio
": '
r'https://visualstudio.microsoft.com/downloads/'
)
r'https://visualstudio.microsoft.com/downloads/'
)
exc
.
args
=
(
message
,
)
exc
.
args
=
(
message
,
)
...
@@ -239,26 +224,50 @@ def _augment_exception(exc, version, arch=''):
...
@@ -239,26 +224,50 @@ def _augment_exception(exc, version, arch=''):
class
PlatformInfo
:
class
PlatformInfo
:
"""
"""
Current and Target Architectures information
s
.
Current and Target Architectures information.
Parameters
Parameters
----------
----------
arch: str
arch: str
Target architecture.
Target architecture.
"""
"""
current_cpu
=
safe_env
.
get
(
'processor_architecture'
,
''
).
lower
()
current_cpu
=
environ
.
get
(
'processor_architecture'
,
''
).
lower
()
def
__init__
(
self
,
arch
):
def
__init__
(
self
,
arch
):
self
.
arch
=
arch
.
lower
().
replace
(
'x64'
,
'amd64'
)
self
.
arch
=
arch
.
lower
().
replace
(
'x64'
,
'amd64'
)
@
property
@
property
def
target_cpu
(
self
):
def
target_cpu
(
self
):
"""
Return Target CPU architecture.
Return
------
str
Target CPU
"""
return
self
.
arch
[
self
.
arch
.
find
(
'_'
)
+
1
:]
return
self
.
arch
[
self
.
arch
.
find
(
'_'
)
+
1
:]
def
target_is_x86
(
self
):
def
target_is_x86
(
self
):
"""
Return True if target CPU is x86 32 bits..
Return
------
bool
CPU is x86 32 bits
"""
return
self
.
target_cpu
==
'x86'
return
self
.
target_cpu
==
'x86'
def
current_is_x86
(
self
):
def
current_is_x86
(
self
):
"""
Return True if current CPU is x86 32 bits..
Return
------
bool
CPU is x86 32 bits
"""
return
self
.
current_cpu
==
'x86'
return
self
.
current_cpu
==
'x86'
def
current_dir
(
self
,
hidex86
=
False
,
x64
=
False
):
def
current_dir
(
self
,
hidex86
=
False
,
x64
=
False
):
...
@@ -274,8 +283,8 @@ class PlatformInfo:
...
@@ -274,8 +283,8 @@ class PlatformInfo:
Return
Return
------
------
s
ubfolder: s
tr
str
'
\
t
arget', or '' (see hidex86 parameter)
subfolder:
'
\
t
arget', or '' (see hidex86 parameter)
"""
"""
return
(
return
(
''
if
(
self
.
current_cpu
==
'x86'
and
hidex86
)
else
''
if
(
self
.
current_cpu
==
'x86'
and
hidex86
)
else
...
@@ -296,8 +305,8 @@ class PlatformInfo:
...
@@ -296,8 +305,8 @@ class PlatformInfo:
Return
Return
------
------
s
ubfolder: s
tr
str
'
\
current
', or '' (see hidex86 parameter)
subfolder:
'
\
current
', or '' (see hidex86 parameter)
"""
"""
return (
return (
'' if (self.target_cpu == '
x86
' and hidex86) else
'' if (self.target_cpu == '
x86
' and hidex86) else
...
@@ -312,13 +321,13 @@ class PlatformInfo:
...
@@ -312,13 +321,13 @@ class PlatformInfo:
Parameters
Parameters
----------
----------
forcex86: bool
forcex86: bool
Use '
x86
' as current architecture even if current a
cr
itecture is
Use '
x86
' as current architecture even if current a
rch
itecture is
not x86.
not x86.
Return
Return
------
------
s
ubfolder: s
tr
str
'' if target architecture is current architecture,
subfolder:
'' if target architecture is current architecture,
'
\
current_target
' if not.
'
\
current_target
' if not.
"""
"""
current = '
x86
' if forcex86 else self.current_cpu
current = '
x86
' if forcex86 else self.current_cpu
...
@@ -330,7 +339,7 @@ class PlatformInfo:
...
@@ -330,7 +339,7 @@ class PlatformInfo:
class RegistryInfo:
class RegistryInfo:
"""
"""
Microsoft Visual Studio related registry information
s
.
Microsoft Visual Studio related registry information.
Parameters
Parameters
----------
----------
...
@@ -349,6 +358,11 @@ class RegistryInfo:
...
@@ -349,6 +358,11 @@ class RegistryInfo:
def visualstudio(self):
def visualstudio(self):
"""
"""
Microsoft Visual Studio root registry key.
Microsoft Visual Studio root registry key.
Return
------
str
Registry key
"""
"""
return '
VisualStudio
'
return '
VisualStudio
'
...
@@ -356,27 +370,47 @@ class RegistryInfo:
...
@@ -356,27 +370,47 @@ class RegistryInfo:
def sxs(self):
def sxs(self):
"""
"""
Microsoft Visual Studio SxS registry key.
Microsoft Visual Studio SxS registry key.
Return
------
str
Registry key
"""
"""
return
os.path.
join(self.visualstudio, '
SxS
')
return join(self.visualstudio, '
SxS
')
@property
@property
def vc(self):
def vc(self):
"""
"""
Microsoft Visual C++ VC7 registry key.
Microsoft Visual C++ VC7 registry key.
Return
------
str
Registry key
"""
"""
return
os.path.
join(self.sxs, '
VC7
')
return join(self.sxs, '
VC7
')
@property
@property
def vs(self):
def vs(self):
"""
"""
Microsoft Visual Studio VS7 registry key.
Microsoft Visual Studio VS7 registry key.
Return
------
str
Registry key
"""
"""
return
os.path.
join(self.sxs, '
VS7
')
return join(self.sxs, '
VS7
')
@property
@property
def vc_for_python(self):
def vc_for_python(self):
"""
"""
Microsoft Visual C++ for Python registry key.
Microsoft Visual C++ for Python registry key.
Return
------
str
Registry key
"""
"""
return r'
DevDiv
\
VCForPython
'
return r'
DevDiv
\
VCForPython
'
...
@@ -384,6 +418,11 @@ class RegistryInfo:
...
@@ -384,6 +418,11 @@ class RegistryInfo:
def microsoft_sdk(self):
def microsoft_sdk(self):
"""
"""
Microsoft SDK registry key.
Microsoft SDK registry key.
Return
------
str
Registry key
"""
"""
return '
Microsoft
SDKs
'
return '
Microsoft
SDKs
'
...
@@ -391,20 +430,35 @@ class RegistryInfo:
...
@@ -391,20 +430,35 @@ class RegistryInfo:
def windows_sdk(self):
def windows_sdk(self):
"""
"""
Microsoft Windows/Platform SDK registry key.
Microsoft Windows/Platform SDK registry key.
Return
------
str
Registry key
"""
"""
return
os.path.
join(self.microsoft_sdk, '
Windows
')
return join(self.microsoft_sdk, '
Windows
')
@property
@property
def netfx_sdk(self):
def netfx_sdk(self):
"""
"""
Microsoft .NET Framework SDK registry key.
Microsoft .NET Framework SDK registry key.
Return
------
str
Registry key
"""
"""
return
os.path.
join(self.microsoft_sdk, '
NETFXSDK
')
return join(self.microsoft_sdk, '
NETFXSDK
')
@property
@property
def windows_kits_roots(self):
def windows_kits_roots(self):
"""
"""
Microsoft Windows Kits Roots registry key.
Microsoft Windows Kits Roots registry key.
Return
------
str
Registry key
"""
"""
return r'
Windows
Kits
\
Installed
Roots
'
return r'
Windows
Kits
\
Installed
Roots
'
...
@@ -421,10 +475,11 @@ class RegistryInfo:
...
@@ -421,10 +475,11 @@ class RegistryInfo:
Return
Return
------
------
str: value
str
Registry key
"""
"""
node64 = '' if self.pi.current_is_x86() or x86 else '
Wow6432Node
'
node64 = '' if self.pi.current_is_x86() or x86 else '
Wow6432Node
'
return
os.path.
join('
Software
', node64, '
Microsoft
', key)
return join('
Software
', node64, '
Microsoft
', key)
def lookup(self, key, name):
def lookup(self, key, name):
"""
"""
...
@@ -439,18 +494,19 @@ class RegistryInfo:
...
@@ -439,18 +494,19 @@ class RegistryInfo:
Return
Return
------
------
str: value
str
value
"""
"""
KEY_READ
= winreg.KEY_READ
key_read
= winreg.KEY_READ
openkey = winreg.OpenKey
openkey = winreg.OpenKey
ms = self.microsoft
ms = self.microsoft
for hkey in self.HKEYS:
for hkey in self.HKEYS:
try:
try:
bkey = openkey(hkey, ms(key), 0,
KEY_READ
)
bkey = openkey(hkey, ms(key), 0,
key_read
)
except (OSError, IOError):
except (OSError, IOError):
if not self.pi.current_is_x86():
if not self.pi.current_is_x86():
try:
try:
bkey = openkey(hkey, ms(key, True), 0,
KEY_READ
)
bkey = openkey(hkey, ms(key, True), 0,
key_read
)
except (OSError, IOError):
except (OSError, IOError):
continue
continue
else:
else:
...
@@ -463,7 +519,7 @@ class RegistryInfo:
...
@@ -463,7 +519,7 @@ class RegistryInfo:
class SystemInfo:
class SystemInfo:
"""
"""
Microsoft Windows and Visual Studio related system in
ormations
.
Microsoft Windows and Visual Studio related system in
formation
.
Parameters
Parameters
----------
----------
...
@@ -474,30 +530,52 @@ class SystemInfo:
...
@@ -474,30 +530,52 @@ class SystemInfo:
"""
"""
# Variables and properties in this class use originals CamelCase variables
# Variables and properties in this class use originals CamelCase variables
# names from Microsoft source files for more easy compar
a
ison.
# names from Microsoft source files for more easy comparison.
WinDir =
safe_env
.get('
WinDir
', '')
WinDir =
environ
.get('
WinDir
', '')
ProgramFiles =
safe_env
.get('
ProgramFiles
', '')
ProgramFiles =
environ
.get('
ProgramFiles
', '')
ProgramFilesx86 =
safe_env
.get('
ProgramFiles
(
x86
)
', ProgramFiles)
ProgramFilesx86 =
environ
.get('
ProgramFiles
(
x86
)
', ProgramFiles)
def __init__(self, registry_info, vc_ver=None):
def __init__(self, registry_info, vc_ver=None):
self.ri = registry_info
self.ri = registry_info
self.pi = self.ri.pi
self.pi = self.ri.pi
self.vc_ver = vc_ver or self._find_latest_available_vc_ver()
def _find_latest_available_vc_ver(self):
self.known_vs_paths = self.find_programdata_vs_vers()
try:
return self.find_available_vc_vers()[-1]
# Except for VS15+, VC version is aligned with VS version
except IndexError:
self.vs_ver = self.vc_ver = (
err = '
No
Microsoft
Visual
C
++
version
found
'
vc_ver or self._find_latest_available_vs_ver())
raise distutils.errors.DistutilsPlatformError(err)
def _find_latest_available_vs_ver(self):
"""
Find the latest VC version
Return
------
float
version
"""
reg_vc_vers = self.find_reg_vs_vers()
if not (reg_vc_vers or self.known_vs_paths):
raise distutils.errors.DistutilsPlatformError(
'
No
Microsoft
Visual
C
++
version
found
')
vc_vers = set(reg_vc_vers)
vc_vers.update(self.known_vs_paths)
return sorted(vc_vers)[-1]
def find_
available_vc
_vers(self):
def find_
reg_vs
_vers(self):
"""
"""
Find all available Microsoft Visual C++ versions.
Find Microsoft Visual Studio versions available in registry.
Return
------
list of float
Versions
"""
"""
ms = self.ri.microsoft
ms = self.ri.microsoft
vckeys = (self.ri.vc, self.ri.vc_for_python, self.ri.vs)
vckeys = (self.ri.vc, self.ri.vc_for_python, self.ri.vs)
v
c
_vers = []
v
s
_vers = []
for hkey in self.ri.HKEYS:
for hkey in self.ri.HKEYS:
for key in vckeys:
for key in vckeys:
try:
try:
...
@@ -508,49 +586,108 @@ class SystemInfo:
...
@@ -508,49 +586,108 @@ class SystemInfo:
for i in range(values):
for i in range(values):
try:
try:
ver = float(winreg.EnumValue(bkey, i)[0])
ver = float(winreg.EnumValue(bkey, i)[0])
if ver not in v
c
_vers:
if ver not in v
s
_vers:
v
c
_vers.append(ver)
v
s
_vers.append(ver)
except ValueError:
except ValueError:
pass
pass
for i in range(subkeys):
for i in range(subkeys):
try:
try:
ver = float(winreg.EnumKey(bkey, i))
ver = float(winreg.EnumKey(bkey, i))
if ver not in v
c
_vers:
if ver not in v
s
_vers:
v
c
_vers.append(ver)
v
s
_vers.append(ver)
except ValueError:
except ValueError:
pass
pass
return sorted(vc_vers)
return sorted(vs_vers)
def find_programdata_vs_vers(self):
r"""
Find Visual studio 2017+ versions from information in
"C:
\
P
r
ogramData
\
Mic
r
osoft
\
Visu
a
lStudio
\
P
a
ckages
\
_I
n
stances".
Return
------
dict
float version as key, path as value.
"""
vs_versions = {}
instances_dir =
\
r'
C
:
\
ProgramData
\
Microsoft
\
VisualStudio
\
Packages
\
_Instances
'
try:
hashed_names = listdir(instances_dir)
except (OSError, IOError):
# Directory not exists with all Visual Studio versions
return vs_versions
for name in hashed_names:
try:
# Get VS installation path from "state.json" file
state_path = join(instances_dir, name, '
state
.
json
')
with open(state_path, '
rt
', encoding='
utf
-
8
') as state_file:
state = json.load(state_file)
vs_path = state['
installationPath
']
# Raises OSError if this VS installation does not contain VC
listdir(join(vs_path, r'
VC
\
Tools
\
MSVC
'))
# Store version and path
vs_versions[self._as_float_version(
state['
installationVersion
'])] = vs_path
except (OSError, IOError, KeyError):
# Skip if "state.json" file is missing or bad format
continue
return vs_versions
@staticmethod
def _as_float_version(version):
"""
Return a string version as a simplified float version (major.minor)
Parameters
----------
version: str
Version.
Return
------
float
version
"""
return float('
.
'.join(version.split('
.
')[:2]))
@property
@property
def VSInstallDir(self):
def VSInstallDir(self):
"""
"""
Microsoft Visual Studio directory.
Microsoft Visual Studio directory.
Return
------
str
path
"""
"""
# Default path
# Default path
name = '
Microsoft
Visual
Studio
%
0.1
f' % self.vc_ver
default = join(self.ProgramFilesx86,
default = os.path.join(self.ProgramFilesx86, name
)
'
Microsoft
Visual
Studio
%
0.1
f' % self.vs_ver
)
# Try to get path from registry, if fail use default path
# Try to get path from registry, if fail use default path
return self.ri.lookup(self.ri.vs, '
%
0.1
f' % self.v
c
_ver) or default
return self.ri.lookup(self.ri.vs, '
%
0.1
f' % self.v
s
_ver) or default
@property
@property
def VCInstallDir(self):
def VCInstallDir(self):
"""
"""
Microsoft Visual C++ directory.
Microsoft Visual C++ directory.
"""
self.VSInstallDir
guess_vc = self._guess_vc() or self._guess_vc_legacy()
# Try to get "VC++ for Python" path from registry as default path
reg_path = os.path.join(self.ri.vc_for_python, '
%
0.1
f' % self.vc_ver)
python_vc = self.ri.lookup(reg_path, '
installdir
')
default_vc = os.path.join(python_vc, '
VC
') if python_vc else guess_vc
# Try to get path from registry, if fail use default path
Return
path = self.ri.lookup(self.ri.vc, '
%
0.1
f' % self.vc_ver) or default_vc
------
str
path
"""
path = self._guess_vc() or self._guess_vc_legacy()
if not
os.path.
isdir(path):
if not isdir(path):
msg = '
Microsoft
Visual
C
++
directory
not
found
'
msg = '
Microsoft
Visual
C
++
directory
not
found
'
raise distutils.errors.DistutilsPlatformError(msg)
raise distutils.errors.DistutilsPlatformError(msg)
...
@@ -558,186 +695,256 @@ class SystemInfo:
...
@@ -558,186 +695,256 @@ class SystemInfo:
def _guess_vc(self):
def _guess_vc(self):
"""
"""
Locate Visual C for 2017
Locate Visual C++ for VS2017+.
Return
------
str
path
"""
"""
if self.vc_ver <= 14.0:
if self.vs_ver <= 14.0:
return
return ''
try:
# First search in known VS paths
vs_dir = self.known_vs_paths[self.vs_ver]
except KeyError:
# Else, search with path from registry
vs_dir = self.VSInstallDir
guess_vc = join(vs_dir, r'
VC
\
Tools
\
MSVC
')
default = r'
VC
\
Tools
\
MSVC
'
guess_vc = os.path.join(self.VSInstallDir, default)
# Subdir with VC exact version as name
# Subdir with VC exact version as name
try:
try:
vc_exact_ver = os.listdir(guess_vc)[-1]
# Update the VC version with real one instead of VS version
return os.path.join(guess_vc, vc_exact_ver)
vc_ver = listdir(guess_vc)[-1]
self.vc_ver = self._as_float_version(vc_ver)
return join(guess_vc, vc_ver)
except (OSError, IOError, IndexError):
except (OSError, IOError, IndexError):
pass
return ''
def _guess_vc_legacy(self):
def _guess_vc_legacy(self):
"""
"""
Locate Visual C for versions prior to 2017
Locate Visual C++ for versions prior to 2017.
Return
------
str
path
"""
"""
default = r'
Microsoft
Visual
Studio
%
0.1
f
\
VC
' % self.vc_ver
default = join(self.ProgramFilesx86,
return os.path.join(self.ProgramFilesx86, default)
r'
Microsoft
Visual
Studio
%
0.1
f
\
VC
' % self.vs_ver)
# Try to get "VC++ for Python" path from registry as default path
reg_path = join(self.ri.vc_for_python, '
%
0.1
f' % self.vs_ver)
python_vc = self.ri.lookup(reg_path, '
installdir
')
default_vc = join(python_vc, '
VC
') if python_vc else default
# Try to get path from registry, if fail use default path
return self.ri.lookup(self.ri.vc, '
%
0.1
f' % self.vs_ver) or default_vc
@property
@property
def WindowsSdkVersion(self):
def WindowsSdkVersion(self):
"""
"""
Microsoft Windows SDK versions for specified MSVC++ version.
Microsoft Windows SDK versions for specified MSVC++ version.
"""
if self.vc_ver <= 9.0:
Return
return ('
7.0
', '
6.1
', '
6.0
a
')
------
elif self.vc_ver == 10.0:
tuple of str
return ('
7.1
', '
7.0
a
')
versions
elif self.vc_ver == 11.0:
"""
return ('
8.0
', '
8.0
a
')
if self.vs_ver <= 9.0:
elif self.vc_ver == 12.0:
return '
7.0
', '
6.1
', '
6.0
a
'
return ('
8.1
', '
8.1
a
')
elif self.vs_ver == 10.0:
elif self.vc_ver >= 14.0:
return '
7.1
', '
7.0
a
'
return ('
10.0
', '
8.1
')
elif self.vs_ver == 11.0:
return '
8.0
', '
8.0
a
'
elif self.vs_ver == 12.0:
return '
8.1
', '
8.1
a
'
elif self.vs_ver >= 14.0:
return '
10.0
', '
8.1
'
@property
@property
def WindowsSdkLastVersion(self):
def WindowsSdkLastVersion(self):
"""
"""
Microsoft Windows SDK last version
Microsoft Windows SDK last version.
Return
------
str
version
"""
"""
return self._use_last_dir_name(os.path.join(
return self._use_last_dir_name(join(self.WindowsSdkDir, '
lib
'))
self.WindowsSdkDir, '
lib
'))
@property
@property
def WindowsSdkDir(self):
def WindowsSdkDir(self):
"""
"""
Microsoft Windows SDK directory.
Microsoft Windows SDK directory.
Return
------
str
path
"""
"""
sdkdir = ''
sdkdir = ''
for ver in self.WindowsSdkVersion:
for ver in self.WindowsSdkVersion:
# Try to get it from registry
# Try to get it from registry
loc =
os.path.
join(self.ri.windows_sdk, '
v
%
s
' % ver)
loc = join(self.ri.windows_sdk, '
v
%
s
' % ver)
sdkdir = self.ri.lookup(loc, '
installationfolder
')
sdkdir = self.ri.lookup(loc, '
installationfolder
')
if sdkdir:
if sdkdir:
break
break
if not sdkdir or not
os.path.
isdir(sdkdir):
if not sdkdir or not isdir(sdkdir):
# Try to get "VC++ for Python" version from registry
# Try to get "VC++ for Python" version from registry
path =
os.path.
join(self.ri.vc_for_python, '
%
0.1
f' % self.vc_ver)
path = join(self.ri.vc_for_python, '
%
0.1
f' % self.vc_ver)
install_base = self.ri.lookup(path, '
installdir
')
install_base = self.ri.lookup(path, '
installdir
')
if install_base:
if install_base:
sdkdir =
os.path.
join(install_base, '
WinSDK
')
sdkdir = join(install_base, '
WinSDK
')
if not sdkdir or not
os.path.
isdir(sdkdir):
if not sdkdir or not isdir(sdkdir):
# If fail, use default new path
# If fail, use default new path
for ver in self.WindowsSdkVersion:
for ver in self.WindowsSdkVersion:
intver = ver[:ver.rfind('
.
')]
intver = ver[:ver.rfind('
.
')]
path = r'
Microsoft
SDKs
\
Windows
Kits
\
%
s
' %
(intver)
path = r'
Microsoft
SDKs
\
Windows
Kits
\
%
s
' %
intver
d =
os.path.
join(self.ProgramFiles, path)
d = join(self.ProgramFiles, path)
if
os.path.
isdir(d):
if isdir(d):
sdkdir = d
sdkdir = d
if not sdkdir or not
os.path.
isdir(sdkdir):
if not sdkdir or not isdir(sdkdir):
# If fail, use default old path
# If fail, use default old path
for ver in self.WindowsSdkVersion:
for ver in self.WindowsSdkVersion:
path = r'
Microsoft
SDKs
\
Windows
\
v
%
s
' % ver
path = r'
Microsoft
SDKs
\
Windows
\
v
%
s
' % ver
d =
os.path.
join(self.ProgramFiles, path)
d = join(self.ProgramFiles, path)
if
os.path.
isdir(d):
if isdir(d):
sdkdir = d
sdkdir = d
if not sdkdir:
if not sdkdir:
# If fail, use Platform SDK
# If fail, use Platform SDK
sdkdir =
os.path.
join(self.VCInstallDir, '
PlatformSDK
')
sdkdir = join(self.VCInstallDir, '
PlatformSDK
')
return sdkdir
return sdkdir
@property
@property
def WindowsSDKExecutablePath(self):
def WindowsSDKExecutablePath(self):
"""
"""
Microsoft Windows SDK executable directory.
Microsoft Windows SDK executable directory.
Return
------
str
path
"""
"""
# Find WinSDK NetFx Tools registry dir name
# Find WinSDK NetFx Tools registry dir name
if self.v
c
_ver <= 11.0:
if self.v
s
_ver <= 11.0:
netfxver = 35
netfxver = 35
arch = ''
arch = ''
else:
else:
netfxver = 40
netfxver = 40
hidex86 = True if self.v
c
_ver <= 12.0 else False
hidex86 = True if self.v
s
_ver <= 12.0 else False
arch = self.pi.current_dir(x64=True, hidex86=hidex86)
arch = self.pi.current_dir(x64=True, hidex86=hidex86)
fx = '
WinSDK
-
NetFx
%
dTools
%
s
' % (netfxver, arch.replace('
\\
', '
-
'))
fx = '
WinSDK
-
NetFx
%
dTools
%
s
' % (netfxver, arch.replace('
\\
', '
-
'))
# list
e
all possibles registry paths
# list all possibles registry paths
regpaths = []
regpaths = []
if self.v
c
_ver >= 14.0:
if self.v
s
_ver >= 14.0:
for ver in self.NetFxSdkVersion:
for ver in self.NetFxSdkVersion:
regpaths += [
os.path.
join(self.ri.netfx_sdk, ver, fx)]
regpaths += [join(self.ri.netfx_sdk, ver, fx)]
for ver in self.WindowsSdkVersion:
for ver in self.WindowsSdkVersion:
regpaths += [
os.path.
join(self.ri.windows_sdk, '
v
%
sA
' % ver, fx)]
regpaths += [join(self.ri.windows_sdk, '
v
%
sA
' % ver, fx)]
# Return installation folder from the more recent path
# Return installation folder from the more recent path
for path in regpaths:
for path in regpaths:
execpath = self.ri.lookup(path, '
installationfolder
')
execpath = self.ri.lookup(path, '
installationfolder
')
if execpath:
if execpath:
break
return execpath
return execpath
@property
@property
def FSharpInstallDir(self):
def FSharpInstallDir(self):
"""
"""
Microsoft Visual F# directory.
Microsoft Visual F# directory.
Return
------
str
path
"""
"""
path = r'
%
0.1
f
\
Setup
\
F
#' % self.vc_ver
path = join(self.ri.visualstudio, r'
%
0.1
f
\
Setup
\
F
#' % self.vs_ver)
path
=
os
.
path
.
join
(
self
.
ri
.
visualstudio
,
path
)
return
self
.
ri
.
lookup
(
path
,
'productdir'
)
or
''
return
self
.
ri
.
lookup
(
path
,
'productdir'
)
or
''
@
property
@
property
def
UniversalCRTSdkDir
(
self
):
def
UniversalCRTSdkDir
(
self
):
"""
"""
Microsoft Universal CRT SDK directory.
Microsoft Universal CRT SDK directory.
Return
------
str
path
"""
"""
# Set Kit Roots versions for specified MSVC++ version
# Set Kit Roots versions for specified MSVC++ version
if
self
.
vc_ver
>=
14.0
:
vers
=
(
'10'
,
'81'
)
if
self
.
vs_ver
>=
14.0
else
()
vers
=
(
'10'
,
'81'
)
else
:
vers
=
()
# Find path of the more recent Kit
# Find path of the more recent Kit
for
ver
in
vers
:
for
ver
in
vers
:
sdkdir
=
self
.
ri
.
lookup
(
self
.
ri
.
windows_kits_roots
,
sdkdir
=
self
.
ri
.
lookup
(
self
.
ri
.
windows_kits_roots
,
'kitsroot%s'
%
ver
)
'kitsroot%s'
%
ver
)
if
sdkdir
:
if
sdkdir
:
break
return
sdkdir
or
''
return
sdkdir
or
''
@
property
@
property
def
UniversalCRTSdkLastVersion
(
self
):
def
UniversalCRTSdkLastVersion
(
self
):
"""
"""
Microsoft Universal C Runtime SDK last version
Microsoft Universal C Runtime SDK last version.
Return
------
str
version
"""
"""
return
self
.
_use_last_dir_name
(
os
.
path
.
join
(
return
self
.
_use_last_dir_name
(
join
(
self
.
UniversalCRTSdkDir
,
'lib'
))
self
.
UniversalCRTSdkDir
,
'lib'
))
@
property
@
property
def
NetFxSdkVersion
(
self
):
def
NetFxSdkVersion
(
self
):
"""
"""
Microsoft .NET Framework SDK versions.
Microsoft .NET Framework SDK versions.
Return
------
tuple of str
versions
"""
"""
# Set FxSdk versions for specified
MSVC++
version
# Set FxSdk versions for specified
VS
version
if
self
.
vc_ver
>=
14.0
:
return
((
'4.7.2'
,
'4.7.1'
,
'4.7'
,
return
(
'4.6.1'
,
'4.6'
)
'4.6.2'
,
'4.6.1'
,
'4.6'
,
else
:
'4.5.2'
,
'4.5.1'
,
'4.5'
)
return
(
)
if
self
.
vs_ver
>=
14.0
else
()
)
@
property
@
property
def
NetFxSdkDir
(
self
):
def
NetFxSdkDir
(
self
):
"""
"""
Microsoft .NET Framework SDK directory.
Microsoft .NET Framework SDK directory.
Return
------
str
path
"""
"""
sdkdir
=
''
for
ver
in
self
.
NetFxSdkVersion
:
for
ver
in
self
.
NetFxSdkVersion
:
loc
=
os
.
path
.
join
(
self
.
ri
.
netfx_sdk
,
ver
)
loc
=
join
(
self
.
ri
.
netfx_sdk
,
ver
)
sdkdir
=
self
.
ri
.
lookup
(
loc
,
'kitsinstallationfolder'
)
sdkdir
=
self
.
ri
.
lookup
(
loc
,
'kitsinstallationfolder'
)
if
sdkdir
:
if
sdkdir
:
break
break
return
sdkdir
or
''
return
sdkdir
@
property
@
property
def
FrameworkDir32
(
self
):
def
FrameworkDir32
(
self
):
"""
"""
Microsoft .NET Framework 32bit directory.
Microsoft .NET Framework 32bit directory.
Return
------
str
path
"""
"""
# Default path
# Default path
guess_fw
=
os
.
path
.
join
(
self
.
WinDir
,
r'Microsoft.NET\
F
ramework'
)
guess_fw
=
join
(
self
.
WinDir
,
r'Microsoft.NET\
F
ramework'
)
# Try to get path from registry, if fail use default path
# Try to get path from registry, if fail use default path
return
self
.
ri
.
lookup
(
self
.
ri
.
vc
,
'frameworkdir32'
)
or
guess_fw
return
self
.
ri
.
lookup
(
self
.
ri
.
vc
,
'frameworkdir32'
)
or
guess_fw
...
@@ -746,9 +953,14 @@ class SystemInfo:
...
@@ -746,9 +953,14 @@ class SystemInfo:
def
FrameworkDir64
(
self
):
def
FrameworkDir64
(
self
):
"""
"""
Microsoft .NET Framework 64bit directory.
Microsoft .NET Framework 64bit directory.
Return
------
str
path
"""
"""
# Default path
# Default path
guess_fw
=
os
.
path
.
join
(
self
.
WinDir
,
r'Microsoft.NET\
F
ramework64'
)
guess_fw
=
join
(
self
.
WinDir
,
r'Microsoft.NET\
F
ramework64'
)
# Try to get path from registry, if fail use default path
# Try to get path from registry, if fail use default path
return
self
.
ri
.
lookup
(
self
.
ri
.
vc
,
'frameworkdir64'
)
or
guess_fw
return
self
.
ri
.
lookup
(
self
.
ri
.
vc
,
'frameworkdir64'
)
or
guess_fw
...
@@ -757,6 +969,11 @@ class SystemInfo:
...
@@ -757,6 +969,11 @@ class SystemInfo:
def
FrameworkVersion32
(
self
):
def
FrameworkVersion32
(
self
):
"""
"""
Microsoft .NET Framework 32bit versions.
Microsoft .NET Framework 32bit versions.
Return
------
tuple of str
versions
"""
"""
return
self
.
_find_dot_net_versions
(
32
)
return
self
.
_find_dot_net_versions
(
32
)
...
@@ -764,6 +981,11 @@ class SystemInfo:
...
@@ -764,6 +981,11 @@ class SystemInfo:
def
FrameworkVersion64
(
self
):
def
FrameworkVersion64
(
self
):
"""
"""
Microsoft .NET Framework 64bit versions.
Microsoft .NET Framework 64bit versions.
Return
------
tuple of str
versions
"""
"""
return
self
.
_find_dot_net_versions
(
64
)
return
self
.
_find_dot_net_versions
(
64
)
...
@@ -775,6 +997,11 @@ class SystemInfo:
...
@@ -775,6 +997,11 @@ class SystemInfo:
----------
----------
bits: int
bits: int
Platform number of bits: 32 or 64.
Platform number of bits: 32 or 64.
Return
------
tuple of str
versions
"""
"""
# Find actual .NET version in registry
# Find actual .NET version in registry
reg_ver
=
self
.
ri
.
lookup
(
self
.
ri
.
vc
,
'frameworkver%d'
%
bits
)
reg_ver
=
self
.
ri
.
lookup
(
self
.
ri
.
vc
,
'frameworkver%d'
%
bits
)
...
@@ -782,18 +1009,17 @@ class SystemInfo:
...
@@ -782,18 +1009,17 @@ class SystemInfo:
ver
=
reg_ver
or
self
.
_use_last_dir_name
(
dot_net_dir
,
'v'
)
or
''
ver
=
reg_ver
or
self
.
_use_last_dir_name
(
dot_net_dir
,
'v'
)
or
''
# Set .NET versions for specified MSVC++ version
# Set .NET versions for specified MSVC++ version
if
self
.
vc_ver
>=
12.0
:
if
self
.
vs_ver
>=
12.0
:
frameworkver
=
(
ver
,
'v4.0'
)
return
ver
,
'v4.0'
elif
self
.
vc_ver
>=
10.0
:
elif
self
.
vs_ver
>=
10.0
:
frameworkver
=
(
'v4.0.30319'
if
ver
.
lower
()[:
2
]
!=
'v4'
else
ver
,
return
'v4.0.30319'
if
ver
.
lower
()[:
2
]
!=
'v4'
else
ver
,
'v3.5'
'v3.5'
)
elif
self
.
vs_ver
==
9.0
:
elif
self
.
vc_ver
==
9.0
:
return
'v3.5'
,
'v2.0.50727'
frameworkver
=
(
'v3.5'
,
'v2.0.50727'
)
elif
self
.
vs_ver
==
8.0
:
if
self
.
vc_ver
==
8.0
:
return
'v3.0'
,
'v2.0.50727'
frameworkver
=
(
'v3.0'
,
'v2.0.50727'
)
return
frameworkver
@
staticmethod
def
_use_last_dir_name
(
path
,
prefix
=
''
):
def
_use_last_dir_name
(
self
,
path
,
prefix
=
''
):
"""
"""
Return name of the last dir in path or '' if no dir found.
Return name of the last dir in path or '' if no dir found.
...
@@ -802,12 +1028,17 @@ class SystemInfo:
...
@@ -802,12 +1028,17 @@ class SystemInfo:
path: str
path: str
Use dirs in this path
Use dirs in this path
prefix: str
prefix: str
Use only dirs startings by this prefix
Use only dirs starting by this prefix
Return
------
str
name
"""
"""
matching_dirs
=
(
matching_dirs
=
(
dir_name
dir_name
for
dir_name
in
reversed
(
os
.
listdir
(
path
))
for
dir_name
in
reversed
(
listdir
(
path
))
if
os
.
path
.
isdir
(
os
.
path
.
join
(
path
,
dir_name
))
and
if
isdir
(
join
(
path
,
dir_name
))
and
dir_name
.
startswith
(
prefix
)
dir_name
.
startswith
(
prefix
)
)
)
return
next
(
matching_dirs
,
None
)
or
''
return
next
(
matching_dirs
,
None
)
or
''
...
@@ -818,7 +1049,7 @@ class EnvironmentInfo:
...
@@ -818,7 +1049,7 @@ class EnvironmentInfo:
Return environment variables for specified Microsoft Visual C++ version
Return environment variables for specified Microsoft Visual C++ version
and platform : Lib, Include, Path and libpath.
and platform : Lib, Include, Path and libpath.
This function is compatible with Microsoft Visual C++ 9.0 to 14.
0
.
This function is compatible with Microsoft Visual C++ 9.0 to 14.
X
.
Script created by analysing Microsoft environment configuration files like
Script created by analysing Microsoft environment configuration files like
"vcvars[...].bat", "SetEnv.Cmd", "vcbuildtools.bat", ...
"vcvars[...].bat", "SetEnv.Cmd", "vcbuildtools.bat", ...
...
@@ -835,7 +1066,7 @@ class EnvironmentInfo:
...
@@ -835,7 +1066,7 @@ class EnvironmentInfo:
"""
"""
# Variables and properties in this class use originals CamelCase variables
# Variables and properties in this class use originals CamelCase variables
# names from Microsoft source files for more easy compar
a
ison.
# names from Microsoft source files for more easy comparison.
def
__init__
(
self
,
arch
,
vc_ver
=
None
,
vc_min_ver
=
0
):
def
__init__
(
self
,
arch
,
vc_ver
=
None
,
vc_min_ver
=
0
):
self
.
pi
=
PlatformInfo
(
arch
)
self
.
pi
=
PlatformInfo
(
arch
)
...
@@ -846,205 +1077,255 @@ class EnvironmentInfo:
...
@@ -846,205 +1077,255 @@ class EnvironmentInfo:
err
=
'No suitable Microsoft Visual C++ version found'
err
=
'No suitable Microsoft Visual C++ version found'
raise
distutils
.
errors
.
DistutilsPlatformError
(
err
)
raise
distutils
.
errors
.
DistutilsPlatformError
(
err
)
@
property
def
vs_ver
(
self
):
"""
Microsoft Visual Studio.
Return
------
float
version
"""
return
self
.
si
.
vs_ver
@
property
@
property
def
vc_ver
(
self
):
def
vc_ver
(
self
):
"""
"""
Microsoft Visual C++ version.
Microsoft Visual C++ version.
Return
------
float
version
"""
"""
return
self
.
si
.
vc_ver
return
self
.
si
.
vc_ver
@
property
@
property
def
VSTools
(
self
):
def
VSTools
(
self
):
"""
"""
Microsoft Visual Studio Tools
Microsoft Visual Studio Tools.
Return
------
list of str
paths
"""
"""
paths
=
[
r'Common7\
IDE
', r'
Common7
\
Tools
']
paths
=
[
r'Common7\
IDE
', r'
Common7
\
Tools
']
if self.v
c
_ver >= 14.0:
if self.v
s
_ver >= 14.0:
arch_subdir = self.pi.current_dir(hidex86=True, x64=True)
arch_subdir = self.pi.current_dir(hidex86=True, x64=True)
paths += [r'
Common7
\
IDE
\
CommonExtensions
\
Microsoft
\
TestWindow
']
paths += [r'
Common7
\
IDE
\
CommonExtensions
\
Microsoft
\
TestWindow
']
paths += [r'
Team
Tools
\
Performance
Tools
']
paths += [r'
Team
Tools
\
Performance
Tools
']
paths += [r'
Team
Tools
\
Performance
Tools
%
s
' % arch_subdir]
paths += [r'
Team
Tools
\
Performance
Tools
%
s
' % arch_subdir]
return [
os.path.
join(self.si.VSInstallDir, path) for path in paths]
return [join(self.si.VSInstallDir, path) for path in paths]
@property
@property
def VCIncludes(self):
def VCIncludes(self):
"""
"""
Microsoft Visual C++ & Microsoft Foundation Class Includes
Microsoft Visual C++ & Microsoft Foundation Class Includes.
Return
------
list of str
paths
"""
"""
return [
os.path.
join(self.si.VCInstallDir, '
Include
'),
return [join(self.si.VCInstallDir, '
Include
'),
os.path.
join(self.si.VCInstallDir, r'
ATLMFC
\
Include
')]
join(self.si.VCInstallDir, r'
ATLMFC
\
Include
')]
@property
@property
def VCLibraries(self):
def VCLibraries(self):
"""
"""
Microsoft Visual C++ & Microsoft Foundation Class Libraries
Microsoft Visual C++ & Microsoft Foundation Class Libraries.
Return
------
list of str
paths
"""
"""
if self.v
c
_ver >= 15.0:
if self.v
s
_ver >= 15.0:
arch_subdir = self.pi.target_dir(x64=True)
arch_subdir = self.pi.target_dir(x64=True)
else:
else:
arch_subdir = self.pi.target_dir(hidex86=True)
arch_subdir = self.pi.target_dir(hidex86=True)
paths = ['
Lib
%
s
' % arch_subdir, r'
ATLMFC
\
Lib
%
s
' % arch_subdir]
paths = ['
Lib
%
s
' % arch_subdir, r'
ATLMFC
\
Lib
%
s
' % arch_subdir]
if self.v
c
_ver >= 14.0:
if self.v
s
_ver >= 14.0:
paths += [r'
Lib
\
store
%
s
' % arch_subdir]
paths += [r'
Lib
\
store
%
s
' % arch_subdir]
return [
os.path.
join(self.si.VCInstallDir, path) for path in paths]
return [join(self.si.VCInstallDir, path) for path in paths]
@property
@property
def VCStoreRefs(self):
def VCStoreRefs(self):
"""
"""
Microsoft Visual C++ store references Libraries
Microsoft Visual C++ store references Libraries.
Return
------
list of str
paths
"""
"""
if self.v
c
_ver < 14.0:
if self.v
s
_ver < 14.0:
return []
return []
return [
os.path.
join(self.si.VCInstallDir, r'
Lib
\
store
\
references
')]
return [join(self.si.VCInstallDir, r'
Lib
\
store
\
references
')]
@property
@property
def VCTools(self):
def VCTools(self):
"""
"""
Microsoft Visual C++ Tools
Microsoft Visual C++ Tools.
Return
------
list of str
paths
"""
"""
si = self.si
si = self.si
tools = [
os.path.
join(si.VCInstallDir, '
VCPackages
')]
tools = [join(si.VCInstallDir, '
VCPackages
')]
forcex86 = True if self.v
c
_ver <= 10.0 else False
forcex86 = True if self.v
s
_ver <= 10.0 else False
arch_subdir = self.pi.cross_dir(forcex86)
arch_subdir = self.pi.cross_dir(forcex86)
if arch_subdir:
if arch_subdir:
tools += [
os.path.
join(si.VCInstallDir, '
Bin
%
s
' % arch_subdir)]
tools += [join(si.VCInstallDir, '
Bin
%
s
' % arch_subdir)]
if self.v
c
_ver == 14.0:
if self.v
s
_ver == 14.0:
path = '
Bin
%
s
' % self.pi.current_dir(hidex86=True)
path = '
Bin
%
s
' % self.pi.current_dir(hidex86=True)
tools += [
os.path.
join(si.VCInstallDir, path)]
tools += [join(si.VCInstallDir, path)]
elif self.v
c
_ver >= 15.0:
elif self.v
s
_ver >= 15.0:
host_dir = (r'
bin
\
HostX86
%
s
' if self.pi.current_is_x86() else
host_dir = (r'
bin
\
HostX86
%
s
' if self.pi.current_is_x86() else
r'
bin
\
HostX64
%
s
')
r'
bin
\
HostX64
%
s
')
tools += [
os.path.
join(
tools += [join(
si.VCInstallDir, host_dir % self.pi.target_dir(x64=True))]
si.VCInstallDir, host_dir % self.pi.target_dir(x64=True))]
if self.pi.current_cpu != self.pi.target_cpu:
if self.pi.current_cpu != self.pi.target_cpu:
tools += [
os.path.
join(
tools += [join(
si.VCInstallDir, host_dir % self.pi.current_dir(x64=True))]
si.VCInstallDir, host_dir % self.pi.current_dir(x64=True))]
else:
else:
tools += [
os.path.
join(si.VCInstallDir, '
Bin
')]
tools += [join(si.VCInstallDir, '
Bin
')]
return tools
return tools
@property
@property
def OSLibraries(self):
def OSLibraries(self):
"""
"""
Microsoft Windows SDK Libraries
Microsoft Windows SDK Libraries.
Return
------
list of str
paths
"""
"""
if self.v
c
_ver <= 10.0:
if self.v
s
_ver <= 10.0:
arch_subdir = self.pi.target_dir(hidex86=True, x64=True)
arch_subdir = self.pi.target_dir(hidex86=True, x64=True)
return [
os.path.
join(self.si.WindowsSdkDir, '
Lib
%
s
' % arch_subdir)]
return [join(self.si.WindowsSdkDir, '
Lib
%
s
' % arch_subdir)]
else:
else:
arch_subdir = self.pi.target_dir(x64=True)
arch_subdir = self.pi.target_dir(x64=True)
lib =
os.path.
join(self.si.WindowsSdkDir, '
lib
')
lib = join(self.si.WindowsSdkDir, '
lib
')
libver = self._sdk_subdir
libver = self._sdk_subdir
return [
os.path.
join(lib, '
%
sum
%
s
' % (libver , arch_subdir))]
return [join(lib, '
%
sum
%
s
' % (libver , arch_subdir))]
@property
@property
def OSIncludes(self):
def OSIncludes(self):
"""
"""
Microsoft Windows SDK Include
Microsoft Windows SDK Include.
Return
------
list of str
paths
"""
"""
include =
os.path.
join(self.si.WindowsSdkDir, '
include
')
include = join(self.si.WindowsSdkDir, '
include
')
if self.v
c
_ver <= 10.0:
if self.v
s
_ver <= 10.0:
return [include,
os.path.
join(include, '
gl
')]
return [include, join(include, '
gl
')]
else:
else:
if self.v
c
_ver >= 14.0:
if self.v
s
_ver >= 14.0:
sdkver = self._sdk_subdir
sdkver = self._sdk_subdir
else:
else:
sdkver = ''
sdkver = ''
return [
os.path.
join(include, '
%
sshared
' % sdkver),
return [join(include, '
%
sshared
' % sdkver),
os.path.
join(include, '
%
sum
' % sdkver),
join(include, '
%
sum
' % sdkver),
os.path.
join(include, '
%
swinrt
' % sdkver)]
join(include, '
%
swinrt
' % sdkver)]
@property
@property
def OSLibpath(self):
def OSLibpath(self):
"""
"""
Microsoft Windows SDK Libraries Paths
Microsoft Windows SDK Libraries Paths.
Return
------
list of str
paths
"""
"""
ref =
os.path.
join(self.si.WindowsSdkDir, '
References
')
ref = join(self.si.WindowsSdkDir, '
References
')
libpath = []
libpath = []
if self.v
c
_ver <= 9.0:
if self.v
s
_ver <= 9.0:
libpath += self.OSLibraries
libpath += self.OSLibraries
if self.v
c
_ver >= 11.0:
if self.v
s
_ver >= 11.0:
libpath += [
os.path.
join(ref, r'
CommonConfiguration
\
Neutral
')]
libpath += [join(ref, r'
CommonConfiguration
\
Neutral
')]
if self.v
c
_ver >= 14.0:
if self.v
s
_ver >= 14.0:
libpath += [
libpath += [
ref,
ref,
os.path.join(self.si.WindowsSdkDir, '
UnionMetadata
'),
join(self.si.WindowsSdkDir, '
UnionMetadata
'),
os.path.join(
join(ref, '
Windows
.
Foundation
.
UniversalApiContract
', '
1.0
.
0.0
'),
ref,
join(ref, '
Windows
.
Foundation
.
FoundationContract
', '
1.0
.
0.0
'),
'
Windows
.
Foundation
.
UniversalApiContract
',
join(ref,'
Windows
.
Networking
.
Connectivity
.
WwanContract
',
'
1.0
.
0.0
',
'
1.0
.
0.0
'),
),
join(self.si.WindowsSdkDir, '
ExtensionSDKs
', '
Microsoft
.
VCLibs
',
os.path.join(
'
%
0.1
f' % self.vs_ver, '
References
', '
CommonConfiguration
',
ref,
'
neutral
'),
'
Windows
.
Foundation
.
FoundationContract
',
'
1.0
.
0.0
',
),
os.path.join(
ref,
'
Windows
.
Networking
.
Connectivity
.
WwanContract
',
'
1.0
.
0.0
',
),
os.path.join(
self.si.WindowsSdkDir,
'
ExtensionSDKs
',
'
Microsoft
.
VCLibs
',
'
%
0.1
f' % self.vc_ver,
'
References
',
'
CommonConfiguration
',
'
neutral
',
),
]
]
return libpath
return libpath
@property
@property
def SdkTools(self):
def SdkTools(self):
"""
"""
Microsoft Windows SDK Tools
Microsoft Windows SDK Tools.
Return
------
list of str
paths
"""
"""
return list(self._sdk_tools())
return list(self._sdk_tools())
def _sdk_tools(self):
def _sdk_tools(self):
"""
"""
Microsoft Windows SDK Tools paths generator
Microsoft Windows SDK Tools paths generator.
Return
------
generator of str
paths
"""
"""
if self.v
c
_ver < 15.0:
if self.v
s
_ver < 15.0:
bin_dir = '
Bin
' if self.v
c
_ver <= 11.0 else r'
Bin
\
x86
'
bin_dir = '
Bin
' if self.v
s
_ver <= 11.0 else r'
Bin
\
x86
'
yield
os.path.
join(self.si.WindowsSdkDir, bin_dir)
yield join(self.si.WindowsSdkDir, bin_dir)
if not self.pi.current_is_x86():
if not self.pi.current_is_x86():
arch_subdir = self.pi.current_dir(x64=True)
arch_subdir = self.pi.current_dir(x64=True)
path = '
Bin
%
s
' % arch_subdir
path = '
Bin
%
s
' % arch_subdir
yield
os.path.
join(self.si.WindowsSdkDir, path)
yield join(self.si.WindowsSdkDir, path)
if self.v
c_ver == 10.0 or self.vc_ver == 11.0
:
if self.v
s_ver in (10.0, 11.0)
:
if self.pi.target_is_x86():
if self.pi.target_is_x86():
arch_subdir = ''
arch_subdir = ''
else:
else:
arch_subdir = self.pi.current_dir(hidex86=True, x64=True)
arch_subdir = self.pi.current_dir(hidex86=True, x64=True)
path = r'
Bin
\
NETFX
4.0
Tools
%
s
' % arch_subdir
path = r'
Bin
\
NETFX
4.0
Tools
%
s
' % arch_subdir
yield
os.path.
join(self.si.WindowsSdkDir, path)
yield join(self.si.WindowsSdkDir, path)
elif self.v
c
_ver >= 15.0:
elif self.v
s
_ver >= 15.0:
path =
os.path.
join(self.si.WindowsSdkDir, '
Bin
')
path = join(self.si.WindowsSdkDir, '
Bin
')
arch_subdir = self.pi.current_dir(x64=True)
arch_subdir = self.pi.current_dir(x64=True)
sdkver = self.si.WindowsSdkLastVersion
sdkver = self.si.WindowsSdkLastVersion
yield
os.path.
join(path, '
%
s
%
s
' % (sdkver, arch_subdir))
yield join(path, '
%
s
%
s
' % (sdkver, arch_subdir))
if self.si.WindowsSDKExecutablePath:
if self.si.WindowsSDKExecutablePath:
yield self.si.WindowsSDKExecutablePath
yield self.si.WindowsSDKExecutablePath
...
@@ -1052,7 +1333,12 @@ class EnvironmentInfo:
...
@@ -1052,7 +1333,12 @@ class EnvironmentInfo:
@property
@property
def _sdk_subdir(self):
def _sdk_subdir(self):
"""
"""
Microsoft Windows SDK version subdir
Microsoft Windows SDK version subdir.
Return
------
str
subdir
"""
"""
ucrtver = self.si.WindowsSdkLastVersion
ucrtver = self.si.WindowsSdkLastVersion
return ('
%
s
\\
' % ucrtver) if ucrtver else ''
return ('
%
s
\\
' % ucrtver) if ucrtver else ''
...
@@ -1060,22 +1346,32 @@ class EnvironmentInfo:
...
@@ -1060,22 +1346,32 @@ class EnvironmentInfo:
@property
@property
def SdkSetup(self):
def SdkSetup(self):
"""
"""
Microsoft Windows SDK Setup
Microsoft Windows SDK Setup.
Return
------
list of str
paths
"""
"""
if self.v
c
_ver > 9.0:
if self.v
s
_ver > 9.0:
return []
return []
return [
os.path.
join(self.si.WindowsSdkDir, '
Setup
')]
return [join(self.si.WindowsSdkDir, '
Setup
')]
@property
@property
def FxTools(self):
def FxTools(self):
"""
"""
Microsoft .NET Framework Tools
Microsoft .NET Framework Tools.
Return
------
list of str
paths
"""
"""
pi = self.pi
pi = self.pi
si = self.si
si = self.si
if self.v
c
_ver <= 10.0:
if self.v
s
_ver <= 10.0:
include32 = True
include32 = True
include64 = not pi.target_is_x86() and not pi.current_is_x86()
include64 = not pi.target_is_x86() and not pi.current_is_x86()
else:
else:
...
@@ -1084,102 +1380,142 @@ class EnvironmentInfo:
...
@@ -1084,102 +1380,142 @@ class EnvironmentInfo:
tools = []
tools = []
if include32:
if include32:
tools += [
os.path.
join(si.FrameworkDir32, ver)
tools += [join(si.FrameworkDir32, ver)
for ver in si.FrameworkVersion32]
for ver in si.FrameworkVersion32]
if include64:
if include64:
tools += [
os.path.
join(si.FrameworkDir64, ver)
tools += [join(si.FrameworkDir64, ver)
for ver in si.FrameworkVersion64]
for ver in si.FrameworkVersion64]
return tools
return tools
@property
@property
def NetFxSDKLibraries(self):
def NetFxSDKLibraries(self):
"""
"""
Microsoft .Net Framework SDK Libraries
Microsoft .Net Framework SDK Libraries.
Return
------
list of str
paths
"""
"""
if self.v
c
_ver < 14.0 or not self.si.NetFxSdkDir:
if self.v
s
_ver < 14.0 or not self.si.NetFxSdkDir:
return []
return []
arch_subdir = self.pi.target_dir(x64=True)
arch_subdir = self.pi.target_dir(x64=True)
return [
os.path.
join(self.si.NetFxSdkDir, r'
lib
\
um
%
s
' % arch_subdir)]
return [join(self.si.NetFxSdkDir, r'
lib
\
um
%
s
' % arch_subdir)]
@property
@property
def NetFxSDKIncludes(self):
def NetFxSDKIncludes(self):
"""
"""
Microsoft .Net Framework SDK Includes
Microsoft .Net Framework SDK Includes.
Return
------
list of str
paths
"""
"""
if self.v
c
_ver < 14.0 or not self.si.NetFxSdkDir:
if self.v
s
_ver < 14.0 or not self.si.NetFxSdkDir:
return []
return []
return [
os.path.
join(self.si.NetFxSdkDir, r'
include
\
um
')]
return [join(self.si.NetFxSdkDir, r'
include
\
um
')]
@property
@property
def VsTDb(self):
def VsTDb(self):
"""
"""
Microsoft Visual Studio Team System Database
Microsoft Visual Studio Team System Database.
Return
------
list of str
paths
"""
"""
return [
os.path.
join(self.si.VSInstallDir, r'
VSTSDB
\
Deploy
')]
return [join(self.si.VSInstallDir, r'
VSTSDB
\
Deploy
')]
@property
@property
def MSBuild(self):
def MSBuild(self):
"""
"""
Microsoft Build Engine
Microsoft Build Engine.
Return
------
list of str
paths
"""
"""
if self.v
c
_ver < 12.0:
if self.v
s
_ver < 12.0:
return []
return []
elif self.v
c
_ver < 15.0:
elif self.v
s
_ver < 15.0:
base_path = self.si.ProgramFilesx86
base_path = self.si.ProgramFilesx86
arch_subdir = self.pi.current_dir(hidex86=True)
arch_subdir = self.pi.current_dir(hidex86=True)
else:
else:
base_path = self.si.VSInstallDir
base_path = self.si.VSInstallDir
arch_subdir = ''
arch_subdir = ''
path = r'
MSBuild
\
%
0.1
f
\
bin
%
s
' % (self.v
c
_ver, arch_subdir)
path = r'
MSBuild
\
%
0.1
f
\
bin
%
s
' % (self.v
s
_ver, arch_subdir)
build = [
os.path.
join(base_path, path)]
build = [join(base_path, path)]
if self.v
c
_ver >= 15.0:
if self.v
s
_ver >= 15.0:
# Add Roslyn C# & Visual Basic Compiler
# Add Roslyn C# & Visual Basic Compiler
build += [
os.path.
join(base_path, path, '
Roslyn
')]
build += [join(base_path, path, '
Roslyn
')]
return build
return build
@property
@property
def HTMLHelpWorkshop(self):
def HTMLHelpWorkshop(self):
"""
"""
Microsoft HTML Help Workshop
Microsoft HTML Help Workshop.
Return
------
list of str
paths
"""
"""
if self.v
c
_ver < 11.0:
if self.v
s
_ver < 11.0:
return []
return []
return [
os.path.
join(self.si.ProgramFilesx86, '
HTML
Help
Workshop
')]
return [join(self.si.ProgramFilesx86, '
HTML
Help
Workshop
')]
@property
@property
def UCRTLibraries(self):
def UCRTLibraries(self):
"""
"""
Microsoft Universal C Runtime SDK Libraries
Microsoft Universal C Runtime SDK Libraries.
Return
------
list of str
paths
"""
"""
if self.v
c
_ver < 14.0:
if self.v
s
_ver < 14.0:
return []
return []
arch_subdir = self.pi.target_dir(x64=True)
arch_subdir = self.pi.target_dir(x64=True)
lib =
os.path.
join(self.si.UniversalCRTSdkDir, '
lib
')
lib = join(self.si.UniversalCRTSdkDir, '
lib
')
ucrtver = self._ucrt_subdir
ucrtver = self._ucrt_subdir
return [
os.path.
join(lib, '
%
sucrt
%
s
' % (ucrtver, arch_subdir))]
return [join(lib, '
%
sucrt
%
s
' % (ucrtver, arch_subdir))]
@property
@property
def UCRTIncludes(self):
def UCRTIncludes(self):
"""
"""
Microsoft Universal C Runtime SDK Include
Microsoft Universal C Runtime SDK Include.
Return
------
list of str
paths
"""
"""
if self.v
c
_ver < 14.0:
if self.v
s
_ver < 14.0:
return []
return []
include =
os.path.
join(self.si.UniversalCRTSdkDir, '
include
')
include = join(self.si.UniversalCRTSdkDir, '
include
')
return [
os.path.
join(include, '
%
sucrt
' % self._ucrt_subdir)]
return [join(include, '
%
sucrt
' % self._ucrt_subdir)]
@property
@property
def _ucrt_subdir(self):
def _ucrt_subdir(self):
"""
"""
Microsoft Universal C Runtime SDK version subdir
Microsoft Universal C Runtime SDK version subdir.
Return
------
str
subdir
"""
"""
ucrtver = self.si.UniversalCRTSdkLastVersion
ucrtver = self.si.UniversalCRTSdkLastVersion
return ('
%
s
\\
' % ucrtver) if ucrtver else ''
return ('
%
s
\\
' % ucrtver) if ucrtver else ''
...
@@ -1187,31 +1523,52 @@ class EnvironmentInfo:
...
@@ -1187,31 +1523,52 @@ class EnvironmentInfo:
@property
@property
def FSharp(self):
def FSharp(self):
"""
"""
Microsoft Visual F#
Microsoft Visual F#.
Return
------
list of str
paths
"""
"""
if
self.vc_ver < 11.0 and self.vc
_ver > 12.0:
if
11.0 > self.vs
_ver > 12.0:
return []
return []
return
self.si.FSharpInstallDir
return
[self.si.FSharpInstallDir]
@property
@property
def VCRuntimeRedist(self):
def VCRuntimeRedist(self):
"""
"""
Microsoft Visual C++ runtime redistribuable dll
Microsoft Visual C++ runtime redistributable dll.
"""
arch_subdir = self.pi.target_dir(x64=True)
if self.vc_ver < 15:
redist_path = self.si.VCInstallDir
vcruntime = '
redist
%
s
\\
Microsoft
.
VC
%
d0
.
CRT
\\
vcruntime
%
d0
.
dll
'
else:
redist_path = self.si.VCInstallDir.replace('
\\
Tools
', '
\\
Redist
')
vcruntime = '
onecore
%
s
\\
Microsoft
.
VC
%
d0
.
CRT
\\
vcruntime
%
d0
.
dll
'
# Visual Studio 2017 is still Visual C++ 14.0
dll_ver = 14.0 if self.vc_ver == 15 else self.vc_ver
vcruntime = vcruntime % (arch_subdir, self.vc_ver, dll_ver)
Return
return os.path.join(redist_path, vcruntime)
------
str
path
"""
vcruntime = '
vcruntime
%
d0
.
dll
' % self.vc_ver
arch_subdir = self.pi.target_dir(x64=True).strip('
\\
')
# Installation prefixes candidates
prefixes = []
tools_path = self.si.VCInstallDir
redist_path = dirname(tools_path.replace(r'
\
Tools
', r'
\
Redist
'))
if isdir(redist_path):
# Redist version may not be exactly the same as tools
redist_path = join(redist_path, listdir(redist_path)[-1])
prefixes += [redist_path, join(redist_path, '
onecore
')]
prefixes += [join(tools_path, '
redist
')] # VS14 legacy path
# CRT directory
crt_dirs = ('
Microsoft
.
VC
%
d
.
CRT
' % (self.vc_ver * 10),
# Sometime store in directory with VS version instead of VC
'
Microsoft
.
VC
%
d
.
CRT
' % (int(self.vs_ver) * 10))
# vcruntime path
for prefix, crt_dir in itertools.product(prefixes, crt_dirs):
path = join(prefix, arch_subdir, crt_dir, vcruntime)
if isfile(path):
return path
def return_env(self, exists=True):
def return_env(self, exists=True):
"""
"""
...
@@ -1221,6 +1578,11 @@ class EnvironmentInfo:
...
@@ -1221,6 +1578,11 @@ class EnvironmentInfo:
----------
----------
exists: bool
exists: bool
It True, only return existing paths.
It True, only return existing paths.
Return
------
dict
environment
"""
"""
env = dict(
env = dict(
include=self._build_paths('
include
',
include=self._build_paths('
include
',
...
@@ -1254,7 +1616,7 @@ class EnvironmentInfo:
...
@@ -1254,7 +1616,7 @@ class EnvironmentInfo:
self.FSharp],
self.FSharp],
exists),
exists),
)
)
if self.v
c_ver >= 14 and os.path.
isfile(self.VCRuntimeRedist):
if self.v
s_ver >= 14 and
isfile(self.VCRuntimeRedist):
env['
py_vcruntime_redist
'] = self.VCRuntimeRedist
env['
py_vcruntime_redist
'] = self.VCRuntimeRedist
return env
return env
...
@@ -1265,20 +1627,35 @@ class EnvironmentInfo:
...
@@ -1265,20 +1627,35 @@ class EnvironmentInfo:
unique, extant, directories from those paths and from
unique, extant, directories from those paths and from
the environment variable. Raise an error if no paths
the environment variable. Raise an error if no paths
are resolved.
are resolved.
Parameters
----------
name: str
Environment variable name
spec_path_lists: list of str
Paths
exists: bool
It True, only return existing paths.
Return
------
str
Pathsep-separated paths
"""
"""
# flatten spec_path_lists
# flatten spec_path_lists
spec_paths = itertools.chain.from_iterable(spec_path_lists)
spec_paths = itertools.chain.from_iterable(spec_path_lists)
env_paths =
safe_env.get(name, '').split(os.
pathsep)
env_paths =
environ.get(name, '').split(
pathsep)
paths = itertools.chain(spec_paths, env_paths)
paths = itertools.chain(spec_paths, env_paths)
extant_paths = list(filter(
os.path.
isdir, paths)) if exists else paths
extant_paths = list(filter(isdir, paths)) if exists else paths
if not extant_paths:
if not extant_paths:
msg = "%s environment variable is empty" % name.upper()
msg = "%s environment variable is empty" % name.upper()
raise distutils.errors.DistutilsPlatformError(msg)
raise distutils.errors.DistutilsPlatformError(msg)
unique_paths = self._unique_everseen(extant_paths)
unique_paths = self._unique_everseen(extant_paths)
return
os.
pathsep.join(unique_paths)
return pathsep.join(unique_paths)
# from Python docs
# from Python docs
def _unique_everseen(self, iterable, key=None):
@staticmethod
def _unique_everseen(iterable, key=None):
"""
"""
List unique elements, preserving order.
List unique elements, preserving order.
Remember all elements ever seen.
Remember all elements ever seen.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment