annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/site-packages/setuptools/msvc.py @ 68:5028fdace37b

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