annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/site-packages/setuptools/msvc.py @ 69:33d812a61356

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