|
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