OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 | 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
3 # Copyright (c) 2009 Google Inc. All rights reserved. | |
4 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 4 # found in the LICENSE file. |
6 | 5 |
7 """Handle version information related to Visual Stuio.""" | 6 """Handle version information related to Visual Stuio.""" |
8 | 7 |
| 8 import errno |
9 import os | 9 import os |
10 import re | 10 import re |
11 import subprocess | 11 import subprocess |
12 import sys | 12 import sys |
13 | 13 |
14 | 14 |
15 class VisualStudioVersion: | 15 class VisualStudioVersion: |
16 """Information regarding a version of Visual Studio.""" | 16 """Information regarding a version of Visual Studio.""" |
17 | 17 |
18 def __init__(self, short_name, description, | 18 def __init__(self, short_name, description, |
(...skipping 24 matching lines...) Expand all Loading... |
43 return self.flat_sln | 43 return self.flat_sln |
44 | 44 |
45 def UsesVcxproj(self): | 45 def UsesVcxproj(self): |
46 """Returns true if this version uses a vcxproj file.""" | 46 """Returns true if this version uses a vcxproj file.""" |
47 return self.uses_vcxproj | 47 return self.uses_vcxproj |
48 | 48 |
49 def ProjectExtension(self): | 49 def ProjectExtension(self): |
50 """Returns the file extension for the project.""" | 50 """Returns the file extension for the project.""" |
51 return self.uses_vcxproj and '.vcxproj' or '.vcproj' | 51 return self.uses_vcxproj and '.vcxproj' or '.vcproj' |
52 | 52 |
53 def _RegistryGetValue(key, value): | 53 def _RegistryQueryBase(sysdir, key, value): |
54 """Use reg.exe to read a paricular key. | 54 """Use reg.exe to read a particular key. |
55 | 55 |
56 While ideally we might use the win32 module, we would like gyp to be | 56 While ideally we might use the win32 module, we would like gyp to be |
57 python neutral, so for instance cygwin python lacks this module. | 57 python neutral, so for instance cygwin python lacks this module. |
58 | 58 |
59 Arguments: | 59 Arguments: |
| 60 sysdir: The system subdirectory to attempt to launch reg.exe from. |
60 key: The registry key to read from. | 61 key: The registry key to read from. |
61 value: The particular value to read. | 62 value: The particular value to read. |
62 Return: | 63 Return: |
63 The contents there, or None for failure. | 64 stdout from reg.exe, or None for failure. |
64 """ | 65 """ |
65 # Skip if not on Windows. | 66 # Skip if not on Windows or Python Win32 setup issue |
66 if sys.platform not in ('win32', 'cygwin'): | 67 if sys.platform not in ('win32', 'cygwin'): |
67 return None | 68 return None |
68 # Run reg.exe. | 69 # Setup params to pass to and attempt to launch reg.exe |
69 cmd = [os.path.join(os.environ.get('WINDIR', ''), 'System32', 'reg.exe'), | 70 cmd = [os.path.join(os.environ.get('WINDIR', ''), sysdir, 'reg.exe'), |
70 'query', key, '/v', value] | 71 'query', key] |
| 72 if value: |
| 73 cmd.extend(['/v', value]) |
71 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 74 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| 75 # Obtain the stdout from reg.exe, reading to the end so p.returncode is valid |
| 76 # Note that the error text may be in [1] in some cases |
72 text = p.communicate()[0] | 77 text = p.communicate()[0] |
73 # Require a successful return value. | 78 # Check return code from reg.exe; officially 0==success and 1==error |
74 if p.returncode: | 79 if p.returncode: |
75 return None | 80 return None |
| 81 return text |
| 82 |
| 83 def _RegistryQuery(key, value=None): |
| 84 """Use reg.exe to read a particular key through _RegistryQueryBase. |
| 85 |
| 86 First tries to launch from %WinDir%\Sysnative to avoid WoW64 redirection. If |
| 87 that fails, it falls back to System32. Sysnative is available on Vista and |
| 88 up and available on Windows Server 2003 and XP through KB patch 942589. Note |
| 89 that Sysnative will always fail if using 64-bit python due to it being a |
| 90 virtual directory and System32 will work correctly in the first place. |
| 91 |
| 92 KB 942589 - http://support.microsoft.com/kb/942589/en-us. |
| 93 |
| 94 Arguments: |
| 95 key: The registry key. |
| 96 value: The particular registry value to read (optional). |
| 97 Return: |
| 98 stdout from reg.exe, or None for failure. |
| 99 """ |
| 100 text = None |
| 101 try: |
| 102 text = _RegistryQueryBase('Sysnative', key, value) |
| 103 except OSError, e: |
| 104 if e.errno == errno.ENOENT: |
| 105 text = _RegistryQueryBase('System32', key, value) |
| 106 else: |
| 107 raise |
| 108 return text |
| 109 |
| 110 def _RegistryGetValue(key, value): |
| 111 """Use reg.exe to obtain the value of a registry key. |
| 112 |
| 113 Args: |
| 114 key: The registry key. |
| 115 value: The particular registry value to read. |
| 116 Return: |
| 117 contents of the registry key's value, or None on failure. |
| 118 """ |
| 119 text = _RegistryQuery(key, value) |
| 120 if not text: |
| 121 return None |
76 # Extract value. | 122 # Extract value. |
77 match = re.search(r'REG_\w+\s+([^\r]+)\r\n', text) | 123 match = re.search(r'REG_\w+\s+([^\r]+)\r\n', text) |
78 if not match: | 124 if not match: |
79 return None | 125 return None |
80 return match.group(1) | 126 return match.group(1) |
81 | 127 |
82 | |
83 def _RegistryKeyExists(key): | 128 def _RegistryKeyExists(key): |
84 """Use reg.exe to see if a key exists. | 129 """Use reg.exe to see if a key exists. |
85 | 130 |
86 Args: | 131 Args: |
87 key: The registry key to check. | 132 key: The registry key to check. |
88 Return: | 133 Return: |
89 True if the key exists | 134 True if the key exists |
90 """ | 135 """ |
91 # Skip if not on Windows. | 136 if not _RegistryQuery(key): |
92 if sys.platform not in ('win32', 'cygwin'): | 137 return False |
93 return None | 138 return True |
94 # Run reg.exe. | |
95 cmd = [os.path.join(os.environ.get('WINDIR', ''), 'System32', 'reg.exe'), | |
96 'query', key] | |
97 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
98 return p.returncode == 0 | |
99 | 139 |
100 | 140 |
101 def _CreateVersion(name): | 141 def _CreateVersion(name): |
| 142 """Sets up MSVS project generation. |
| 143 |
| 144 Setup is based off the GYP_MSVS_VERSION environment variable or whatever is |
| 145 autodetected if GYP_MSVS_VERSION is not explicitly specified. If a version is |
| 146 passed in that doesn't match a value in versions python will throw a error. |
| 147 """ |
102 versions = { | 148 versions = { |
103 '2010': VisualStudioVersion('2010', | 149 '2010': VisualStudioVersion('2010', |
104 'Visual Studio 2010', | 150 'Visual Studio 2010', |
105 solution_version='11.00', | 151 solution_version='11.00', |
106 project_version='4.0', | 152 project_version='4.0', |
107 flat_sln=False, | 153 flat_sln=False, |
108 uses_vcxproj=True), | 154 uses_vcxproj=True), |
| 155 '2010e': VisualStudioVersion('2010e', |
| 156 'Visual Studio 2010', |
| 157 solution_version='11.00', |
| 158 project_version='4.0', |
| 159 flat_sln=True, |
| 160 uses_vcxproj=True), |
109 '2008': VisualStudioVersion('2008', | 161 '2008': VisualStudioVersion('2008', |
110 'Visual Studio 2008', | 162 'Visual Studio 2008', |
111 solution_version='10.00', | 163 solution_version='10.00', |
112 project_version='9.00', | 164 project_version='9.00', |
113 flat_sln=False, | 165 flat_sln=False, |
114 uses_vcxproj=False), | 166 uses_vcxproj=False), |
115 '2008e': VisualStudioVersion('2008e', | 167 '2008e': VisualStudioVersion('2008e', |
116 'Visual Studio 2008', | 168 'Visual Studio 2008', |
117 solution_version='10.00', | 169 solution_version='10.00', |
118 project_version='9.00', | 170 project_version='9.00', |
(...skipping 17 matching lines...) Expand all Loading... |
136 | 188 |
137 def _DetectVisualStudioVersions(): | 189 def _DetectVisualStudioVersions(): |
138 """Collect the list of installed visual studio versions. | 190 """Collect the list of installed visual studio versions. |
139 | 191 |
140 Returns: | 192 Returns: |
141 A list of visual studio versions installed in descending order of | 193 A list of visual studio versions installed in descending order of |
142 usage preference. | 194 usage preference. |
143 Base this on the registry and a quick check if devenv.exe exists. | 195 Base this on the registry and a quick check if devenv.exe exists. |
144 Only versions 8-10 are considered. | 196 Only versions 8-10 are considered. |
145 Possibilities are: | 197 Possibilities are: |
146 2005 - Visual Studio 2005 (8) | 198 2005(e) - Visual Studio 2005 (8) |
147 2008 - Visual Studio 2008 (9) | 199 2008(e) - Visual Studio 2008 (9) |
148 2010 - Visual Studio 2010 (10) | 200 2010(e) - Visual Studio 2010 (10) |
| 201 Where (e) is e for express editions of MSVS and blank otherwise. |
149 """ | 202 """ |
150 version_to_year = {'8.0': '2005', '9.0': '2008', '10.0': '2010'} | 203 version_to_year = {'8.0': '2005', '9.0': '2008', '10.0': '2010'} |
151 versions = [] | 204 versions = [] |
152 # For now, prefer versions before VS2010 | 205 # For now, prefer versions before VS2010 |
153 for version in ('9.0', '8.0', '10.0'): | 206 for version in ('9.0', '8.0', '10.0'): |
154 # Check if VS2010 and later is installed as specified by | 207 # Check if VS2010 and later is installed as specified by |
155 # http://msdn.microsoft.com/en-us/library/bb164659.aspx | 208 # http://msdn.microsoft.com/en-us/library/bb164659.aspx |
156 key32 = r'HKLM\SOFTWARE\Microsoft\DevDiv\VS\Servicing\%s' % version | 209 keys = [r'HKLM\SOFTWARE\Microsoft\DevDiv\VS\Servicing\%s' % version, |
157 key64 = r'HKLM\SOFTWARE\Wow6432Node\Microsoft\DevDiv\VS\Servicing\%sD' % ( | 210 r'HKLM\SOFTWARE\Wow6432Node\Microsoft\DevDiv\VS\Servicing\%s' % ( |
158 version) | 211 version)] |
159 if _RegistryKeyExists(key32) or _RegistryKeyExists(key64): | 212 for index in range(len(keys)): |
160 # Add this one. | 213 if not _RegistryKeyExists(keys[index]): |
161 # TODO(jeanluc) This does not check for an express version. | 214 continue |
162 versions.append(_CreateVersion(version_to_year[version])) | 215 # Check for express |
163 continue | 216 if _RegistryKeyExists(keys[index] + '\expbsln'): |
164 # Get the install dir for this version. | 217 # Add this one |
165 key = r'HKLM\Software\Microsoft\VisualStudio\%s' % version | 218 versions.append(_CreateVersion(version_to_year[version] + 'e')) |
166 path = _RegistryGetValue(key, 'InstallDir') | 219 else: |
167 if not path: | 220 # Add this one |
168 continue | 221 versions.append(_CreateVersion(version_to_year[version])) |
169 # Check for full. | 222 |
170 if os.path.exists(os.path.join(path, 'devenv.exe')): | 223 # Old (pre-VS2010) method of searching for which VS version is installed |
171 # Add this one. | 224 keys = [r'HKLM\Software\Microsoft\VisualStudio\%s' % version, |
172 versions.append(_CreateVersion(version_to_year[version])) | 225 r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\%s' % version, |
173 # Check for express. | 226 r'HKLM\Software\Microsoft\VCExpress\%s' % version, |
174 elif os.path.exists(os.path.join(path, 'vcexpress.exe')): | 227 r'HKLM\Software\Wow6432Node\Microsoft\VCExpress\%s' % version] |
175 # Add this one. | 228 for index in range(len(keys)): |
176 versions.append(_CreateVersion(version_to_year[version] + 'e')) | 229 path = _RegistryGetValue(keys[index], 'InstallDir') |
| 230 if not path: |
| 231 continue |
| 232 # Check for full. |
| 233 if os.path.exists(os.path.join(path, 'devenv.exe')): |
| 234 # Add this one. |
| 235 versions.append(_CreateVersion(version_to_year[version])) |
| 236 # Check for express. |
| 237 elif os.path.exists(os.path.join(path, 'vcexpress.exe')): |
| 238 # Add this one. |
| 239 versions.append(_CreateVersion(version_to_year[version] + 'e')) |
177 return versions | 240 return versions |
178 | 241 |
179 | 242 |
180 def SelectVisualStudioVersion(version='auto'): | 243 def SelectVisualStudioVersion(version='auto'): |
181 """Select which version of Visual Studio projects to generate. | 244 """Select which version of Visual Studio projects to generate. |
182 | 245 |
183 Arguments: | 246 Arguments: |
184 version: Hook to allow caller to force a particular version (vs auto). | 247 version: Hook to allow caller to force a particular version (vs auto). |
185 Returns: | 248 Returns: |
186 An object representing a visual studio project format version. | 249 An object representing a visual studio project format version. |
187 """ | 250 """ |
188 # In auto mode, check environment variable for override. | 251 # In auto mode, check environment variable for override. |
189 if version == 'auto': | 252 if version == 'auto': |
190 version = os.environ.get('GYP_MSVS_VERSION', 'auto') | 253 version = os.environ.get('GYP_MSVS_VERSION', 'auto') |
191 # In auto mode, pick the most preferred version present. | 254 # In auto mode, pick the most preferred version present. |
192 if version == 'auto': | 255 if version == 'auto': |
193 versions = _DetectVisualStudioVersions() | 256 versions = _DetectVisualStudioVersions() |
194 if not versions: | 257 if not versions: |
195 # Default to 2005. | 258 # Default to 2005. |
196 return _CreateVersion('2005') | 259 return _CreateVersion('2005') |
197 return versions[0] | 260 return versions[0] |
198 # Convert version string into a version object. | 261 # Convert version string into a version object. |
199 return _CreateVersion(version) | 262 return _CreateVersion(version) |
OLD | NEW |