Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/setuptools/msvc.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
| author | shellac |
|---|---|
| date | Sat, 02 May 2020 07:14:21 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:26e78fe6e8c4 |
|---|---|
| 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.0: | |
| 15 Microsoft Visual C++ Build Tools 2015 (x86, x64, arm) | |
| 16 Microsoft Visual Studio 2017 (x86, x64, arm, arm64) | |
| 17 Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64) | |
| 18 """ | |
| 19 | |
| 20 import os | |
| 21 import sys | |
| 22 import platform | |
| 23 import itertools | |
| 24 import distutils.errors | |
| 25 from setuptools.extern.packaging.version import LegacyVersion | |
| 26 | |
| 27 from setuptools.extern.six.moves import filterfalse | |
| 28 | |
| 29 from .monkey import get_unpatched | |
| 30 | |
| 31 if platform.system() == 'Windows': | |
| 32 from setuptools.extern.six.moves import winreg | |
| 33 safe_env = os.environ | |
| 34 else: | |
| 35 """ | |
| 36 Mock winreg and environ so the module can be imported | |
| 37 on this platform. | |
| 38 """ | |
| 39 | |
| 40 class winreg: | |
| 41 HKEY_USERS = None | |
| 42 HKEY_CURRENT_USER = None | |
| 43 HKEY_LOCAL_MACHINE = None | |
| 44 HKEY_CLASSES_ROOT = None | |
| 45 | |
| 46 safe_env = dict() | |
| 47 | |
| 48 _msvc9_suppress_errors = ( | |
| 49 # msvc9compiler isn't available on some platforms | |
| 50 ImportError, | |
| 51 | |
| 52 # msvc9compiler raises DistutilsPlatformError in some | |
| 53 # environments. See #1118. | |
| 54 distutils.errors.DistutilsPlatformError, | |
| 55 ) | |
| 56 | |
| 57 try: | |
| 58 from distutils.msvc9compiler import Reg | |
| 59 except _msvc9_suppress_errors: | |
| 60 pass | |
| 61 | |
| 62 | |
| 63 def msvc9_find_vcvarsall(version): | |
| 64 """ | |
| 65 Patched "distutils.msvc9compiler.find_vcvarsall" to use the standalone | |
| 66 compiler build for Python (VCForPython). Fall back to original behavior | |
| 67 when the standalone compiler is not available. | |
| 68 | |
| 69 Redirect the path of "vcvarsall.bat". | |
| 70 | |
| 71 Known supported compilers | |
| 72 ------------------------- | |
| 73 Microsoft Visual C++ 9.0: | |
| 74 Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64) | |
| 75 | |
| 76 Parameters | |
| 77 ---------- | |
| 78 version: float | |
| 79 Required Microsoft Visual C++ version. | |
| 80 | |
| 81 Return | |
| 82 ------ | |
| 83 vcvarsall.bat path: str | |
| 84 """ | |
| 85 VC_BASE = r'Software\%sMicrosoft\DevDiv\VCForPython\%0.1f' | |
| 86 key = VC_BASE % ('', version) | |
| 87 try: | |
| 88 # Per-user installs register the compiler path here | |
| 89 productdir = Reg.get_value(key, "installdir") | |
| 90 except KeyError: | |
| 91 try: | |
| 92 # All-user installs on a 64-bit system register here | |
| 93 key = VC_BASE % ('Wow6432Node\\', version) | |
| 94 productdir = Reg.get_value(key, "installdir") | |
| 95 except KeyError: | |
| 96 productdir = None | |
| 97 | |
| 98 if productdir: | |
| 99 vcvarsall = os.path.os.path.join(productdir, "vcvarsall.bat") | |
| 100 if os.path.isfile(vcvarsall): | |
| 101 return vcvarsall | |
| 102 | |
| 103 return get_unpatched(msvc9_find_vcvarsall)(version) | |
| 104 | |
| 105 | |
| 106 def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): | |
| 107 """ | |
| 108 Patched "distutils.msvc9compiler.query_vcvarsall" for support extra | |
| 109 compilers. | |
| 110 | |
| 111 Set environment without use of "vcvarsall.bat". | |
| 112 | |
| 113 Known supported compilers | |
| 114 ------------------------- | |
| 115 Microsoft Visual C++ 9.0: | |
| 116 Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64) | |
| 117 Microsoft Windows SDK 6.1 (x86, x64, ia64) | |
| 118 Microsoft Windows SDK 7.0 (x86, x64, ia64) | |
| 119 | |
| 120 Microsoft Visual C++ 10.0: | |
| 121 Microsoft Windows SDK 7.1 (x86, x64, ia64) | |
| 122 | |
| 123 Parameters | |
| 124 ---------- | |
| 125 ver: float | |
| 126 Required Microsoft Visual C++ version. | |
| 127 arch: str | |
| 128 Target architecture. | |
| 129 | |
| 130 Return | |
| 131 ------ | |
| 132 environment: dict | |
| 133 """ | |
| 134 # Try to get environement from vcvarsall.bat (Classical way) | |
| 135 try: | |
| 136 orig = get_unpatched(msvc9_query_vcvarsall) | |
| 137 return orig(ver, arch, *args, **kwargs) | |
| 138 except distutils.errors.DistutilsPlatformError: | |
| 139 # Pass error if Vcvarsall.bat is missing | |
| 140 pass | |
| 141 except ValueError: | |
| 142 # Pass error if environment not set after executing vcvarsall.bat | |
| 143 pass | |
| 144 | |
| 145 # If error, try to set environment directly | |
| 146 try: | |
| 147 return EnvironmentInfo(arch, ver).return_env() | |
| 148 except distutils.errors.DistutilsPlatformError as exc: | |
| 149 _augment_exception(exc, ver, arch) | |
| 150 raise | |
| 151 | |
| 152 | |
| 153 def msvc14_get_vc_env(plat_spec): | |
| 154 """ | |
| 155 Patched "distutils._msvccompiler._get_vc_env" for support extra | |
| 156 compilers. | |
| 157 | |
| 158 Set environment without use of "vcvarsall.bat". | |
| 159 | |
| 160 Known supported compilers | |
| 161 ------------------------- | |
| 162 Microsoft Visual C++ 14.0: | |
| 163 Microsoft Visual C++ Build Tools 2015 (x86, x64, arm) | |
| 164 Microsoft Visual Studio 2017 (x86, x64, arm, arm64) | |
| 165 Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64) | |
| 166 | |
| 167 Parameters | |
| 168 ---------- | |
| 169 plat_spec: str | |
| 170 Target architecture. | |
| 171 | |
| 172 Return | |
| 173 ------ | |
| 174 environment: dict | |
| 175 """ | |
| 176 # Try to get environment from vcvarsall.bat (Classical way) | |
| 177 try: | |
| 178 return get_unpatched(msvc14_get_vc_env)(plat_spec) | |
| 179 except distutils.errors.DistutilsPlatformError: | |
| 180 # Pass error Vcvarsall.bat is missing | |
| 181 pass | |
| 182 | |
| 183 # If error, try to set environment directly | |
| 184 try: | |
| 185 return EnvironmentInfo(plat_spec, vc_min_ver=14.0).return_env() | |
| 186 except distutils.errors.DistutilsPlatformError as exc: | |
| 187 _augment_exception(exc, 14.0) | |
| 188 raise | |
| 189 | |
| 190 | |
| 191 def msvc14_gen_lib_options(*args, **kwargs): | |
| 192 """ | |
| 193 Patched "distutils._msvccompiler.gen_lib_options" for fix | |
| 194 compatibility between "numpy.distutils" and "distutils._msvccompiler" | |
| 195 (for Numpy < 1.11.2) | |
| 196 """ | |
| 197 if "numpy.distutils" in sys.modules: | |
| 198 import numpy as np | |
| 199 if LegacyVersion(np.__version__) < LegacyVersion('1.11.2'): | |
| 200 return np.distutils.ccompiler.gen_lib_options(*args, **kwargs) | |
| 201 return get_unpatched(msvc14_gen_lib_options)(*args, **kwargs) | |
| 202 | |
| 203 | |
| 204 def _augment_exception(exc, version, arch=''): | |
| 205 """ | |
| 206 Add details to the exception message to help guide the user | |
| 207 as to what action will resolve it. | |
| 208 """ | |
| 209 # Error if MSVC++ directory not found or environment not set | |
| 210 message = exc.args[0] | |
| 211 | |
| 212 if "vcvarsall" in message.lower() or "visual c" in message.lower(): | |
| 213 # Special error message if MSVC++ not installed | |
| 214 tmpl = 'Microsoft Visual C++ {version:0.1f} is required.' | |
| 215 message = tmpl.format(**locals()) | |
| 216 msdownload = 'www.microsoft.com/download/details.aspx?id=%d' | |
| 217 if version == 9.0: | |
| 218 if arch.lower().find('ia64') > -1: | |
| 219 # For VC++ 9.0, if IA64 support is needed, redirect user | |
| 220 # to Windows SDK 7.0 | |
| 221 message += ' Get it with "Microsoft Windows SDK 7.0": ' | |
| 222 message += msdownload % 3138 | |
| 223 else: | |
| 224 # For VC++ 9.0 redirect user to Vc++ for Python 2.7 : | |
| 225 # This redirection link is maintained by Microsoft. | |
| 226 # Contact vspython@microsoft.com if it needs updating. | |
| 227 message += ' Get it from http://aka.ms/vcpython27' | |
| 228 elif version == 10.0: | |
| 229 # For VC++ 10.0 Redirect user to Windows SDK 7.1 | |
| 230 message += ' Get it with "Microsoft Windows SDK 7.1": ' | |
| 231 message += msdownload % 8279 | |
| 232 elif version >= 14.0: | |
| 233 # For VC++ 14.0 Redirect user to Visual C++ Build Tools | |
| 234 message += (' Get it with "Microsoft Visual C++ Build Tools": ' | |
| 235 r'https://visualstudio.microsoft.com/downloads/') | |
| 236 | |
| 237 exc.args = (message, ) | |
| 238 | |
| 239 | |
| 240 class PlatformInfo: | |
| 241 """ | |
| 242 Current and Target Architectures informations. | |
| 243 | |
| 244 Parameters | |
| 245 ---------- | |
| 246 arch: str | |
| 247 Target architecture. | |
| 248 """ | |
| 249 current_cpu = safe_env.get('processor_architecture', '').lower() | |
| 250 | |
| 251 def __init__(self, arch): | |
| 252 self.arch = arch.lower().replace('x64', 'amd64') | |
| 253 | |
| 254 @property | |
| 255 def target_cpu(self): | |
| 256 return self.arch[self.arch.find('_') + 1:] | |
| 257 | |
| 258 def target_is_x86(self): | |
| 259 return self.target_cpu == 'x86' | |
| 260 | |
| 261 def current_is_x86(self): | |
| 262 return self.current_cpu == 'x86' | |
| 263 | |
| 264 def current_dir(self, hidex86=False, x64=False): | |
| 265 """ | |
| 266 Current platform specific subfolder. | |
| 267 | |
| 268 Parameters | |
| 269 ---------- | |
| 270 hidex86: bool | |
| 271 return '' and not '\x86' if architecture is x86. | |
| 272 x64: bool | |
| 273 return '\x64' and not '\amd64' if architecture is amd64. | |
| 274 | |
| 275 Return | |
| 276 ------ | |
| 277 subfolder: str | |
| 278 '\target', or '' (see hidex86 parameter) | |
| 279 """ | |
| 280 return ( | |
| 281 '' if (self.current_cpu == 'x86' and hidex86) else | |
| 282 r'\x64' if (self.current_cpu == 'amd64' and x64) else | |
| 283 r'\%s' % self.current_cpu | |
| 284 ) | |
| 285 | |
| 286 def target_dir(self, hidex86=False, x64=False): | |
| 287 r""" | |
| 288 Target platform specific subfolder. | |
| 289 | |
| 290 Parameters | |
| 291 ---------- | |
| 292 hidex86: bool | |
| 293 return '' and not '\x86' if architecture is x86. | |
| 294 x64: bool | |
| 295 return '\x64' and not '\amd64' if architecture is amd64. | |
| 296 | |
| 297 Return | |
| 298 ------ | |
| 299 subfolder: str | |
| 300 '\current', or '' (see hidex86 parameter) | |
| 301 """ | |
| 302 return ( | |
| 303 '' if (self.target_cpu == 'x86' and hidex86) else | |
| 304 r'\x64' if (self.target_cpu == 'amd64' and x64) else | |
| 305 r'\%s' % self.target_cpu | |
| 306 ) | |
| 307 | |
| 308 def cross_dir(self, forcex86=False): | |
| 309 r""" | |
| 310 Cross platform specific subfolder. | |
| 311 | |
| 312 Parameters | |
| 313 ---------- | |
| 314 forcex86: bool | |
| 315 Use 'x86' as current architecture even if current acritecture is | |
| 316 not x86. | |
| 317 | |
| 318 Return | |
| 319 ------ | |
| 320 subfolder: str | |
| 321 '' if target architecture is current architecture, | |
| 322 '\current_target' if not. | |
| 323 """ | |
| 324 current = 'x86' if forcex86 else self.current_cpu | |
| 325 return ( | |
| 326 '' if self.target_cpu == current else | |
| 327 self.target_dir().replace('\\', '\\%s_' % current) | |
| 328 ) | |
| 329 | |
| 330 | |
| 331 class RegistryInfo: | |
| 332 """ | |
| 333 Microsoft Visual Studio related registry informations. | |
| 334 | |
| 335 Parameters | |
| 336 ---------- | |
| 337 platform_info: PlatformInfo | |
| 338 "PlatformInfo" instance. | |
| 339 """ | |
| 340 HKEYS = (winreg.HKEY_USERS, | |
| 341 winreg.HKEY_CURRENT_USER, | |
| 342 winreg.HKEY_LOCAL_MACHINE, | |
| 343 winreg.HKEY_CLASSES_ROOT) | |
| 344 | |
| 345 def __init__(self, platform_info): | |
| 346 self.pi = platform_info | |
| 347 | |
| 348 @property | |
| 349 def visualstudio(self): | |
| 350 """ | |
| 351 Microsoft Visual Studio root registry key. | |
| 352 """ | |
| 353 return 'VisualStudio' | |
| 354 | |
| 355 @property | |
| 356 def sxs(self): | |
| 357 """ | |
| 358 Microsoft Visual Studio SxS registry key. | |
| 359 """ | |
| 360 return os.path.join(self.visualstudio, 'SxS') | |
| 361 | |
| 362 @property | |
| 363 def vc(self): | |
| 364 """ | |
| 365 Microsoft Visual C++ VC7 registry key. | |
| 366 """ | |
| 367 return os.path.join(self.sxs, 'VC7') | |
| 368 | |
| 369 @property | |
| 370 def vs(self): | |
| 371 """ | |
| 372 Microsoft Visual Studio VS7 registry key. | |
| 373 """ | |
| 374 return os.path.join(self.sxs, 'VS7') | |
| 375 | |
| 376 @property | |
| 377 def vc_for_python(self): | |
| 378 """ | |
| 379 Microsoft Visual C++ for Python registry key. | |
| 380 """ | |
| 381 return r'DevDiv\VCForPython' | |
| 382 | |
| 383 @property | |
| 384 def microsoft_sdk(self): | |
| 385 """ | |
| 386 Microsoft SDK registry key. | |
| 387 """ | |
| 388 return 'Microsoft SDKs' | |
| 389 | |
| 390 @property | |
| 391 def windows_sdk(self): | |
| 392 """ | |
| 393 Microsoft Windows/Platform SDK registry key. | |
| 394 """ | |
| 395 return os.path.join(self.microsoft_sdk, 'Windows') | |
| 396 | |
| 397 @property | |
| 398 def netfx_sdk(self): | |
| 399 """ | |
| 400 Microsoft .NET Framework SDK registry key. | |
| 401 """ | |
| 402 return os.path.join(self.microsoft_sdk, 'NETFXSDK') | |
| 403 | |
| 404 @property | |
| 405 def windows_kits_roots(self): | |
| 406 """ | |
| 407 Microsoft Windows Kits Roots registry key. | |
| 408 """ | |
| 409 return r'Windows Kits\Installed Roots' | |
| 410 | |
| 411 def microsoft(self, key, x86=False): | |
| 412 """ | |
| 413 Return key in Microsoft software registry. | |
| 414 | |
| 415 Parameters | |
| 416 ---------- | |
| 417 key: str | |
| 418 Registry key path where look. | |
| 419 x86: str | |
| 420 Force x86 software registry. | |
| 421 | |
| 422 Return | |
| 423 ------ | |
| 424 str: value | |
| 425 """ | |
| 426 node64 = '' if self.pi.current_is_x86() or x86 else 'Wow6432Node' | |
| 427 return os.path.join('Software', node64, 'Microsoft', key) | |
| 428 | |
| 429 def lookup(self, key, name): | |
| 430 """ | |
| 431 Look for values in registry in Microsoft software registry. | |
| 432 | |
| 433 Parameters | |
| 434 ---------- | |
| 435 key: str | |
| 436 Registry key path where look. | |
| 437 name: str | |
| 438 Value name to find. | |
| 439 | |
| 440 Return | |
| 441 ------ | |
| 442 str: value | |
| 443 """ | |
| 444 KEY_READ = winreg.KEY_READ | |
| 445 openkey = winreg.OpenKey | |
| 446 ms = self.microsoft | |
| 447 for hkey in self.HKEYS: | |
| 448 try: | |
| 449 bkey = openkey(hkey, ms(key), 0, KEY_READ) | |
| 450 except (OSError, IOError): | |
| 451 if not self.pi.current_is_x86(): | |
| 452 try: | |
| 453 bkey = openkey(hkey, ms(key, True), 0, KEY_READ) | |
| 454 except (OSError, IOError): | |
| 455 continue | |
| 456 else: | |
| 457 continue | |
| 458 try: | |
| 459 return winreg.QueryValueEx(bkey, name)[0] | |
| 460 except (OSError, IOError): | |
| 461 pass | |
| 462 | |
| 463 | |
| 464 class SystemInfo: | |
| 465 """ | |
| 466 Microsoft Windows and Visual Studio related system inormations. | |
| 467 | |
| 468 Parameters | |
| 469 ---------- | |
| 470 registry_info: RegistryInfo | |
| 471 "RegistryInfo" instance. | |
| 472 vc_ver: float | |
| 473 Required Microsoft Visual C++ version. | |
| 474 """ | |
| 475 | |
| 476 # Variables and properties in this class use originals CamelCase variables | |
| 477 # names from Microsoft source files for more easy comparaison. | |
| 478 WinDir = safe_env.get('WinDir', '') | |
| 479 ProgramFiles = safe_env.get('ProgramFiles', '') | |
| 480 ProgramFilesx86 = safe_env.get('ProgramFiles(x86)', ProgramFiles) | |
| 481 | |
| 482 def __init__(self, registry_info, vc_ver=None): | |
| 483 self.ri = registry_info | |
| 484 self.pi = self.ri.pi | |
| 485 self.vc_ver = vc_ver or self._find_latest_available_vc_ver() | |
| 486 | |
| 487 def _find_latest_available_vc_ver(self): | |
| 488 try: | |
| 489 return self.find_available_vc_vers()[-1] | |
| 490 except IndexError: | |
| 491 err = 'No Microsoft Visual C++ version found' | |
| 492 raise distutils.errors.DistutilsPlatformError(err) | |
| 493 | |
| 494 def find_available_vc_vers(self): | |
| 495 """ | |
| 496 Find all available Microsoft Visual C++ versions. | |
| 497 """ | |
| 498 ms = self.ri.microsoft | |
| 499 vckeys = (self.ri.vc, self.ri.vc_for_python, self.ri.vs) | |
| 500 vc_vers = [] | |
| 501 for hkey in self.ri.HKEYS: | |
| 502 for key in vckeys: | |
| 503 try: | |
| 504 bkey = winreg.OpenKey(hkey, ms(key), 0, winreg.KEY_READ) | |
| 505 except (OSError, IOError): | |
| 506 continue | |
| 507 subkeys, values, _ = winreg.QueryInfoKey(bkey) | |
| 508 for i in range(values): | |
| 509 try: | |
| 510 ver = float(winreg.EnumValue(bkey, i)[0]) | |
| 511 if ver not in vc_vers: | |
| 512 vc_vers.append(ver) | |
| 513 except ValueError: | |
| 514 pass | |
| 515 for i in range(subkeys): | |
| 516 try: | |
| 517 ver = float(winreg.EnumKey(bkey, i)) | |
| 518 if ver not in vc_vers: | |
| 519 vc_vers.append(ver) | |
| 520 except ValueError: | |
| 521 pass | |
| 522 return sorted(vc_vers) | |
| 523 | |
| 524 @property | |
| 525 def VSInstallDir(self): | |
| 526 """ | |
| 527 Microsoft Visual Studio directory. | |
| 528 """ | |
| 529 # Default path | |
| 530 name = 'Microsoft Visual Studio %0.1f' % self.vc_ver | |
| 531 default = os.path.join(self.ProgramFilesx86, name) | |
| 532 | |
| 533 # Try to get path from registry, if fail use default path | |
| 534 return self.ri.lookup(self.ri.vs, '%0.1f' % self.vc_ver) or default | |
| 535 | |
| 536 @property | |
| 537 def VCInstallDir(self): | |
| 538 """ | |
| 539 Microsoft Visual C++ directory. | |
| 540 """ | |
| 541 self.VSInstallDir | |
| 542 | |
| 543 guess_vc = self._guess_vc() or self._guess_vc_legacy() | |
| 544 | |
| 545 # Try to get "VC++ for Python" path from registry as default path | |
| 546 reg_path = os.path.join(self.ri.vc_for_python, '%0.1f' % self.vc_ver) | |
| 547 python_vc = self.ri.lookup(reg_path, 'installdir') | |
| 548 default_vc = os.path.join(python_vc, 'VC') if python_vc else guess_vc | |
| 549 | |
| 550 # Try to get path from registry, if fail use default path | |
| 551 path = self.ri.lookup(self.ri.vc, '%0.1f' % self.vc_ver) or default_vc | |
| 552 | |
| 553 if not os.path.isdir(path): | |
| 554 msg = 'Microsoft Visual C++ directory not found' | |
| 555 raise distutils.errors.DistutilsPlatformError(msg) | |
| 556 | |
| 557 return path | |
| 558 | |
| 559 def _guess_vc(self): | |
| 560 """ | |
| 561 Locate Visual C for 2017 | |
| 562 """ | |
| 563 if self.vc_ver <= 14.0: | |
| 564 return | |
| 565 | |
| 566 default = r'VC\Tools\MSVC' | |
| 567 guess_vc = os.path.join(self.VSInstallDir, default) | |
| 568 # Subdir with VC exact version as name | |
| 569 try: | |
| 570 vc_exact_ver = os.listdir(guess_vc)[-1] | |
| 571 return os.path.join(guess_vc, vc_exact_ver) | |
| 572 except (OSError, IOError, IndexError): | |
| 573 pass | |
| 574 | |
| 575 def _guess_vc_legacy(self): | |
| 576 """ | |
| 577 Locate Visual C for versions prior to 2017 | |
| 578 """ | |
| 579 default = r'Microsoft Visual Studio %0.1f\VC' % self.vc_ver | |
| 580 return os.path.join(self.ProgramFilesx86, default) | |
| 581 | |
| 582 @property | |
| 583 def WindowsSdkVersion(self): | |
| 584 """ | |
| 585 Microsoft Windows SDK versions for specified MSVC++ version. | |
| 586 """ | |
| 587 if self.vc_ver <= 9.0: | |
| 588 return ('7.0', '6.1', '6.0a') | |
| 589 elif self.vc_ver == 10.0: | |
| 590 return ('7.1', '7.0a') | |
| 591 elif self.vc_ver == 11.0: | |
| 592 return ('8.0', '8.0a') | |
| 593 elif self.vc_ver == 12.0: | |
| 594 return ('8.1', '8.1a') | |
| 595 elif self.vc_ver >= 14.0: | |
| 596 return ('10.0', '8.1') | |
| 597 | |
| 598 @property | |
| 599 def WindowsSdkLastVersion(self): | |
| 600 """ | |
| 601 Microsoft Windows SDK last version | |
| 602 """ | |
| 603 return self._use_last_dir_name(os.path.join( | |
| 604 self.WindowsSdkDir, 'lib')) | |
| 605 | |
| 606 @property | |
| 607 def WindowsSdkDir(self): | |
| 608 """ | |
| 609 Microsoft Windows SDK directory. | |
| 610 """ | |
| 611 sdkdir = '' | |
| 612 for ver in self.WindowsSdkVersion: | |
| 613 # Try to get it from registry | |
| 614 loc = os.path.join(self.ri.windows_sdk, 'v%s' % ver) | |
| 615 sdkdir = self.ri.lookup(loc, 'installationfolder') | |
| 616 if sdkdir: | |
| 617 break | |
| 618 if not sdkdir or not os.path.isdir(sdkdir): | |
| 619 # Try to get "VC++ for Python" version from registry | |
| 620 path = os.path.join(self.ri.vc_for_python, '%0.1f' % self.vc_ver) | |
| 621 install_base = self.ri.lookup(path, 'installdir') | |
| 622 if install_base: | |
| 623 sdkdir = os.path.join(install_base, 'WinSDK') | |
| 624 if not sdkdir or not os.path.isdir(sdkdir): | |
| 625 # If fail, use default new path | |
| 626 for ver in self.WindowsSdkVersion: | |
| 627 intver = ver[:ver.rfind('.')] | |
| 628 path = r'Microsoft SDKs\Windows Kits\%s' % (intver) | |
| 629 d = os.path.join(self.ProgramFiles, path) | |
| 630 if os.path.isdir(d): | |
| 631 sdkdir = d | |
| 632 if not sdkdir or not os.path.isdir(sdkdir): | |
| 633 # If fail, use default old path | |
| 634 for ver in self.WindowsSdkVersion: | |
| 635 path = r'Microsoft SDKs\Windows\v%s' % ver | |
| 636 d = os.path.join(self.ProgramFiles, path) | |
| 637 if os.path.isdir(d): | |
| 638 sdkdir = d | |
| 639 if not sdkdir: | |
| 640 # If fail, use Platform SDK | |
| 641 sdkdir = os.path.join(self.VCInstallDir, 'PlatformSDK') | |
| 642 return sdkdir | |
| 643 | |
| 644 @property | |
| 645 def WindowsSDKExecutablePath(self): | |
| 646 """ | |
| 647 Microsoft Windows SDK executable directory. | |
| 648 """ | |
| 649 # Find WinSDK NetFx Tools registry dir name | |
| 650 if self.vc_ver <= 11.0: | |
| 651 netfxver = 35 | |
| 652 arch = '' | |
| 653 else: | |
| 654 netfxver = 40 | |
| 655 hidex86 = True if self.vc_ver <= 12.0 else False | |
| 656 arch = self.pi.current_dir(x64=True, hidex86=hidex86) | |
| 657 fx = 'WinSDK-NetFx%dTools%s' % (netfxver, arch.replace('\\', '-')) | |
| 658 | |
| 659 # liste all possibles registry paths | |
| 660 regpaths = [] | |
| 661 if self.vc_ver >= 14.0: | |
| 662 for ver in self.NetFxSdkVersion: | |
| 663 regpaths += [os.path.join(self.ri.netfx_sdk, ver, fx)] | |
| 664 | |
| 665 for ver in self.WindowsSdkVersion: | |
| 666 regpaths += [os.path.join(self.ri.windows_sdk, 'v%sA' % ver, fx)] | |
| 667 | |
| 668 # Return installation folder from the more recent path | |
| 669 for path in regpaths: | |
| 670 execpath = self.ri.lookup(path, 'installationfolder') | |
| 671 if execpath: | |
| 672 break | |
| 673 return execpath | |
| 674 | |
| 675 @property | |
| 676 def FSharpInstallDir(self): | |
| 677 """ | |
| 678 Microsoft Visual F# directory. | |
| 679 """ | |
| 680 path = r'%0.1f\Setup\F#' % self.vc_ver | |
| 681 path = os.path.join(self.ri.visualstudio, path) | |
| 682 return self.ri.lookup(path, 'productdir') or '' | |
| 683 | |
| 684 @property | |
| 685 def UniversalCRTSdkDir(self): | |
| 686 """ | |
| 687 Microsoft Universal CRT SDK directory. | |
| 688 """ | |
| 689 # Set Kit Roots versions for specified MSVC++ version | |
| 690 if self.vc_ver >= 14.0: | |
| 691 vers = ('10', '81') | |
| 692 else: | |
| 693 vers = () | |
| 694 | |
| 695 # Find path of the more recent Kit | |
| 696 for ver in vers: | |
| 697 sdkdir = self.ri.lookup(self.ri.windows_kits_roots, | |
| 698 'kitsroot%s' % ver) | |
| 699 if sdkdir: | |
| 700 break | |
| 701 return sdkdir or '' | |
| 702 | |
| 703 @property | |
| 704 def UniversalCRTSdkLastVersion(self): | |
| 705 """ | |
| 706 Microsoft Universal C Runtime SDK last version | |
| 707 """ | |
| 708 return self._use_last_dir_name(os.path.join( | |
| 709 self.UniversalCRTSdkDir, 'lib')) | |
| 710 | |
| 711 @property | |
| 712 def NetFxSdkVersion(self): | |
| 713 """ | |
| 714 Microsoft .NET Framework SDK versions. | |
| 715 """ | |
| 716 # Set FxSdk versions for specified MSVC++ version | |
| 717 if self.vc_ver >= 14.0: | |
| 718 return ('4.6.1', '4.6') | |
| 719 else: | |
| 720 return () | |
| 721 | |
| 722 @property | |
| 723 def NetFxSdkDir(self): | |
| 724 """ | |
| 725 Microsoft .NET Framework SDK directory. | |
| 726 """ | |
| 727 for ver in self.NetFxSdkVersion: | |
| 728 loc = os.path.join(self.ri.netfx_sdk, ver) | |
| 729 sdkdir = self.ri.lookup(loc, 'kitsinstallationfolder') | |
| 730 if sdkdir: | |
| 731 break | |
| 732 return sdkdir or '' | |
| 733 | |
| 734 @property | |
| 735 def FrameworkDir32(self): | |
| 736 """ | |
| 737 Microsoft .NET Framework 32bit directory. | |
| 738 """ | |
| 739 # Default path | |
| 740 guess_fw = os.path.join(self.WinDir, r'Microsoft.NET\Framework') | |
| 741 | |
| 742 # Try to get path from registry, if fail use default path | |
| 743 return self.ri.lookup(self.ri.vc, 'frameworkdir32') or guess_fw | |
| 744 | |
| 745 @property | |
| 746 def FrameworkDir64(self): | |
| 747 """ | |
| 748 Microsoft .NET Framework 64bit directory. | |
| 749 """ | |
| 750 # Default path | |
| 751 guess_fw = os.path.join(self.WinDir, r'Microsoft.NET\Framework64') | |
| 752 | |
| 753 # Try to get path from registry, if fail use default path | |
| 754 return self.ri.lookup(self.ri.vc, 'frameworkdir64') or guess_fw | |
| 755 | |
| 756 @property | |
| 757 def FrameworkVersion32(self): | |
| 758 """ | |
| 759 Microsoft .NET Framework 32bit versions. | |
| 760 """ | |
| 761 return self._find_dot_net_versions(32) | |
| 762 | |
| 763 @property | |
| 764 def FrameworkVersion64(self): | |
| 765 """ | |
| 766 Microsoft .NET Framework 64bit versions. | |
| 767 """ | |
| 768 return self._find_dot_net_versions(64) | |
| 769 | |
| 770 def _find_dot_net_versions(self, bits): | |
| 771 """ | |
| 772 Find Microsoft .NET Framework versions. | |
| 773 | |
| 774 Parameters | |
| 775 ---------- | |
| 776 bits: int | |
| 777 Platform number of bits: 32 or 64. | |
| 778 """ | |
| 779 # Find actual .NET version in registry | |
| 780 reg_ver = self.ri.lookup(self.ri.vc, 'frameworkver%d' % bits) | |
| 781 dot_net_dir = getattr(self, 'FrameworkDir%d' % bits) | |
| 782 ver = reg_ver or self._use_last_dir_name(dot_net_dir, 'v') or '' | |
| 783 | |
| 784 # Set .NET versions for specified MSVC++ version | |
| 785 if self.vc_ver >= 12.0: | |
| 786 frameworkver = (ver, 'v4.0') | |
| 787 elif self.vc_ver >= 10.0: | |
| 788 frameworkver = ('v4.0.30319' if ver.lower()[:2] != 'v4' else ver, | |
| 789 'v3.5') | |
| 790 elif self.vc_ver == 9.0: | |
| 791 frameworkver = ('v3.5', 'v2.0.50727') | |
| 792 if self.vc_ver == 8.0: | |
| 793 frameworkver = ('v3.0', 'v2.0.50727') | |
| 794 return frameworkver | |
| 795 | |
| 796 def _use_last_dir_name(self, path, prefix=''): | |
| 797 """ | |
| 798 Return name of the last dir in path or '' if no dir found. | |
| 799 | |
| 800 Parameters | |
| 801 ---------- | |
| 802 path: str | |
| 803 Use dirs in this path | |
| 804 prefix: str | |
| 805 Use only dirs startings by this prefix | |
| 806 """ | |
| 807 matching_dirs = ( | |
| 808 dir_name | |
| 809 for dir_name in reversed(os.listdir(path)) | |
| 810 if os.path.isdir(os.path.join(path, dir_name)) and | |
| 811 dir_name.startswith(prefix) | |
| 812 ) | |
| 813 return next(matching_dirs, None) or '' | |
| 814 | |
| 815 | |
| 816 class EnvironmentInfo: | |
| 817 """ | |
| 818 Return environment variables for specified Microsoft Visual C++ version | |
| 819 and platform : Lib, Include, Path and libpath. | |
| 820 | |
| 821 This function is compatible with Microsoft Visual C++ 9.0 to 14.0. | |
| 822 | |
| 823 Script created by analysing Microsoft environment configuration files like | |
| 824 "vcvars[...].bat", "SetEnv.Cmd", "vcbuildtools.bat", ... | |
| 825 | |
| 826 Parameters | |
| 827 ---------- | |
| 828 arch: str | |
| 829 Target architecture. | |
| 830 vc_ver: float | |
| 831 Required Microsoft Visual C++ version. If not set, autodetect the last | |
| 832 version. | |
| 833 vc_min_ver: float | |
| 834 Minimum Microsoft Visual C++ version. | |
| 835 """ | |
| 836 | |
| 837 # Variables and properties in this class use originals CamelCase variables | |
| 838 # names from Microsoft source files for more easy comparaison. | |
| 839 | |
| 840 def __init__(self, arch, vc_ver=None, vc_min_ver=0): | |
| 841 self.pi = PlatformInfo(arch) | |
| 842 self.ri = RegistryInfo(self.pi) | |
| 843 self.si = SystemInfo(self.ri, vc_ver) | |
| 844 | |
| 845 if self.vc_ver < vc_min_ver: | |
| 846 err = 'No suitable Microsoft Visual C++ version found' | |
| 847 raise distutils.errors.DistutilsPlatformError(err) | |
| 848 | |
| 849 @property | |
| 850 def vc_ver(self): | |
| 851 """ | |
| 852 Microsoft Visual C++ version. | |
| 853 """ | |
| 854 return self.si.vc_ver | |
| 855 | |
| 856 @property | |
| 857 def VSTools(self): | |
| 858 """ | |
| 859 Microsoft Visual Studio Tools | |
| 860 """ | |
| 861 paths = [r'Common7\IDE', r'Common7\Tools'] | |
| 862 | |
| 863 if self.vc_ver >= 14.0: | |
| 864 arch_subdir = self.pi.current_dir(hidex86=True, x64=True) | |
| 865 paths += [r'Common7\IDE\CommonExtensions\Microsoft\TestWindow'] | |
| 866 paths += [r'Team Tools\Performance Tools'] | |
| 867 paths += [r'Team Tools\Performance Tools%s' % arch_subdir] | |
| 868 | |
| 869 return [os.path.join(self.si.VSInstallDir, path) for path in paths] | |
| 870 | |
| 871 @property | |
| 872 def VCIncludes(self): | |
| 873 """ | |
| 874 Microsoft Visual C++ & Microsoft Foundation Class Includes | |
| 875 """ | |
| 876 return [os.path.join(self.si.VCInstallDir, 'Include'), | |
| 877 os.path.join(self.si.VCInstallDir, r'ATLMFC\Include')] | |
| 878 | |
| 879 @property | |
| 880 def VCLibraries(self): | |
| 881 """ | |
| 882 Microsoft Visual C++ & Microsoft Foundation Class Libraries | |
| 883 """ | |
| 884 if self.vc_ver >= 15.0: | |
| 885 arch_subdir = self.pi.target_dir(x64=True) | |
| 886 else: | |
| 887 arch_subdir = self.pi.target_dir(hidex86=True) | |
| 888 paths = ['Lib%s' % arch_subdir, r'ATLMFC\Lib%s' % arch_subdir] | |
| 889 | |
| 890 if self.vc_ver >= 14.0: | |
| 891 paths += [r'Lib\store%s' % arch_subdir] | |
| 892 | |
| 893 return [os.path.join(self.si.VCInstallDir, path) for path in paths] | |
| 894 | |
| 895 @property | |
| 896 def VCStoreRefs(self): | |
| 897 """ | |
| 898 Microsoft Visual C++ store references Libraries | |
| 899 """ | |
| 900 if self.vc_ver < 14.0: | |
| 901 return [] | |
| 902 return [os.path.join(self.si.VCInstallDir, r'Lib\store\references')] | |
| 903 | |
| 904 @property | |
| 905 def VCTools(self): | |
| 906 """ | |
| 907 Microsoft Visual C++ Tools | |
| 908 """ | |
| 909 si = self.si | |
| 910 tools = [os.path.join(si.VCInstallDir, 'VCPackages')] | |
| 911 | |
| 912 forcex86 = True if self.vc_ver <= 10.0 else False | |
| 913 arch_subdir = self.pi.cross_dir(forcex86) | |
| 914 if arch_subdir: | |
| 915 tools += [os.path.join(si.VCInstallDir, 'Bin%s' % arch_subdir)] | |
| 916 | |
| 917 if self.vc_ver == 14.0: | |
| 918 path = 'Bin%s' % self.pi.current_dir(hidex86=True) | |
| 919 tools += [os.path.join(si.VCInstallDir, path)] | |
| 920 | |
| 921 elif self.vc_ver >= 15.0: | |
| 922 host_dir = (r'bin\HostX86%s' if self.pi.current_is_x86() else | |
| 923 r'bin\HostX64%s') | |
| 924 tools += [os.path.join( | |
| 925 si.VCInstallDir, host_dir % self.pi.target_dir(x64=True))] | |
| 926 | |
| 927 if self.pi.current_cpu != self.pi.target_cpu: | |
| 928 tools += [os.path.join( | |
| 929 si.VCInstallDir, host_dir % self.pi.current_dir(x64=True))] | |
| 930 | |
| 931 else: | |
| 932 tools += [os.path.join(si.VCInstallDir, 'Bin')] | |
| 933 | |
| 934 return tools | |
| 935 | |
| 936 @property | |
| 937 def OSLibraries(self): | |
| 938 """ | |
| 939 Microsoft Windows SDK Libraries | |
| 940 """ | |
| 941 if self.vc_ver <= 10.0: | |
| 942 arch_subdir = self.pi.target_dir(hidex86=True, x64=True) | |
| 943 return [os.path.join(self.si.WindowsSdkDir, 'Lib%s' % arch_subdir)] | |
| 944 | |
| 945 else: | |
| 946 arch_subdir = self.pi.target_dir(x64=True) | |
| 947 lib = os.path.join(self.si.WindowsSdkDir, 'lib') | |
| 948 libver = self._sdk_subdir | |
| 949 return [os.path.join(lib, '%sum%s' % (libver , arch_subdir))] | |
| 950 | |
| 951 @property | |
| 952 def OSIncludes(self): | |
| 953 """ | |
| 954 Microsoft Windows SDK Include | |
| 955 """ | |
| 956 include = os.path.join(self.si.WindowsSdkDir, 'include') | |
| 957 | |
| 958 if self.vc_ver <= 10.0: | |
| 959 return [include, os.path.join(include, 'gl')] | |
| 960 | |
| 961 else: | |
| 962 if self.vc_ver >= 14.0: | |
| 963 sdkver = self._sdk_subdir | |
| 964 else: | |
| 965 sdkver = '' | |
| 966 return [os.path.join(include, '%sshared' % sdkver), | |
| 967 os.path.join(include, '%sum' % sdkver), | |
| 968 os.path.join(include, '%swinrt' % sdkver)] | |
| 969 | |
| 970 @property | |
| 971 def OSLibpath(self): | |
| 972 """ | |
| 973 Microsoft Windows SDK Libraries Paths | |
| 974 """ | |
| 975 ref = os.path.join(self.si.WindowsSdkDir, 'References') | |
| 976 libpath = [] | |
| 977 | |
| 978 if self.vc_ver <= 9.0: | |
| 979 libpath += self.OSLibraries | |
| 980 | |
| 981 if self.vc_ver >= 11.0: | |
| 982 libpath += [os.path.join(ref, r'CommonConfiguration\Neutral')] | |
| 983 | |
| 984 if self.vc_ver >= 14.0: | |
| 985 libpath += [ | |
| 986 ref, | |
| 987 os.path.join(self.si.WindowsSdkDir, 'UnionMetadata'), | |
| 988 os.path.join( | |
| 989 ref, | |
| 990 'Windows.Foundation.UniversalApiContract', | |
| 991 '1.0.0.0', | |
| 992 ), | |
| 993 os.path.join( | |
| 994 ref, | |
| 995 'Windows.Foundation.FoundationContract', | |
| 996 '1.0.0.0', | |
| 997 ), | |
| 998 os.path.join( | |
| 999 ref, | |
| 1000 'Windows.Networking.Connectivity.WwanContract', | |
| 1001 '1.0.0.0', | |
| 1002 ), | |
| 1003 os.path.join( | |
| 1004 self.si.WindowsSdkDir, | |
| 1005 'ExtensionSDKs', | |
| 1006 'Microsoft.VCLibs', | |
| 1007 '%0.1f' % self.vc_ver, | |
| 1008 'References', | |
| 1009 'CommonConfiguration', | |
| 1010 'neutral', | |
| 1011 ), | |
| 1012 ] | |
| 1013 return libpath | |
| 1014 | |
| 1015 @property | |
| 1016 def SdkTools(self): | |
| 1017 """ | |
| 1018 Microsoft Windows SDK Tools | |
| 1019 """ | |
| 1020 return list(self._sdk_tools()) | |
| 1021 | |
| 1022 def _sdk_tools(self): | |
| 1023 """ | |
| 1024 Microsoft Windows SDK Tools paths generator | |
| 1025 """ | |
| 1026 if self.vc_ver < 15.0: | |
| 1027 bin_dir = 'Bin' if self.vc_ver <= 11.0 else r'Bin\x86' | |
| 1028 yield os.path.join(self.si.WindowsSdkDir, bin_dir) | |
| 1029 | |
| 1030 if not self.pi.current_is_x86(): | |
| 1031 arch_subdir = self.pi.current_dir(x64=True) | |
| 1032 path = 'Bin%s' % arch_subdir | |
| 1033 yield os.path.join(self.si.WindowsSdkDir, path) | |
| 1034 | |
| 1035 if self.vc_ver == 10.0 or self.vc_ver == 11.0: | |
| 1036 if self.pi.target_is_x86(): | |
| 1037 arch_subdir = '' | |
| 1038 else: | |
| 1039 arch_subdir = self.pi.current_dir(hidex86=True, x64=True) | |
| 1040 path = r'Bin\NETFX 4.0 Tools%s' % arch_subdir | |
| 1041 yield os.path.join(self.si.WindowsSdkDir, path) | |
| 1042 | |
| 1043 elif self.vc_ver >= 15.0: | |
| 1044 path = os.path.join(self.si.WindowsSdkDir, 'Bin') | |
| 1045 arch_subdir = self.pi.current_dir(x64=True) | |
| 1046 sdkver = self.si.WindowsSdkLastVersion | |
| 1047 yield os.path.join(path, '%s%s' % (sdkver, arch_subdir)) | |
| 1048 | |
| 1049 if self.si.WindowsSDKExecutablePath: | |
| 1050 yield self.si.WindowsSDKExecutablePath | |
| 1051 | |
| 1052 @property | |
| 1053 def _sdk_subdir(self): | |
| 1054 """ | |
| 1055 Microsoft Windows SDK version subdir | |
| 1056 """ | |
| 1057 ucrtver = self.si.WindowsSdkLastVersion | |
| 1058 return ('%s\\' % ucrtver) if ucrtver else '' | |
| 1059 | |
| 1060 @property | |
| 1061 def SdkSetup(self): | |
| 1062 """ | |
| 1063 Microsoft Windows SDK Setup | |
| 1064 """ | |
| 1065 if self.vc_ver > 9.0: | |
| 1066 return [] | |
| 1067 | |
| 1068 return [os.path.join(self.si.WindowsSdkDir, 'Setup')] | |
| 1069 | |
| 1070 @property | |
| 1071 def FxTools(self): | |
| 1072 """ | |
| 1073 Microsoft .NET Framework Tools | |
| 1074 """ | |
| 1075 pi = self.pi | |
| 1076 si = self.si | |
| 1077 | |
| 1078 if self.vc_ver <= 10.0: | |
| 1079 include32 = True | |
| 1080 include64 = not pi.target_is_x86() and not pi.current_is_x86() | |
| 1081 else: | |
| 1082 include32 = pi.target_is_x86() or pi.current_is_x86() | |
| 1083 include64 = pi.current_cpu == 'amd64' or pi.target_cpu == 'amd64' | |
| 1084 | |
| 1085 tools = [] | |
| 1086 if include32: | |
| 1087 tools += [os.path.join(si.FrameworkDir32, ver) | |
| 1088 for ver in si.FrameworkVersion32] | |
| 1089 if include64: | |
| 1090 tools += [os.path.join(si.FrameworkDir64, ver) | |
| 1091 for ver in si.FrameworkVersion64] | |
| 1092 return tools | |
| 1093 | |
| 1094 @property | |
| 1095 def NetFxSDKLibraries(self): | |
| 1096 """ | |
| 1097 Microsoft .Net Framework SDK Libraries | |
| 1098 """ | |
| 1099 if self.vc_ver < 14.0 or not self.si.NetFxSdkDir: | |
| 1100 return [] | |
| 1101 | |
| 1102 arch_subdir = self.pi.target_dir(x64=True) | |
| 1103 return [os.path.join(self.si.NetFxSdkDir, r'lib\um%s' % arch_subdir)] | |
| 1104 | |
| 1105 @property | |
| 1106 def NetFxSDKIncludes(self): | |
| 1107 """ | |
| 1108 Microsoft .Net Framework SDK Includes | |
| 1109 """ | |
| 1110 if self.vc_ver < 14.0 or not self.si.NetFxSdkDir: | |
| 1111 return [] | |
| 1112 | |
| 1113 return [os.path.join(self.si.NetFxSdkDir, r'include\um')] | |
| 1114 | |
| 1115 @property | |
| 1116 def VsTDb(self): | |
| 1117 """ | |
| 1118 Microsoft Visual Studio Team System Database | |
| 1119 """ | |
| 1120 return [os.path.join(self.si.VSInstallDir, r'VSTSDB\Deploy')] | |
| 1121 | |
| 1122 @property | |
| 1123 def MSBuild(self): | |
| 1124 """ | |
| 1125 Microsoft Build Engine | |
| 1126 """ | |
| 1127 if self.vc_ver < 12.0: | |
| 1128 return [] | |
| 1129 elif self.vc_ver < 15.0: | |
| 1130 base_path = self.si.ProgramFilesx86 | |
| 1131 arch_subdir = self.pi.current_dir(hidex86=True) | |
| 1132 else: | |
| 1133 base_path = self.si.VSInstallDir | |
| 1134 arch_subdir = '' | |
| 1135 | |
| 1136 path = r'MSBuild\%0.1f\bin%s' % (self.vc_ver, arch_subdir) | |
| 1137 build = [os.path.join(base_path, path)] | |
| 1138 | |
| 1139 if self.vc_ver >= 15.0: | |
| 1140 # Add Roslyn C# & Visual Basic Compiler | |
| 1141 build += [os.path.join(base_path, path, 'Roslyn')] | |
| 1142 | |
| 1143 return build | |
| 1144 | |
| 1145 @property | |
| 1146 def HTMLHelpWorkshop(self): | |
| 1147 """ | |
| 1148 Microsoft HTML Help Workshop | |
| 1149 """ | |
| 1150 if self.vc_ver < 11.0: | |
| 1151 return [] | |
| 1152 | |
| 1153 return [os.path.join(self.si.ProgramFilesx86, 'HTML Help Workshop')] | |
| 1154 | |
| 1155 @property | |
| 1156 def UCRTLibraries(self): | |
| 1157 """ | |
| 1158 Microsoft Universal C Runtime SDK Libraries | |
| 1159 """ | |
| 1160 if self.vc_ver < 14.0: | |
| 1161 return [] | |
| 1162 | |
| 1163 arch_subdir = self.pi.target_dir(x64=True) | |
| 1164 lib = os.path.join(self.si.UniversalCRTSdkDir, 'lib') | |
| 1165 ucrtver = self._ucrt_subdir | |
| 1166 return [os.path.join(lib, '%sucrt%s' % (ucrtver, arch_subdir))] | |
| 1167 | |
| 1168 @property | |
| 1169 def UCRTIncludes(self): | |
| 1170 """ | |
| 1171 Microsoft Universal C Runtime SDK Include | |
| 1172 """ | |
| 1173 if self.vc_ver < 14.0: | |
| 1174 return [] | |
| 1175 | |
| 1176 include = os.path.join(self.si.UniversalCRTSdkDir, 'include') | |
| 1177 return [os.path.join(include, '%sucrt' % self._ucrt_subdir)] | |
| 1178 | |
| 1179 @property | |
| 1180 def _ucrt_subdir(self): | |
| 1181 """ | |
| 1182 Microsoft Universal C Runtime SDK version subdir | |
| 1183 """ | |
| 1184 ucrtver = self.si.UniversalCRTSdkLastVersion | |
| 1185 return ('%s\\' % ucrtver) if ucrtver else '' | |
| 1186 | |
| 1187 @property | |
| 1188 def FSharp(self): | |
| 1189 """ | |
| 1190 Microsoft Visual F# | |
| 1191 """ | |
| 1192 if self.vc_ver < 11.0 and self.vc_ver > 12.0: | |
| 1193 return [] | |
| 1194 | |
| 1195 return self.si.FSharpInstallDir | |
| 1196 | |
| 1197 @property | |
| 1198 def VCRuntimeRedist(self): | |
| 1199 """ | |
| 1200 Microsoft Visual C++ runtime redistribuable dll | |
| 1201 """ | |
| 1202 arch_subdir = self.pi.target_dir(x64=True) | |
| 1203 if self.vc_ver < 15: | |
| 1204 redist_path = self.si.VCInstallDir | |
| 1205 vcruntime = 'redist%s\\Microsoft.VC%d0.CRT\\vcruntime%d0.dll' | |
| 1206 else: | |
| 1207 redist_path = self.si.VCInstallDir.replace('\\Tools', '\\Redist') | |
| 1208 vcruntime = 'onecore%s\\Microsoft.VC%d0.CRT\\vcruntime%d0.dll' | |
| 1209 | |
| 1210 # Visual Studio 2017 is still Visual C++ 14.0 | |
| 1211 dll_ver = 14.0 if self.vc_ver == 15 else self.vc_ver | |
| 1212 | |
| 1213 vcruntime = vcruntime % (arch_subdir, self.vc_ver, dll_ver) | |
| 1214 return os.path.join(redist_path, vcruntime) | |
| 1215 | |
| 1216 def return_env(self, exists=True): | |
| 1217 """ | |
| 1218 Return environment dict. | |
| 1219 | |
| 1220 Parameters | |
| 1221 ---------- | |
| 1222 exists: bool | |
| 1223 It True, only return existing paths. | |
| 1224 """ | |
| 1225 env = dict( | |
| 1226 include=self._build_paths('include', | |
| 1227 [self.VCIncludes, | |
| 1228 self.OSIncludes, | |
| 1229 self.UCRTIncludes, | |
| 1230 self.NetFxSDKIncludes], | |
| 1231 exists), | |
| 1232 lib=self._build_paths('lib', | |
| 1233 [self.VCLibraries, | |
| 1234 self.OSLibraries, | |
| 1235 self.FxTools, | |
| 1236 self.UCRTLibraries, | |
| 1237 self.NetFxSDKLibraries], | |
| 1238 exists), | |
| 1239 libpath=self._build_paths('libpath', | |
| 1240 [self.VCLibraries, | |
| 1241 self.FxTools, | |
| 1242 self.VCStoreRefs, | |
| 1243 self.OSLibpath], | |
| 1244 exists), | |
| 1245 path=self._build_paths('path', | |
| 1246 [self.VCTools, | |
| 1247 self.VSTools, | |
| 1248 self.VsTDb, | |
| 1249 self.SdkTools, | |
| 1250 self.SdkSetup, | |
| 1251 self.FxTools, | |
| 1252 self.MSBuild, | |
| 1253 self.HTMLHelpWorkshop, | |
| 1254 self.FSharp], | |
| 1255 exists), | |
| 1256 ) | |
| 1257 if self.vc_ver >= 14 and os.path.isfile(self.VCRuntimeRedist): | |
| 1258 env['py_vcruntime_redist'] = self.VCRuntimeRedist | |
| 1259 return env | |
| 1260 | |
| 1261 def _build_paths(self, name, spec_path_lists, exists): | |
| 1262 """ | |
| 1263 Given an environment variable name and specified paths, | |
| 1264 return a pathsep-separated string of paths containing | |
| 1265 unique, extant, directories from those paths and from | |
| 1266 the environment variable. Raise an error if no paths | |
| 1267 are resolved. | |
| 1268 """ | |
| 1269 # flatten spec_path_lists | |
| 1270 spec_paths = itertools.chain.from_iterable(spec_path_lists) | |
| 1271 env_paths = safe_env.get(name, '').split(os.pathsep) | |
| 1272 paths = itertools.chain(spec_paths, env_paths) | |
| 1273 extant_paths = list(filter(os.path.isdir, paths)) if exists else paths | |
| 1274 if not extant_paths: | |
| 1275 msg = "%s environment variable is empty" % name.upper() | |
| 1276 raise distutils.errors.DistutilsPlatformError(msg) | |
| 1277 unique_paths = self._unique_everseen(extant_paths) | |
| 1278 return os.pathsep.join(unique_paths) | |
| 1279 | |
| 1280 # from Python docs | |
| 1281 def _unique_everseen(self, iterable, key=None): | |
| 1282 """ | |
| 1283 List unique elements, preserving order. | |
| 1284 Remember all elements ever seen. | |
| 1285 | |
| 1286 _unique_everseen('AAAABBBCCDAABBB') --> A B C D | |
| 1287 | |
| 1288 _unique_everseen('ABBCcAD', str.lower) --> A B C D | |
| 1289 """ | |
| 1290 seen = set() | |
| 1291 seen_add = seen.add | |
| 1292 if key is None: | |
| 1293 for element in filterfalse(seen.__contains__, iterable): | |
| 1294 seen_add(element) | |
| 1295 yield element | |
| 1296 else: | |
| 1297 for element in iterable: | |
| 1298 k = key(element) | |
| 1299 if k not in seen: | |
| 1300 seen_add(k) | |
| 1301 yield element |
