4 # Permission is hereby granted, free of charge, to any person obtaining
5 # a copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish,
8 # distribute, sublicense, and/or sell copies of the Software, and to
9 # permit persons to whom the Software is furnished to do so, subject to
10 # the following conditions:
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
16 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 # * supported arch for versions: for old versions of batch file without
26 # argument, giving bogus argument cannot be detected, so we have to hardcode
28 # * print warning when msvc version specified but not found
29 # * find out why warning do not print
30 # * test on 64 bits XP + VS 2005 (and VS 6 if possible)
33 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
35 __doc__ = """Module for Visual C/C++ detection and configuration.
41 from string import digits as string_digits
51 get_installed_sdks = sdk.get_installed_sdks
54 class VisualCException(Exception):
57 class UnsupportedVersion(VisualCException):
60 class UnsupportedArch(VisualCException):
63 class MissingConfiguration(VisualCException):
66 class NoVersionFound(VisualCException):
69 class BatchFileExecutionError(VisualCException):
72 # Dict to 'canonalize' the arch
73 _ARCH_TO_CANONICAL = {
83 # Given a (host, target) tuple, return the argument for the bat file. Both host
84 # and targets should be canonalized.
85 _HOST_TARGET_ARCH_TO_BAT_ARCH = {
86 ("x86", "x86"): "x86",
87 ("x86", "amd64"): "x86_amd64",
88 ("amd64", "amd64"): "amd64",
89 ("amd64", "x86"): "x86",
90 ("x86", "ia64"): "x86_ia64"
93 def get_host_target(env):
94 host_platform = env.get('HOST_ARCH')
96 host_platform = platform.machine()
97 # TODO(2.5): the native Python platform.machine() function returns
98 # '' on all Python versions before 2.6, after which it also uses
99 # PROCESSOR_ARCHITECTURE.
100 if not host_platform:
101 host_platform = os.environ.get('PROCESSOR_ARCHITECTURE', '')
102 target_platform = env.get('TARGET_ARCH')
103 if not target_platform:
104 target_platform = host_platform
107 host = _ARCH_TO_CANONICAL[host_platform]
109 msg = "Unrecognized host architecture %s"
110 raise ValueError(msg % repr(host_platform))
113 target = _ARCH_TO_CANONICAL[target_platform]
115 raise ValueError("Unrecognized target architecture %s" % target_platform)
117 return (host, target)
119 _VCVER = ["10.0", "9.0", "9.0Exp","8.0", "8.0Exp","7.1", "7.0", "6.0"]
121 _VCVER_TO_PRODUCT_DIR = {
123 r'Microsoft\VisualStudio\10.0\Setup\VC\ProductDir'],
125 r'Microsoft\VisualStudio\9.0\Setup\VC\ProductDir'],
127 r'Microsoft\VCExpress\9.0\Setup\VC\ProductDir'],
129 r'Microsoft\VisualStudio\8.0\Setup\VC\ProductDir'],
131 r'Microsoft\VCExpress\8.0\Setup\VC\ProductDir'],
133 r'Microsoft\VisualStudio\7.1\Setup\VC\ProductDir'],
135 r'Microsoft\VisualStudio\7.0\Setup\VC\ProductDir'],
137 r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++\ProductDir']
140 def msvc_version_to_maj_min(msvc_version):
141 t = msvc_version.split(".")
143 raise ValueError("Unrecognized version %s" % msvc_version)
148 except ValueError, e:
149 raise ValueError("Unrecognized version %s" % msvc_version)
151 def is_host_target_supported(host_target, msvc_version):
152 """Return True if the given (host, target) tuple is supported given the
158 tuple of (canonalized) host-target, e.g. ("x86", "amd64") for cross
159 compilation from 32 bits windows to 64 bits.
161 msvc version (major.minor, e.g. 10.0)
165 This only check whether a given version *may* support the given (host,
166 target), not that the toolchain is actually present on the machine.
168 # We assume that any Visual Studio version supports x86 as a target
169 if host_target[1] != "x86":
170 maj, min = msvc_version_to_maj_min(msvc_version)
176 def find_vc_pdir(msvc_version):
177 """Try to find the product directory for the given
182 If for some reason the requested version could not be found, an
183 exception which inherits from VisualCException will be raised."""
185 if common.is_win64():
186 root = root + 'Wow6432Node\\'
188 hkeys = _VCVER_TO_PRODUCT_DIR[msvc_version]
190 debug("Unknown version of MSVC: %s" % msvc_version)
191 raise UnsupportedVersion("Unknown version %s" % msvc_version)
196 comps = common.read_reg(key)
197 except WindowsError, e:
198 debug('find_vc_dir(): no VC registry key %s' % repr(key))
200 debug('find_vc_dir(): found VC in registry: %s' % comps)
201 if os.path.exists(comps):
204 debug('find_vc_dir(): reg says dir is %s, but it does not exist. (ignoring)'\
206 raise MissingConfiguration("registry dir %s not found on the filesystem" % comps)
209 def find_batch_file(env,msvc_version):
211 Find the location of the batch script which should set up the compiler
212 for any TARGET_ARCH whose compilers were installed by Visual Studio/VCExpress
214 pdir = find_vc_pdir(msvc_version)
216 raise NoVersionFound("No version of Visual Studio found")
218 debug('vc.py: find_batch_file() pdir:%s'%pdir)
220 # filter out e.g. "Exp" from the version name
221 msvc_ver_numeric = ''.join([x for x in msvc_version if x in string_digits + "."])
222 vernum = float(msvc_ver_numeric)
224 pdir = os.path.join(pdir, os.pardir, "Common7", "Tools")
225 batfilename = os.path.join(pdir, "vsvars32.bat")
227 pdir = os.path.join(pdir, "Bin")
228 batfilename = os.path.join(pdir, "vcvars32.bat")
230 batfilename = os.path.join(pdir, "vcvarsall.bat")
232 if not os.path.exists(batfilename):
233 debug("Not found: %s" % batfilename)
236 installed_sdks=get_installed_sdks()
237 (host_arch,target_arch)=get_host_target(env)
238 for _sdk in installed_sdks:
239 sdk_bat_file=_sdk.get_sdk_vc_script(host_arch,target_arch)
240 sdk_bat_file_path=os.path.join(pdir,sdk_bat_file)
241 debug('vc.py:find_batch_file() sdk_bat_file_path:%s'%sdk_bat_file_path)
242 if os.path.exists(sdk_bat_file_path):
243 return (batfilename,sdk_bat_file_path)
245 debug("vc.py:find_batch_file() not found:%s"%sdk_bat_file_path)
247 return (batfilename,None)
249 __INSTALLED_VCS_RUN = None
251 def cached_get_installed_vcs():
252 global __INSTALLED_VCS_RUN
254 if __INSTALLED_VCS_RUN is None:
255 ret = get_installed_vcs()
256 __INSTALLED_VCS_RUN = ret
258 return __INSTALLED_VCS_RUN
260 def get_installed_vcs():
261 installed_versions = []
263 debug('trying to find VC %s' % ver)
265 if find_vc_pdir(ver):
266 debug('found VC %s' % ver)
267 installed_versions.append(ver)
269 debug('find_vc_pdir return None for ver %s' % ver)
270 except VisualCException, e:
271 debug('did not find VC %s: caught exception %s' % (ver, str(e)))
272 return installed_versions
274 def reset_installed_vcs():
275 """Make it try again to find VC. This is just for the tests."""
276 __INSTALLED_VCS_RUN = None
278 def script_env(script, args=None):
279 stdout = common.get_output(script, args)
280 # Stupid batch files do not set return code: we take a look at the
281 # beginning of the output for an error message instead
282 olines = stdout.splitlines()
283 if olines[0].startswith("The specified configuration type is missing"):
284 raise BatchFileExecutionError("\n".join(olines[:2]))
286 return common.parse_output(stdout)
288 def get_default_version(env):
289 debug('get_default_version()')
291 msvc_version = env.get('MSVC_VERSION')
292 msvs_version = env.get('MSVS_VERSION')
294 debug('get_default_version(): msvc_version:%s msvs_version:%s'%(msvc_version,msvs_version))
296 if msvs_version and not msvc_version:
298 SCons.Warnings.DeprecatedWarning,
299 "MSVS_VERSION is deprecated: please use MSVC_VERSION instead ")
301 elif msvc_version and msvs_version:
302 if not msvc_version == msvs_version:
304 SCons.Warnings.VisualVersionMismatch,
305 "Requested msvc version (%s) and msvs version (%s) do " \
306 "not match: please use MSVC_VERSION only to request a " \
307 "visual studio version, MSVS_VERSION is deprecated" \
308 % (msvc_version, msvs_version))
311 installed_vcs = cached_get_installed_vcs()
312 debug('installed_vcs:%s' % installed_vcs)
313 if not installed_vcs:
314 msg = 'No installed VCs'
315 debug('msv %s\n' % repr(msg))
316 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
318 msvc_version = installed_vcs[0]
319 debug('msvc_setup_env: using default installed MSVC version %s\n' % repr(msvc_version))
323 def msvc_setup_env_once(env):
325 has_run = env["MSVC_SETUP_RUN"]
331 env["MSVC_SETUP_RUN"] = True
333 def msvc_setup_env(env):
334 debug('msvc_setup_env()')
336 version = get_default_version(env)
338 warn_msg = "No version of Visual Studio compiler found - C/C++ " \
339 "compilers most likely not set correctly"
340 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
342 debug('msvc_setup_env: using specified MSVC version %s\n' % repr(version))
344 # XXX: we set-up both MSVS version for backward
345 # compatibility with the msvs tool
346 env['MSVC_VERSION'] = version
347 env['MSVS_VERSION'] = version
351 (vc_script,sdk_script) = find_batch_file(env,version)
352 debug('vc.py:msvc_setup_env() vc_script:%s sdk_script:%s'%(vc_script,sdk_script))
353 except VisualCException, e:
355 debug('Caught exception while looking for batch file (%s)' % msg)
356 warn_msg = "VC version %s not installed. " + \
357 "C/C++ compilers are most likely not set correctly.\n" + \
358 " Installed versions are: %s"
359 warn_msg = warn_msg % (version, cached_get_installed_vcs())
360 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
363 debug('vc.py:msvc_setup_env() vc_script:%s sdk_script:%s'%(vc_script,sdk_script))
364 use_script = env.get('MSVC_USE_SCRIPT', True)
365 if SCons.Util.is_String(use_script):
366 debug('use_script 1 %s\n' % repr(use_script))
367 d = script_env(use_script)
369 host_platform, target_platform = get_host_target(env)
370 host_target = (host_platform, target_platform)
371 if not is_host_target_supported(host_target, version):
372 warn_msg = "host, target = %s not supported for MSVC version %s" % \
373 (host_target, version)
374 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
375 arg = _HOST_TARGET_ARCH_TO_BAT_ARCH[host_target]
376 debug('use_script 2 %s, args:%s\n' % (repr(vc_script), arg))
379 d = script_env(vc_script, args=arg)
380 except BatchFileExecutionError, e:
381 debug('use_script 3: failed running VC script %s: %s: Error:%s'%(repr(vc_script),arg,e))
383 if not vc_script and sdk_script:
384 debug('use_script 4: trying sdk script: %s'%(sdk_script))
386 d = script_env(sdk_script,args=[])
387 except BatchFileExecutionError,e:
388 debug('use_script 5: failed running SDK script %s: Error:%s'%(repr(sdk_script),e))
390 elif not vc_script and not sdk_script:
391 debug('use_script 6: Neither VC script nor SDK script found')
395 debug('MSVC_USE_SCRIPT set to False')
396 warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \
398 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
401 for k, v in d.items():
402 debug('vc.py:msvc_setup_env() env:%s -> %s'%(k,v))
403 env.PrependENVPath(k, v, delete_existing=True)
405 def msvc_exists(version=None):
406 vcs = cached_get_installed_vcs()
409 return version in vcs