2
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 The SCons Foundation
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__ = "src/engine/SCons/Tool/MSCommon/vc.py 2013/03/03 09:48:35 garyo"
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 = {
86
# Given a (host, target) tuple, return the argument for the bat file. Both host
87
# and targets should be canonalized.
88
_HOST_TARGET_ARCH_TO_BAT_ARCH = {
89
("x86", "x86"): "x86",
90
("x86", "amd64"): "x86_amd64",
91
("amd64", "amd64"): "amd64",
92
("amd64", "x86"): "x86",
93
("x86", "ia64"): "x86_ia64"
96
def get_host_target(env):
97
debug('vc.py:get_host_target()')
99
host_platform = env.get('HOST_ARCH')
100
if not host_platform:
101
host_platform = platform.machine()
102
# TODO(2.5): the native Python platform.machine() function returns
103
# '' on all Python versions before 2.6, after which it also uses
104
# PROCESSOR_ARCHITECTURE.
105
if not host_platform:
106
host_platform = os.environ.get('PROCESSOR_ARCHITECTURE', '')
108
# Retain user requested TARGET_ARCH
109
req_target_platform = env.get('TARGET_ARCH')
110
debug('vc.py:get_host_target() req_target_platform:%s'%req_target_platform)
112
if req_target_platform:
113
# If user requested a specific platform then only try that one.
114
target_platform = req_target_platform
116
target_platform = host_platform
119
host = _ARCH_TO_CANONICAL[host_platform.lower()]
121
msg = "Unrecognized host architecture %s"
122
raise ValueError(msg % repr(host_platform))
125
target = _ARCH_TO_CANONICAL[target_platform.lower()]
127
all_archs = str(_ARCH_TO_CANONICAL.keys())
128
raise ValueError("Unrecognized target architecture %s\n\tValid architectures: %s" % (target_platform, all_archs))
130
return (host, target,req_target_platform)
132
_VCVER = ["11.0", "11.0Exp", "10.0", "10.0Exp", "9.0", "9.0Exp","8.0", "8.0Exp","7.1", "7.0", "6.0"]
134
_VCVER_TO_PRODUCT_DIR = {
136
r'Microsoft\VisualStudio\11.0\Setup\VC\ProductDir'],
138
r'Microsoft\VCExpress\11.0\Setup\VC\ProductDir'],
140
r'Microsoft\VisualStudio\10.0\Setup\VC\ProductDir'],
142
r'Microsoft\VCExpress\10.0\Setup\VC\ProductDir'],
144
r'Microsoft\VisualStudio\9.0\Setup\VC\ProductDir'],
146
r'Microsoft\VCExpress\9.0\Setup\VC\ProductDir'],
148
r'Microsoft\VisualStudio\8.0\Setup\VC\ProductDir'],
150
r'Microsoft\VCExpress\8.0\Setup\VC\ProductDir'],
152
r'Microsoft\VisualStudio\7.1\Setup\VC\ProductDir'],
154
r'Microsoft\VisualStudio\7.0\Setup\VC\ProductDir'],
156
r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++\ProductDir']
159
def msvc_version_to_maj_min(msvc_version):
160
msvc_version_numeric = ''.join([x for x in msvc_version if x in string_digits + '.'])
162
t = msvc_version_numeric.split(".")
164
raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric))
169
except ValueError, e:
170
raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric))
172
def is_host_target_supported(host_target, msvc_version):
173
"""Return True if the given (host, target) tuple is supported given the
179
tuple of (canonalized) host-target, e.g. ("x86", "amd64") for cross
180
compilation from 32 bits windows to 64 bits.
182
msvc version (major.minor, e.g. 10.0)
186
This only check whether a given version *may* support the given (host,
187
target), not that the toolchain is actually present on the machine.
189
# We assume that any Visual Studio version supports x86 as a target
190
if host_target[1] != "x86":
191
maj, min = msvc_version_to_maj_min(msvc_version)
197
def find_vc_pdir(msvc_version):
198
"""Try to find the product directory for the given
203
If for some reason the requested version could not be found, an
204
exception which inherits from VisualCException will be raised."""
206
if common.is_win64():
207
root = root + 'Wow6432Node\\'
209
hkeys = _VCVER_TO_PRODUCT_DIR[msvc_version]
211
debug("Unknown version of MSVC: %s" % msvc_version)
212
raise UnsupportedVersion("Unknown version %s" % msvc_version)
217
comps = common.read_reg(key)
218
except WindowsError, e:
219
debug('find_vc_dir(): no VC registry key %s' % repr(key))
221
debug('find_vc_dir(): found VC in registry: %s' % comps)
222
if os.path.exists(comps):
225
debug('find_vc_dir(): reg says dir is %s, but it does not exist. (ignoring)'\
227
raise MissingConfiguration("registry dir %s not found on the filesystem" % comps)
230
def find_batch_file(env,msvc_version,host_arch,target_arch):
232
Find the location of the batch script which should set up the compiler
233
for any TARGET_ARCH whose compilers were installed by Visual Studio/VCExpress
235
pdir = find_vc_pdir(msvc_version)
237
raise NoVersionFound("No version of Visual Studio found")
239
debug('vc.py: find_batch_file() pdir:%s'%pdir)
241
# filter out e.g. "Exp" from the version name
242
msvc_ver_numeric = ''.join([x for x in msvc_version if x in string_digits + "."])
243
vernum = float(msvc_ver_numeric)
245
pdir = os.path.join(pdir, os.pardir, "Common7", "Tools")
246
batfilename = os.path.join(pdir, "vsvars32.bat")
248
pdir = os.path.join(pdir, "Bin")
249
batfilename = os.path.join(pdir, "vcvars32.bat")
251
batfilename = os.path.join(pdir, "vcvarsall.bat")
253
if not os.path.exists(batfilename):
254
debug("Not found: %s" % batfilename)
257
installed_sdks=get_installed_sdks()
258
for _sdk in installed_sdks:
259
sdk_bat_file=_sdk.get_sdk_vc_script(host_arch,target_arch)
260
sdk_bat_file_path=os.path.join(pdir,sdk_bat_file)
261
debug('vc.py:find_batch_file() sdk_bat_file_path:%s'%sdk_bat_file_path)
262
if os.path.exists(sdk_bat_file_path):
263
return (batfilename,sdk_bat_file_path)
265
debug("vc.py:find_batch_file() not found:%s"%sdk_bat_file_path)
267
return (batfilename,None)
269
__INSTALLED_VCS_RUN = None
271
def cached_get_installed_vcs():
272
global __INSTALLED_VCS_RUN
274
if __INSTALLED_VCS_RUN is None:
275
ret = get_installed_vcs()
276
__INSTALLED_VCS_RUN = ret
278
return __INSTALLED_VCS_RUN
280
def get_installed_vcs():
281
installed_versions = []
283
debug('trying to find VC %s' % ver)
285
if find_vc_pdir(ver):
286
debug('found VC %s' % ver)
287
installed_versions.append(ver)
289
debug('find_vc_pdir return None for ver %s' % ver)
290
except VisualCException, e:
291
debug('did not find VC %s: caught exception %s' % (ver, str(e)))
292
return installed_versions
294
def reset_installed_vcs():
295
"""Make it try again to find VC. This is just for the tests."""
296
__INSTALLED_VCS_RUN = None
298
def script_env(script, args=None):
299
stdout = common.get_output(script, args)
300
# Stupid batch files do not set return code: we take a look at the
301
# beginning of the output for an error message instead
302
olines = stdout.splitlines()
303
if olines[0].startswith("The specified configuration type is missing"):
304
raise BatchFileExecutionError("\n".join(olines[:2]))
306
return common.parse_output(stdout)
308
def get_default_version(env):
309
debug('get_default_version()')
311
msvc_version = env.get('MSVC_VERSION')
312
msvs_version = env.get('MSVS_VERSION')
314
debug('get_default_version(): msvc_version:%s msvs_version:%s'%(msvc_version,msvs_version))
316
if msvs_version and not msvc_version:
318
SCons.Warnings.DeprecatedWarning,
319
"MSVS_VERSION is deprecated: please use MSVC_VERSION instead ")
321
elif msvc_version and msvs_version:
322
if not msvc_version == msvs_version:
324
SCons.Warnings.VisualVersionMismatch,
325
"Requested msvc version (%s) and msvs version (%s) do " \
326
"not match: please use MSVC_VERSION only to request a " \
327
"visual studio version, MSVS_VERSION is deprecated" \
328
% (msvc_version, msvs_version))
331
installed_vcs = cached_get_installed_vcs()
332
debug('installed_vcs:%s' % installed_vcs)
333
if not installed_vcs:
334
#msg = 'No installed VCs'
335
#debug('msv %s\n' % repr(msg))
336
#SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
337
debug('msvc_setup_env: No installed VCs')
339
msvc_version = installed_vcs[0]
340
debug('msvc_setup_env: using default installed MSVC version %s\n' % repr(msvc_version))
344
def msvc_setup_env_once(env):
346
has_run = env["MSVC_SETUP_RUN"]
352
env["MSVC_SETUP_RUN"] = True
354
def msvc_find_valid_batch_script(env,version):
355
debug('vc.py:msvc_find_valid_batch_script()')
356
# Find the host platform, target platform, and if present the requested
358
(host_platform, target_platform,req_target_platform) = get_host_target(env)
360
# If the user hasn't specifically requested a TARGET_ARCH, and
361
# The TARGET_ARCH is amd64 then also try 32 bits if there are no viable
362
# 64 bit tools installed
363
try_target_archs = [target_platform]
364
if not req_target_platform and target_platform in ('amd64','x86_64'):
365
try_target_archs.append('x86')
368
for tp in try_target_archs:
369
# Set to current arch.
370
env['TARGET_ARCH']=tp
372
debug("vc.py:msvc_find_valid_batch_script() trying target_platform:%s"%tp)
373
host_target = (host_platform, tp)
374
if not is_host_target_supported(host_target, version):
375
warn_msg = "host, target = %s not supported for MSVC version %s" % \
376
(host_target, version)
377
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
378
arg = _HOST_TARGET_ARCH_TO_BAT_ARCH[host_target]
380
# Try to locate a batch file for this host/target platform combo
382
(vc_script,sdk_script) = find_batch_file(env,version,host_platform,tp)
383
debug('vc.py:msvc_find_valid_batch_script() vc_script:%s sdk_script:%s'%(vc_script,sdk_script))
384
except VisualCException, e:
386
debug('Caught exception while looking for batch file (%s)' % msg)
387
warn_msg = "VC version %s not installed. " + \
388
"C/C++ compilers are most likely not set correctly.\n" + \
389
" Installed versions are: %s"
390
warn_msg = warn_msg % (version, cached_get_installed_vcs())
391
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
394
# Try to use the located batch file for this host/target platform combo
395
debug('vc.py:msvc_find_valid_batch_script() use_script 2 %s, args:%s\n' % (repr(vc_script), arg))
398
d = script_env(vc_script, args=arg)
399
except BatchFileExecutionError, e:
400
debug('vc.py:msvc_find_valid_batch_script() use_script 3: failed running VC script %s: %s: Error:%s'%(repr(vc_script),arg,e))
402
if not vc_script and sdk_script:
403
debug('vc.py:msvc_find_valid_batch_script() use_script 4: trying sdk script: %s'%(sdk_script))
405
d = script_env(sdk_script,args=[])
406
except BatchFileExecutionError,e:
407
debug('vc.py:msvc_find_valid_batch_script() use_script 5: failed running SDK script %s: Error:%s'%(repr(sdk_script),e))
409
elif not vc_script and not sdk_script:
410
debug('vc.py:msvc_find_valid_batch_script() use_script 6: Neither VC script nor SDK script found')
413
# If we cannot find a viable installed compiler, reset the TARGET_ARCH
414
# To it's initial value
416
env['TARGET_ARCH']=req_target_platform
421
def msvc_setup_env(env):
422
debug('msvc_setup_env()')
424
version = get_default_version(env)
426
warn_msg = "No version of Visual Studio compiler found - C/C++ " \
427
"compilers most likely not set correctly"
428
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
430
debug('msvc_setup_env: using specified MSVC version %s\n' % repr(version))
432
# XXX: we set-up both MSVS version for backward
433
# compatibility with the msvs tool
434
env['MSVC_VERSION'] = version
435
env['MSVS_VERSION'] = version
439
use_script = env.get('MSVC_USE_SCRIPT', True)
440
if SCons.Util.is_String(use_script):
441
debug('vc.py:msvc_setup_env() use_script 1 %s\n' % repr(use_script))
442
d = script_env(use_script)
444
d = msvc_find_valid_batch_script(env,version)
445
debug('vc.py:msvc_setup_env() use_script 2 %s\n' % d)
449
debug('MSVC_USE_SCRIPT set to False')
450
warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \
452
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
455
for k, v in d.items():
456
debug('vc.py:msvc_setup_env() env:%s -> %s'%(k,v))
457
env.PrependENVPath(k, v, delete_existing=True)
459
def msvc_exists(version=None):
460
vcs = cached_get_installed_vcs()
463
return version in vcs