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.
48 class VisualCException(Exception):
51 class UnsupportedVersion(VisualCException):
54 class UnsupportedArch(VisualCException):
57 class MissingConfiguration(VisualCException):
60 class NoVersionFound(VisualCException):
63 class BatchFileExecutionError(VisualCException):
66 # Dict to 'canonalize' the arch
67 _ARCH_TO_CANONICAL = {
77 # Given a (host, target) tuple, return the argument for the bat file. Both host
78 # and targets should be canonalized.
79 _HOST_TARGET_ARCH_TO_BAT_ARCH = {
80 ("x86", "x86"): "x86",
81 ("x86", "amd64"): "x86_amd64",
82 ("amd64", "amd64"): "amd64",
83 ("amd64", "x86"): "x86",
84 ("x86", "ia64"): "x86_ia64"
87 def get_host_target(env):
88 host_platform = env.get('HOST_ARCH')
90 host_platform = platform.machine()
91 # TODO(2.5): the native Python platform.machine() function returns
92 # '' on all Python versions before 2.6, after which it also uses
93 # PROCESSOR_ARCHITECTURE.
95 host_platform = os.environ.get('PROCESSOR_ARCHITECTURE', '')
96 target_platform = env.get('TARGET_ARCH')
97 if not target_platform:
98 target_platform = host_platform
101 host = _ARCH_TO_CANONICAL[host_platform]
103 msg = "Unrecognized host architecture %s"
104 raise ValueError(msg % repr(host_platform))
107 target = _ARCH_TO_CANONICAL[target_platform]
109 raise ValueError("Unrecognized target architecture %s" % target_platform)
111 return (host, target)
113 _VCVER = ["10.0", "9.0", "8.0", "7.1", "7.0", "6.0"]
115 _VCVER_TO_PRODUCT_DIR = {
117 r'Microsoft\VisualStudio\10.0\Setup\VC\ProductDir'],
119 r'Microsoft\VisualStudio\9.0\Setup\VC\ProductDir',
120 r'Microsoft\VCExpress\9.0\Setup\VC\ProductDir'],
122 r'Microsoft\VisualStudio\8.0\Setup\VC\ProductDir',
123 r'Microsoft\VCExpress\8.0\Setup\VC\ProductDir'],
125 r'Microsoft\VisualStudio\7.1\Setup\VC\ProductDir'],
127 r'Microsoft\VisualStudio\7.0\Setup\VC\ProductDir'],
129 r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++\ProductDir']
132 def msvc_version_to_maj_min(msvc_version):
133 t = msvc_version.split(".")
135 raise ValueError("Unrecognized version %s" % msvc_version)
140 except ValueError, e:
141 raise ValueError("Unrecognized version %s" % msvc_version)
143 def is_host_target_supported(host_target, msvc_version):
144 """Return True if the given (host, target) tuple is supported given the
150 tuple of (canonalized) host-target, e.g. ("x86", "amd64") for cross
151 compilation from 32 bits windows to 64 bits.
153 msvc version (major.minor, e.g. 10.0)
157 This only check whether a given version *may* support the given (host,
158 target), not that the toolchain is actually present on the machine.
160 # We assume that any Visual Studio version supports x86 as a target
161 if host_target[1] != "x86":
162 maj, min = msvc_version_to_maj_min(msvc_version)
168 def find_vc_pdir(msvc_version):
169 """Try to find the product directory for the given
174 If for some reason the requested version could not be found, an
175 exception which inherits from VisualCException will be raised."""
177 if common.is_win64():
178 root = root + 'Wow6432Node\\'
180 hkeys = _VCVER_TO_PRODUCT_DIR[msvc_version]
182 debug("Unknown version of MSVC: %s" % msvc_version)
183 raise UnsupportedVersion("Unknown version %s" % msvc_version)
188 comps = common.read_reg(key)
189 except WindowsError, e:
190 debug('find_vc_dir(): no VC registry key %s' % repr(key))
192 debug('find_vc_dir(): found VC in registry: %s' % comps)
193 if os.path.exists(comps):
196 debug('find_vc_dir(): reg says dir is %s, but it does not exist. (ignoring)'\
198 raise MissingConfiguration("registry dir %s not found on the filesystem" % comps)
201 def find_batch_file(msvc_version):
202 pdir = find_vc_pdir(msvc_version)
204 raise NoVersionFound("No version of Visual Studio found")
206 vernum = float(msvc_version)
208 pdir = os.path.join(pdir, os.pardir, "Common7", "Tools")
209 batfilename = os.path.join(pdir, "vsvars32.bat")
211 pdir = os.path.join(pdir, "Bin")
212 batfilename = os.path.join(pdir, "vcvars32.bat")
214 batfilename = os.path.join(pdir, "vcvarsall.bat")
216 if os.path.exists(batfilename):
219 debug("Not found: %s" % batfilename)
222 __INSTALLED_VCS_RUN = None
224 def cached_get_installed_vcs():
225 global __INSTALLED_VCS_RUN
227 if __INSTALLED_VCS_RUN is None:
228 ret = get_installed_vcs()
229 __INSTALLED_VCS_RUN = ret
231 return __INSTALLED_VCS_RUN
233 def get_installed_vcs():
234 installed_versions = []
236 debug('trying to find VC %s' % ver)
238 if find_vc_pdir(ver):
239 debug('found VC %s' % ver)
240 installed_versions.append(ver)
242 debug('find_vc_pdir return None for ver %s' % ver)
243 except VisualCException, e:
244 debug('did not find VC %s: caught exception %s' % (ver, str(e)))
245 return installed_versions
247 def reset_installed_vcs():
248 """Make it try again to find VC. This is just for the tests."""
249 __INSTALLED_VCS_RUN = None
251 def script_env(script, args=None):
252 stdout = common.get_output(script, args)
253 # Stupid batch files do not set return code: we take a look at the
254 # beginning of the output for an error message instead
255 olines = stdout.splitlines()
256 if olines[0].startswith("The specified configuration type is missing"):
257 raise BatchFileExecutionError("\n".join(olines[:2]))
259 return common.parse_output(stdout)
261 def get_default_version(env):
262 debug('get_default_version()')
264 msvc_version = env.get('MSVC_VERSION')
265 msvs_version = env.get('MSVS_VERSION')
267 if msvs_version and not msvc_version:
269 SCons.Warnings.DeprecatedWarning,
270 "MSVS_VERSION is deprecated: please use MSVC_VERSION instead ")
272 elif msvc_version and msvs_version:
273 if not msvc_version == msvs_version:
275 SCons.Warnings.VisualVersionMismatch,
276 "Requested msvc version (%s) and msvs version (%s) do " \
277 "not match: please use MSVC_VERSION only to request a " \
278 "visual studio version, MSVS_VERSION is deprecated" \
279 % (msvc_version, msvs_version))
282 installed_vcs = cached_get_installed_vcs()
283 debug('installed_vcs:%s' % installed_vcs)
284 if not installed_vcs:
285 msg = 'No installed VCs'
286 debug('msv %s\n' % repr(msg))
287 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
289 msvc_version = installed_vcs[0]
290 debug('msvc_setup_env: using default installed MSVC version %s\n' % repr(msvc_version))
294 def msvc_setup_env_once(env):
296 has_run = env["MSVC_SETUP_RUN"]
302 env["MSVC_SETUP_RUN"] = True
304 def msvc_setup_env(env):
305 debug('msvc_setup_env()')
307 version = get_default_version(env)
309 warn_msg = "No version of Visual Studio compiler found - C/C++ " \
310 "compilers most likely not set correctly"
311 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
313 debug('msvc_setup_env: using specified MSVC version %s\n' % repr(version))
315 # XXX: we set-up both MSVS version for backward
316 # compatibility with the msvs tool
317 env['MSVC_VERSION'] = version
318 env['MSVS_VERSION'] = version
322 script = find_batch_file(version)
323 except VisualCException, e:
325 debug('Caught exception while looking for batch file (%s)' % msg)
326 warn_msg = "VC version %s not installed. " + \
327 "C/C++ compilers are most likely not set correctly.\n" + \
328 " Installed versions are: %s"
329 warn_msg = warn_msg % (version, cached_get_installed_vcs())
330 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
333 use_script = env.get('MSVC_USE_SCRIPT', True)
334 if SCons.Util.is_String(use_script):
335 debug('use_script 1 %s\n' % repr(use_script))
336 d = script_env(use_script)
338 host_platform, target_platform = get_host_target(env)
339 host_target = (host_platform, target_platform)
340 if not is_host_target_supported(host_target, version):
341 warn_msg = "host, target = %s not supported for MSVC version %s" % \
342 (host_target, version)
343 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
344 arg = _HOST_TARGET_ARCH_TO_BAT_ARCH[host_target]
345 debug('use_script 2 %s, args:%s\n' % (repr(script), arg))
347 d = script_env(script, args=arg)
348 except BatchFileExecutionError, e:
349 msg = "MSVC error while executing %s with args %s (error was %s)" % \
350 (script, arg, str(e))
351 raise SCons.Errors.UserError(msg)
353 debug('MSVC_USE_SCRIPT set to False')
354 warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \
356 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
359 for k, v in d.items():
360 env.PrependENVPath(k, v, delete_existing=True)
362 def msvc_exists(version=None):
363 vcs = cached_get_installed_vcs()
366 return version in vcs