|
6 | 6 | an egg or wheel.
|
7 | 7 | """
|
8 | 8 |
|
| 9 | +import collections |
9 | 10 | import fnmatch
|
10 | 11 | import glob
|
11 | 12 | import os
|
|
24 | 25 | DEVTOOLS = "MsDev" if sys.platform == "win32" else "Mono"
|
25 | 26 | ARCH = "x64" if platform.architecture()[0] == "64bit" else "x86"
|
26 | 27 |
|
| 28 | +############################################################################### |
| 29 | +# Windows Keys Constants for MSBUILD tools |
| 30 | +RegKey = collections.namedtuple('RegKey', 'sdk_name key value_name suffix') |
| 31 | +vs_python = "Programs\\Common\\Microsoft\\Visual C++ for Python\\9.0\\WinSDK" |
| 32 | +vs_root = "SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\{0}" |
| 33 | +sdks_root = "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v{0}Win32Tools" |
| 34 | +kits_root = "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots" |
| 35 | +kits_suffix = os.path.join("bin", ARCH) |
27 | 36 |
|
| 37 | +WIN_SDK_KEYS = ( |
| 38 | + RegKey(sdk_name="Windows Kit 10.0", key=kits_root, |
| 39 | + value_name="KitsRoot10", suffix=kits_suffix), |
| 40 | + |
| 41 | + RegKey(sdk_name="Windows Kit 8.1", key=kits_root, |
| 42 | + value_name="KitsRoot81", suffix=kits_suffix), |
| 43 | + |
| 44 | + RegKey(sdk_name="Windows Kit 8.0", key=kits_root, |
| 45 | + value_name="KitsRoot", suffix=kits_suffix), |
| 46 | + |
| 47 | + RegKey(sdk_name="Windows SDK 7.1A", key=sdks_root.format("7.1A\\WinSDK-"), |
| 48 | + value_name="InstallationFolder", suffix=""), |
| 49 | + |
| 50 | + RegKey(sdk_name="Windows SDK 7.1", key=sdks_root.format("7.1\\WinSDK"), |
| 51 | + value_name="InstallationFolder", suffix=""), |
| 52 | + |
| 53 | + RegKey(sdk_name="Windows SDK 7.0A", key=sdks_root.format("7.0A\\WinSDK-"), |
| 54 | + value_name="InstallationFolder", suffix=""), |
| 55 | + |
| 56 | + RegKey(sdk_name="Windows SDK 7.0", key=sdks_root.format("7.0\\WinSDK"), |
| 57 | + value_name="InstallationFolder", suffix=""), |
| 58 | + |
| 59 | + RegKey(sdk_name="Windows SDK 6.0A", key=sdks_root.format("6.0A\\WinSDK"), |
| 60 | + value_name="InstallationFolder", suffix=""), |
| 61 | +) |
| 62 | + |
| 63 | +VS_KEYS = ( |
| 64 | + RegKey(sdk_name="MSBuild 14", key=vs_root.format("14.0"), |
| 65 | + value_name="MSBuildToolsPath", suffix=""), |
| 66 | + |
| 67 | + RegKey(sdk_name="MSBuild 12", key=vs_root.format("12.0"), |
| 68 | + value_name="MSBuildToolsPath", suffix=""), |
| 69 | + |
| 70 | + RegKey(sdk_name="MSBuild 4", key=vs_root.format("4.0"), |
| 71 | + value_name="MSBuildToolsPath", suffix=""), |
| 72 | + |
| 73 | + RegKey(sdk_name="MSBuild 3.5", key=vs_root.format("3.5"), |
| 74 | + value_name="MSBuildToolsPath", suffix=""), |
| 75 | + |
| 76 | + RegKey(sdk_name="MSBuild 2.0", key=vs_root.format("2.0"), |
| 77 | + value_name="MSBuildToolsPath", suffix=""), |
| 78 | +) |
| 79 | + |
| 80 | + |
| 81 | +############################################################################### |
28 | 82 | def _find_msbuild_tool(tool="msbuild.exe", use_windows_sdk=False):
|
29 | 83 | """Return full path to one of the Microsoft build tools"""
|
| 84 | + # Search in PATH first |
30 | 85 | path = spawn.find_executable(tool)
|
31 | 86 | if path:
|
32 | 87 | return path
|
33 | 88 |
|
| 89 | + # Search within registry to find build tools |
34 | 90 | try: # PY2
|
35 | 91 | import _winreg as winreg
|
36 | 92 | except ImportError: # PY3
|
37 | 93 | import winreg
|
38 | 94 |
|
39 |
| - keys_to_check = [] |
40 |
| - if use_windows_sdk: |
41 |
| - sdks_root = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows" |
42 |
| - kits_root = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots" |
43 |
| - kits_suffix = os.path.join("bin", ARCH) |
44 |
| - keys_to_check.extend([ |
45 |
| - ("Windows Kit 10.0", kits_root, "KitsRoot10", kits_suffix), |
46 |
| - ("Windows Kit 8.1", kits_root, "KitsRoot81", kits_suffix), |
47 |
| - ("Windows Kit 8.0", kits_root, "KitsRoot", kits_suffix), |
48 |
| - ("Windows SDK 7.1A", sdks_root + r"\v7.1A\WinSDK-Win32Tools", "InstallationFolder"), |
49 |
| - ("Windows SDK 7.1", sdks_root + r"\v7.1\WinSDKWin32Tools", "InstallationFolder"), |
50 |
| - ("Windows SDK 7.0A", sdks_root + r"\v7.0A\WinSDK-Win32Tools", "InstallationFolder"), |
51 |
| - ("Windows SDK 7.0", sdks_root + r"\v7.0\WinSDKWin32Tools", "InstallationFolder"), |
52 |
| - ("Windows SDK 6.0A", sdks_root + r"\v6.0A\WinSDKWin32Tools", "InstallationFolder") |
53 |
| - ]) |
54 |
| - else: |
55 |
| - vs_root = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions" |
56 |
| - keys_to_check.extend([ |
57 |
| - ("MSBuild 14", vs_root + r"\14.0", "MSBuildToolsPath"), |
58 |
| - ("MSBuild 12", vs_root + r"\12.0", "MSBuildToolsPath"), |
59 |
| - ("MSBuild 4", vs_root + r"\4.0", "MSBuildToolsPath"), |
60 |
| - ("MSBuild 3.5", vs_root + r"\3.5", "MSBuildToolsPath"), |
61 |
| - ("MSBuild 2.0", vs_root + r"\2.0", "MSBuildToolsPath") |
62 |
| - ]) |
63 |
| - |
64 |
| - # read the possible tools paths from the various registry locations |
65 |
| - paths_to_check = [] |
66 |
| - hreg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) |
67 |
| - try: |
68 |
| - for key_to_check in keys_to_check: |
69 |
| - sdk_name, key, value_name = key_to_check[:3] |
70 |
| - suffix = key_to_check[3] if len(key_to_check) > 3 else None |
71 |
| - hkey = None |
72 |
| - try: |
73 |
| - hkey = winreg.OpenKey(hreg, key) |
74 |
| - val, type_ = winreg.QueryValueEx(hkey, value_name) |
| 95 | + keys_to_check = WIN_SDK_KEYS if use_windows_sdk else VS_KEYS |
| 96 | + for rkey in keys_to_check: |
| 97 | + try: |
| 98 | + with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, rkey.key) as hkey: |
| 99 | + val, type_ = winreg.QueryValueEx(hkey, rkey.value_name) |
75 | 100 | if type_ != winreg.REG_SZ:
|
76 | 101 | continue
|
77 |
| - if suffix: |
78 |
| - val = os.path.join(val, suffix) |
79 |
| - paths_to_check.append((sdk_name, val)) |
80 |
| - except WindowsError: |
81 |
| - pass |
82 |
| - finally: |
83 |
| - if hkey: |
84 |
| - hkey.Close() |
85 |
| - finally: |
86 |
| - hreg.Close() |
| 102 | + path = os.path.join(val, rkey.suffix, tool) |
| 103 | + if os.path.exists(path): |
| 104 | + log.info("Using {0} from {1}".format(tool, rkey.sdk_name)) |
| 105 | + return path |
| 106 | + except WindowsError: |
| 107 | + # Key doesn't exist |
| 108 | + pass |
87 | 109 |
|
88 | 110 | # Add Visual C++ for Python as a fall-back in case one
|
89 | 111 | # of the other Windows SDKs isn't installed
|
90 | 112 | if use_windows_sdk:
|
| 113 | + sdk_name = "Visual C++ for Python" |
91 | 114 | localappdata = os.environ["LOCALAPPDATA"]
|
92 |
| - pywinsdk = localappdata + r"\Programs\Common\Microsoft\Visual C++ for Python\9.0\WinSDK\Bin" |
93 |
| - if ARCH == "x64": |
94 |
| - pywinsdk += r"\x64" |
95 |
| - paths_to_check.append(("Visual C++ for Python", pywinsdk)) |
96 |
| - |
97 |
| - for sdk_name, path in paths_to_check: |
98 |
| - path = os.path.join(path, tool) |
| 115 | + suffix = "Bin\\x64" if ARCH == "x64" else "Bin" |
| 116 | + path = os.path.join(localappdata, vs_python, suffix, tool) |
99 | 117 | if os.path.exists(path):
|
100 |
| - log.info("Using %s from %s" % (tool, sdk_name)) |
| 118 | + log.info("Using {0} from {1}".format(tool, sdk_name)) |
101 | 119 | return path
|
102 | 120 |
|
103 |
| - raise RuntimeError("%s could not be found" % tool) |
| 121 | + raise RuntimeError("{0} could not be found".format(tool)) |
104 | 122 |
|
105 | 123 |
|
106 | 124 | class BuildExtPythonnet(build_ext.build_ext):
|
|
0 commit comments