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.
50 get_installed_sdks = sdk.get_installed_sdks
53 class VisualCException(Exception):
56 class UnsupportedVersion(VisualCException):
59 class UnsupportedArch(VisualCException):
62 class MissingConfiguration(VisualCException):
65 class NoVersionFound(VisualCException):
68 class BatchFileExecutionError(VisualCException):
71 # Dict to 'canonalize' the arch
72 _ARCH_TO_CANONICAL = {
82 # Given a (host, target) tuple, return the argument for the bat file. Both host
83 # and targets should be canonalized.
84 _HOST_TARGET_ARCH_TO_BAT_ARCH = {
85 ("x86", "x86"): "x86",
86 ("x86", "amd64"): "x86_amd64",
87 ("amd64", "amd64"): "amd64",
88 ("amd64", "x86"): "x86",
89 ("x86", "ia64"): "x86_ia64"
92 def get_host_target(env):
93 host_platform = env.get('HOST_ARCH')
95 host_platform = platform.machine()
96 # TODO(2.5): the native Python platform.machine() function returns
97 # '' on all Python versions before 2.6, after which it also uses
98 # PROCESSOR_ARCHITECTURE.
100 host_platform = os.environ.get('PROCESSOR_ARCHITECTURE', '')
101 target_platform = env.get('TARGET_ARCH')
102 if not target_platform:
103 target_platform = host_platform
106 host = _ARCH_TO_CANONICAL[host_platform]
108 msg = "Unrecognized host architecture %s"
109 raise ValueError(msg % repr(host_platform))
112 target = _ARCH_TO_CANONICAL[target_platform]
114 raise ValueError("Unrecognized target architecture %s" % target_platform)
116 return (host, target)
118 _VCVER = ["10.0", "9.0", "8.0", "7.1", "7.0", "6.0"]
120 _VCVER_TO_PRODUCT_DIR = {
122 r'Microsoft\VisualStudio\10.0\Setup\VC\ProductDir'],
124 r'Microsoft\VisualStudio\9.0\Setup\VC\ProductDir',
125 r'Microsoft\VCExpress\9.0\Setup\VC\ProductDir'],
127 r'Microsoft\VisualStudio\8.0\Setup\VC\ProductDir',
128 r'Microsoft\VCExpress\8.0\Setup\VC\ProductDir'],
130 r'Microsoft\VisualStudio\7.1\Setup\VC\ProductDir'],
132 r'Microsoft\VisualStudio\7.0\Setup\VC\ProductDir'],
134 r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++\ProductDir']
137 def msvc_version_to_maj_min(msvc_version):
138 t = msvc_version.split(".")
140 raise ValueError("Unrecognized version %s" % msvc_version)
145 except ValueError, e:
146 raise ValueError("Unrecognized version %s" % msvc_version)
148 def is_host_target_supported(host_target, msvc_version):
149 """Return True if the given (host, target) tuple is supported given the
155 tuple of (canonalized) host-target, e.g. ("x86", "amd64") for cross
156 compilation from 32 bits windows to 64 bits.
158 msvc version (major.minor, e.g. 10.0)
162 This only check whether a given version *may* support the given (host,
163 target), not that the toolchain is actually present on the machine.
165 # We assume that any Visual Studio version supports x86 as a target
166 if host_target[1] != "x86":
167 maj, min = msvc_version_to_maj_min(msvc_version)
173 def find_vc_pdir(msvc_version):
174 """Try to find the product directory for the given
179 If for some reason the requested version could not be found, an
180 exception which inherits from VisualCException will be raised."""
182 if common.is_win64():
183 root = root + 'Wow6432Node\\'
185 hkeys = _VCVER_TO_PRODUCT_DIR[msvc_version]
187 debug("Unknown version of MSVC: %s" % msvc_version)
188 raise UnsupportedVersion("Unknown version %s" % msvc_version)
193 comps = common.read_reg(key)
194 except WindowsError, e:
195 debug('find_vc_dir(): no VC registry key %s' % repr(key))
197 debug('find_vc_dir(): found VC in registry: %s' % comps)
198 if os.path.exists(comps):
201 debug('find_vc_dir(): reg says dir is %s, but it does not exist. (ignoring)'\
203 raise MissingConfiguration("registry dir %s not found on the filesystem" % comps)
206 def find_batch_file(env,msvc_version):
208 Find the location of the batch script which should set up the compiler
209 for any TARGET_ARCH whose compilers were installed by Visual Studio/VCExpress
211 pdir = find_vc_pdir(msvc_version)
213 raise NoVersionFound("No version of Visual Studio found")
215 vernum = float(msvc_version)
217 pdir = os.path.join(pdir, os.pardir, "Common7", "Tools")
218 batfilename = os.path.join(pdir, "vsvars32.bat")
220 pdir = os.path.join(pdir, "Bin")
221 batfilename = os.path.join(pdir, "vcvars32.bat")
223 batfilename = os.path.join(pdir, "vcvarsall.bat")
225 if not os.path.exists(batfilename):
226 debug("Not found: %s" % batfilename)
229 installed_sdks=get_installed_sdks()
230 (host_arch,target_arch)=get_host_target(env)
231 for _sdk in installed_sdks:
232 #print "Trying :%s"%_sdk.vc_setup_scripts
233 sdk_bat_file=_sdk.get_sdk_vc_script(host_arch,target_arch)
234 sdk_bat_file_path=os.path.join(pdir,sdk_bat_file)
235 #print "PATH: %s"%sdk_bat_file_path
236 if os.path.exists(sdk_bat_file_path):
237 return (batfilename,sdk_bat_file_path)
239 return (batfilename,None)
241 __INSTALLED_VCS_RUN = None
243 def cached_get_installed_vcs():
244 global __INSTALLED_VCS_RUN
246 if __INSTALLED_VCS_RUN is None:
247 ret = get_installed_vcs()
248 __INSTALLED_VCS_RUN = ret
250 return __INSTALLED_VCS_RUN
252 def get_installed_vcs():
253 installed_versions = []
255 debug('trying to find VC %s' % ver)
257 if find_vc_pdir(ver):
258 debug('found VC %s' % ver)
259 installed_versions.append(ver)
261 debug('find_vc_pdir return None for ver %s' % ver)
262 except VisualCException, e:
263 debug('did not find VC %s: caught exception %s' % (ver, str(e)))
264 return installed_versions
266 def reset_installed_vcs():
267 """Make it try again to find VC. This is just for the tests."""
268 __INSTALLED_VCS_RUN = None
270 def script_env(script, args=None):
271 stdout = common.get_output(script, args)
272 # Stupid batch files do not set return code: we take a look at the
273 # beginning of the output for an error message instead
274 olines = stdout.splitlines()
275 if olines[0].startswith("The specified configuration type is missing"):
276 raise BatchFileExecutionError("\n".join(olines[:2]))
278 return common.parse_output(stdout)
280 def get_default_version(env):
281 debug('get_default_version()')
283 msvc_version = env.get('MSVC_VERSION')
284 msvs_version = env.get('MSVS_VERSION')
286 if msvs_version and not msvc_version:
288 SCons.Warnings.DeprecatedWarning,
289 "MSVS_VERSION is deprecated: please use MSVC_VERSION instead ")
291 elif msvc_version and msvs_version:
292 if not msvc_version == msvs_version:
294 SCons.Warnings.VisualVersionMismatch,
295 "Requested msvc version (%s) and msvs version (%s) do " \
296 "not match: please use MSVC_VERSION only to request a " \
297 "visual studio version, MSVS_VERSION is deprecated" \
298 % (msvc_version, msvs_version))
301 installed_vcs = cached_get_installed_vcs()
302 debug('installed_vcs:%s' % installed_vcs)
303 if not installed_vcs:
304 msg = 'No installed VCs'
305 debug('msv %s\n' % repr(msg))
306 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
308 msvc_version = installed_vcs[0]
309 debug('msvc_setup_env: using default installed MSVC version %s\n' % repr(msvc_version))
313 def msvc_setup_env_once(env):
315 has_run = env["MSVC_SETUP_RUN"]
321 env["MSVC_SETUP_RUN"] = True
323 def msvc_setup_env(env):
324 debug('msvc_setup_env()')
326 version = get_default_version(env)
328 warn_msg = "No version of Visual Studio compiler found - C/C++ " \
329 "compilers most likely not set correctly"
330 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
332 debug('msvc_setup_env: using specified MSVC version %s\n' % repr(version))
334 # XXX: we set-up both MSVS version for backward
335 # compatibility with the msvs tool
336 env['MSVC_VERSION'] = version
337 env['MSVS_VERSION'] = version
341 (vc_script,sdk_script) = find_batch_file(env,version)
342 except VisualCException, e:
344 debug('Caught exception while looking for batch file (%s)' % msg)
345 warn_msg = "VC version %s not installed. " + \
346 "C/C++ compilers are most likely not set correctly.\n" + \
347 " Installed versions are: %s"
348 warn_msg = warn_msg % (version, cached_get_installed_vcs())
349 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
352 use_script = env.get('MSVC_USE_SCRIPT', True)
353 if SCons.Util.is_String(use_script):
354 debug('use_script 1 %s\n' % repr(use_script))
355 d = script_env(use_script)
357 host_platform, target_platform = get_host_target(env)
358 host_target = (host_platform, target_platform)
359 if not is_host_target_supported(host_target, version):
360 warn_msg = "host, target = %s not supported for MSVC version %s" % \
361 (host_target, version)
362 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
363 arg = _HOST_TARGET_ARCH_TO_BAT_ARCH[host_target]
364 debug('use_script 2 %s, args:%s\n' % (repr(vc_script), arg))
367 d = script_env(vc_script, args=arg)
368 except BatchFileExecutionError, e:
369 debug('use_script 3: failed running VC script %s: %s: Error:%s'%(repr(vc_script),arg,e))
371 if not vc_script and sdk_script:
372 debug('use_script 4: trying sdk script: %s %s'%(sdk_script,arg))
374 d = script_env(sdk_script,args=[])
375 except BatchFileExecutionError,e:
376 debug('use_script 5: failed running SDK script %s: Error:%s'%(repr(sdk_script),e))
378 elif not vc_script and not sdk_script:
379 debug('use_script 6: Neither VC script nor SDK script found')
383 debug('MSVC_USE_SCRIPT set to False')
384 warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \
386 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
389 for k, v in d.items():
390 env.PrependENVPath(k, v, delete_existing=True)
392 def msvc_exists(version=None):
393 vcs = cached_get_installed_vcs()
396 return version in vcs