Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: pylib/gyp/MSVSVersion.py

Issue 6729005: GYP: Stronger MSVS Version Autodetection; VC2010 Express support Base URL: http://gyp.googlecode.com/svn/trunk/
Patch Set: Registry logic cleanup; try Sysnative before System32; AUTHORS Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « AUTHORS ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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)
OLDNEW
« no previous file with comments | « AUTHORS ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698