test: terminate gracefully in cluster-net-send
[platform/upstream/nodejs.git] / tools / gyp / pylib / gyp / MSVSVersion.py
1 # Copyright (c) 2013 Google Inc. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """Handle version information related to Visual Stuio."""
6
7 import errno
8 import os
9 import re
10 import subprocess
11 import sys
12 import gyp
13 import glob
14
15
16 class VisualStudioVersion(object):
17   """Information regarding a version of Visual Studio."""
18
19   def __init__(self, short_name, description,
20                solution_version, project_version, flat_sln, uses_vcxproj,
21                path, sdk_based, default_toolset=None):
22     self.short_name = short_name
23     self.description = description
24     self.solution_version = solution_version
25     self.project_version = project_version
26     self.flat_sln = flat_sln
27     self.uses_vcxproj = uses_vcxproj
28     self.path = path
29     self.sdk_based = sdk_based
30     self.default_toolset = default_toolset
31
32   def ShortName(self):
33     return self.short_name
34
35   def Description(self):
36     """Get the full description of the version."""
37     return self.description
38
39   def SolutionVersion(self):
40     """Get the version number of the sln files."""
41     return self.solution_version
42
43   def ProjectVersion(self):
44     """Get the version number of the vcproj or vcxproj files."""
45     return self.project_version
46
47   def FlatSolution(self):
48     return self.flat_sln
49
50   def UsesVcxproj(self):
51     """Returns true if this version uses a vcxproj file."""
52     return self.uses_vcxproj
53
54   def ProjectExtension(self):
55     """Returns the file extension for the project."""
56     return self.uses_vcxproj and '.vcxproj' or '.vcproj'
57
58   def Path(self):
59     """Returns the path to Visual Studio installation."""
60     return self.path
61
62   def ToolPath(self, tool):
63     """Returns the path to a given compiler tool. """
64     return os.path.normpath(os.path.join(self.path, "VC/bin", tool))
65
66   def DefaultToolset(self):
67     """Returns the msbuild toolset version that will be used in the absence
68     of a user override."""
69     return self.default_toolset
70
71   def SetupScript(self, target_arch):
72     """Returns a command (with arguments) to be used to set up the
73     environment."""
74     # Check if we are running in the SDK command line environment and use
75     # the setup script from the SDK if so. |target_arch| should be either
76     # 'x86' or 'x64'.
77     assert target_arch in ('x86', 'x64')
78     sdk_dir = os.environ.get('WindowsSDKDir')
79     if self.sdk_based and sdk_dir:
80       return [os.path.normpath(os.path.join(sdk_dir, 'Bin/SetEnv.Cmd')),
81               '/' + target_arch]
82     else:
83       # We don't use VC/vcvarsall.bat for x86 because vcvarsall calls
84       # vcvars32, which it can only find if VS??COMNTOOLS is set, which it
85       # isn't always.
86       if target_arch == 'x86':
87         if self.short_name == '2013' and (
88             os.environ.get('PROCESSOR_ARCHITECTURE') == 'AMD64' or
89             os.environ.get('PROCESSOR_ARCHITEW6432') == 'AMD64'):
90           # VS2013 non-Express has a x64-x86 cross that we want to prefer.
91           return [os.path.normpath(
92              os.path.join(self.path, 'VC/vcvarsall.bat')), 'amd64_x86']
93         # Otherwise, the standard x86 compiler.
94         return [os.path.normpath(
95           os.path.join(self.path, 'Common7/Tools/vsvars32.bat'))]
96       else:
97         assert target_arch == 'x64'
98         arg = 'x86_amd64'
99         if (os.environ.get('PROCESSOR_ARCHITECTURE') == 'AMD64' or
100             os.environ.get('PROCESSOR_ARCHITEW6432') == 'AMD64'):
101           # Use the 64-on-64 compiler if we can.
102           arg = 'amd64'
103         return [os.path.normpath(
104             os.path.join(self.path, 'VC/vcvarsall.bat')), arg]
105
106
107 def _RegistryQueryBase(sysdir, key, value):
108   """Use reg.exe to read a particular key.
109
110   While ideally we might use the win32 module, we would like gyp to be
111   python neutral, so for instance cygwin python lacks this module.
112
113   Arguments:
114     sysdir: The system subdirectory to attempt to launch reg.exe from.
115     key: The registry key to read from.
116     value: The particular value to read.
117   Return:
118     stdout from reg.exe, or None for failure.
119   """
120   # Skip if not on Windows or Python Win32 setup issue
121   if sys.platform not in ('win32', 'cygwin'):
122     return None
123   # Setup params to pass to and attempt to launch reg.exe
124   cmd = [os.path.join(os.environ.get('WINDIR', ''), sysdir, 'reg.exe'),
125          'query', key]
126   if value:
127     cmd.extend(['/v', value])
128   p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
129   # Obtain the stdout from reg.exe, reading to the end so p.returncode is valid
130   # Note that the error text may be in [1] in some cases
131   text = p.communicate()[0]
132   # Check return code from reg.exe; officially 0==success and 1==error
133   if p.returncode:
134     return None
135   return text
136
137
138 def _RegistryQuery(key, value=None):
139   """Use reg.exe to read a particular key through _RegistryQueryBase.
140
141   First tries to launch from %WinDir%\Sysnative to avoid WoW64 redirection. If
142   that fails, it falls back to System32.  Sysnative is available on Vista and
143   up and available on Windows Server 2003 and XP through KB patch 942589. Note
144   that Sysnative will always fail if using 64-bit python due to it being a
145   virtual directory and System32 will work correctly in the first place.
146
147   KB 942589 - http://support.microsoft.com/kb/942589/en-us.
148
149   Arguments:
150     key: The registry key.
151     value: The particular registry value to read (optional).
152   Return:
153     stdout from reg.exe, or None for failure.
154   """
155   text = None
156   try:
157     text = _RegistryQueryBase('Sysnative', key, value)
158   except OSError, e:
159     if e.errno == errno.ENOENT:
160       text = _RegistryQueryBase('System32', key, value)
161     else:
162       raise
163   return text
164
165
166 def _RegistryGetValue(key, value):
167   """Use reg.exe to obtain the value of a registry key.
168
169   Args:
170     key: The registry key.
171     value: The particular registry value to read.
172   Return:
173     contents of the registry key's value, or None on failure.
174   """
175   text = _RegistryQuery(key, value)
176   if not text:
177     return None
178   # Extract value.
179   match = re.search(r'REG_\w+\s+([^\r]+)\r\n', text)
180   if not match:
181     return None
182   return match.group(1)
183
184
185 def _RegistryKeyExists(key):
186   """Use reg.exe to see if a key exists.
187
188   Args:
189     key: The registry key to check.
190   Return:
191     True if the key exists
192   """
193   if not _RegistryQuery(key):
194     return False
195   return True
196
197
198 def _CreateVersion(name, path, sdk_based=False):
199   """Sets up MSVS project generation.
200
201   Setup is based off the GYP_MSVS_VERSION environment variable or whatever is
202   autodetected if GYP_MSVS_VERSION is not explicitly specified. If a version is
203   passed in that doesn't match a value in versions python will throw a error.
204   """
205   if path:
206     path = os.path.normpath(path)
207   versions = {
208       '2013': VisualStudioVersion('2013',
209                                   'Visual Studio 2013',
210                                   solution_version='13.00',
211                                   project_version='12.0',
212                                   flat_sln=False,
213                                   uses_vcxproj=True,
214                                   path=path,
215                                   sdk_based=sdk_based,
216                                   default_toolset='v120'),
217       '2013e': VisualStudioVersion('2013e',
218                                    'Visual Studio 2013',
219                                    solution_version='13.00',
220                                    project_version='12.0',
221                                    flat_sln=True,
222                                    uses_vcxproj=True,
223                                    path=path,
224                                    sdk_based=sdk_based,
225                                    default_toolset='v120'),
226       '2012': VisualStudioVersion('2012',
227                                   'Visual Studio 2012',
228                                   solution_version='12.00',
229                                   project_version='4.0',
230                                   flat_sln=False,
231                                   uses_vcxproj=True,
232                                   path=path,
233                                   sdk_based=sdk_based,
234                                   default_toolset='v110'),
235       '2012e': VisualStudioVersion('2012e',
236                                    'Visual Studio 2012',
237                                    solution_version='12.00',
238                                    project_version='4.0',
239                                    flat_sln=True,
240                                    uses_vcxproj=True,
241                                    path=path,
242                                    sdk_based=sdk_based,
243                                    default_toolset='v110'),
244       '2010': VisualStudioVersion('2010',
245                                   'Visual Studio 2010',
246                                   solution_version='11.00',
247                                   project_version='4.0',
248                                   flat_sln=False,
249                                   uses_vcxproj=True,
250                                   path=path,
251                                   sdk_based=sdk_based),
252       '2010e': VisualStudioVersion('2010e',
253                                    'Visual C++ Express 2010',
254                                    solution_version='11.00',
255                                    project_version='4.0',
256                                    flat_sln=True,
257                                    uses_vcxproj=True,
258                                    path=path,
259                                    sdk_based=sdk_based),
260       '2008': VisualStudioVersion('2008',
261                                   'Visual Studio 2008',
262                                   solution_version='10.00',
263                                   project_version='9.00',
264                                   flat_sln=False,
265                                   uses_vcxproj=False,
266                                   path=path,
267                                   sdk_based=sdk_based),
268       '2008e': VisualStudioVersion('2008e',
269                                    'Visual Studio 2008',
270                                    solution_version='10.00',
271                                    project_version='9.00',
272                                    flat_sln=True,
273                                    uses_vcxproj=False,
274                                    path=path,
275                                    sdk_based=sdk_based),
276       '2005': VisualStudioVersion('2005',
277                                   'Visual Studio 2005',
278                                   solution_version='9.00',
279                                   project_version='8.00',
280                                   flat_sln=False,
281                                   uses_vcxproj=False,
282                                   path=path,
283                                   sdk_based=sdk_based),
284       '2005e': VisualStudioVersion('2005e',
285                                    'Visual Studio 2005',
286                                    solution_version='9.00',
287                                    project_version='8.00',
288                                    flat_sln=True,
289                                    uses_vcxproj=False,
290                                    path=path,
291                                    sdk_based=sdk_based),
292   }
293   return versions[str(name)]
294
295
296 def _ConvertToCygpath(path):
297   """Convert to cygwin path if we are using cygwin."""
298   if sys.platform == 'cygwin':
299     p = subprocess.Popen(['cygpath', path], stdout=subprocess.PIPE)
300     path = p.communicate()[0].strip()
301   return path
302
303
304 def _DetectVisualStudioVersions(versions_to_check, force_express):
305   """Collect the list of installed visual studio versions.
306
307   Returns:
308     A list of visual studio versions installed in descending order of
309     usage preference.
310     Base this on the registry and a quick check if devenv.exe exists.
311     Only versions 8-10 are considered.
312     Possibilities are:
313       2005(e) - Visual Studio 2005 (8)
314       2008(e) - Visual Studio 2008 (9)
315       2010(e) - Visual Studio 2010 (10)
316       2012(e) - Visual Studio 2012 (11)
317       2013(e) - Visual Studio 2013 (11)
318     Where (e) is e for express editions of MSVS and blank otherwise.
319   """
320   version_to_year = {
321       '8.0': '2005',
322       '9.0': '2008',
323       '10.0': '2010',
324       '11.0': '2012',
325       '12.0': '2013',
326   }
327   versions = []
328   for version in versions_to_check:
329     # Old method of searching for which VS version is installed
330     # We don't use the 2010-encouraged-way because we also want to get the
331     # path to the binaries, which it doesn't offer.
332     keys = [r'HKLM\Software\Microsoft\VisualStudio\%s' % version,
333             r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\%s' % version,
334             r'HKLM\Software\Microsoft\VCExpress\%s' % version,
335             r'HKLM\Software\Wow6432Node\Microsoft\VCExpress\%s' % version]
336     for index in range(len(keys)):
337       path = _RegistryGetValue(keys[index], 'InstallDir')
338       if not path:
339         continue
340       path = _ConvertToCygpath(path)
341       # Check for full.
342       full_path = os.path.join(path, 'devenv.exe')
343       express_path = os.path.join(path, '*express.exe')
344       if not force_express and os.path.exists(full_path):
345         # Add this one.
346         versions.append(_CreateVersion(version_to_year[version],
347             os.path.join(path, '..', '..')))
348       # Check for express.
349       elif glob.glob(express_path):
350         # Add this one.
351         versions.append(_CreateVersion(version_to_year[version] + 'e',
352             os.path.join(path, '..', '..')))
353
354     # The old method above does not work when only SDK is installed.
355     keys = [r'HKLM\Software\Microsoft\VisualStudio\SxS\VC7',
356             r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\SxS\VC7']
357     for index in range(len(keys)):
358       path = _RegistryGetValue(keys[index], version)
359       if not path:
360         continue
361       path = _ConvertToCygpath(path)
362       versions.append(_CreateVersion(version_to_year[version] + 'e',
363           os.path.join(path, '..'), sdk_based=True))
364
365   return versions
366
367
368 def SelectVisualStudioVersion(version='auto'):
369   """Select which version of Visual Studio projects to generate.
370
371   Arguments:
372     version: Hook to allow caller to force a particular version (vs auto).
373   Returns:
374     An object representing a visual studio project format version.
375   """
376   # In auto mode, check environment variable for override.
377   if version == 'auto':
378     version = os.environ.get('GYP_MSVS_VERSION', 'auto')
379   version_map = {
380     'auto': ('10.0', '12.0', '9.0', '8.0', '11.0'),
381     '2005': ('8.0',),
382     '2005e': ('8.0',),
383     '2008': ('9.0',),
384     '2008e': ('9.0',),
385     '2010': ('10.0',),
386     '2010e': ('10.0',),
387     '2012': ('11.0',),
388     '2012e': ('11.0',),
389     '2013': ('12.0',),
390     '2013e': ('12.0',),
391   }
392   override_path = os.environ.get('GYP_MSVS_OVERRIDE_PATH')
393   if override_path:
394     msvs_version = os.environ.get('GYP_MSVS_VERSION')
395     if not msvs_version:
396       raise ValueError('GYP_MSVS_OVERRIDE_PATH requires GYP_MSVS_VERSION to be '
397                        'set to a particular version (e.g. 2010e).')
398     return _CreateVersion(msvs_version, override_path, sdk_based=True)
399   version = str(version)
400   versions = _DetectVisualStudioVersions(version_map[version], 'e' in version)
401   if not versions:
402     if version == 'auto':
403       # Default to 2005 if we couldn't find anything
404       return _CreateVersion('2005', None)
405     else:
406       return _CreateVersion(version, None)
407   return versions[0]