PageRenderTime 294ms CodeModel.GetById 46ms RepoModel.GetById 0ms app.codeStats 0ms

/flask/Lib/site-packages/setuptools/msvc.py

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