2
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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 5134 2010/08/16 23:02:40 bdeegan"
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
raise ValueError("Unrecognized target architecture %s" % target_platform)
129
return (host, target,req_target_platform)
131
_VCVER = ["10.0", "9.0", "9.0Exp","8.0", "8.0Exp","7.1", "7.0", "6.0"]
133
_VCVER_TO_PRODUCT_DIR = {
135
r'Microsoft\VisualStudio\10.0\Setup\VC\ProductDir'],
137
r'Microsoft\VisualStudio\9.0\Setup\VC\ProductDir'],
139
r'Microsoft\VCExpress\9.0\Setup\VC\ProductDir'],
141
r'Microsoft\VisualStudio\8.0\Setup\VC\ProductDir'],
143
r'Microsoft\VCExpress\8.0\Setup\VC\ProductDir'],
145
r'Microsoft\VisualStudio\7.1\Setup\VC\ProductDir'],
147
r'Microsoft\VisualStudio\7.0\Setup\VC\ProductDir'],
149
r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++\ProductDir']
152
def msvc_version_to_maj_min(msvc_version):
153
msvc_version_numeric = ''.join([x for x in msvc_version if x in string_digits + '.'])
155
t = msvc_version_numeric.split(".")
157
raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric))
162
except ValueError, e:
163
raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric))
165
def is_host_target_supported(host_target, msvc_version):
166
"""Return True if the given (host, target) tuple is supported given the
172
tuple of (canonalized) host-target, e.g. ("x86", "amd64") for cross
173
compilation from 32 bits windows to 64 bits.
175
msvc version (major.minor, e.g. 10.0)
179
This only check whether a given version *may* support the given (host,
180
target), not that the toolchain is actually present on the machine.
182
# We assume that any Visual Studio version supports x86 as a target
183
if host_target[1] != "x86":
184
maj, min = msvc_version_to_maj_min(msvc_version)
190
def find_vc_pdir(msvc_version):
191
"""Try to find the product directory for the given
196
If for some reason the requested version could not be found, an
197
exception which inherits from VisualCException will be raised."""
199
if common.is_win64():
200
root = root + 'Wow6432Node\\'
202
hkeys = _VCVER_TO_PRODUCT_DIR[msvc_version]
204
debug("Unknown version of MSVC: %s" % msvc_version)
205
raise UnsupportedVersion("Unknown version %s" % msvc_version)
210
comps = common.read_reg(key)
211
except WindowsError, e:
212
debug('find_vc_dir(): no VC registry key %s' % repr(key))
214
debug('find_vc_dir(): found VC in registry: %s' % comps)
215
if os.path.exists(comps):
218
debug('find_vc_dir(): reg says dir is %s, but it does not exist. (ignoring)'\
220
raise MissingConfiguration("registry dir %s not found on the filesystem" % comps)
223
def find_batch_file(env,msvc_version,host_arch,target_arch):
225
Find the location of the batch script which should set up the compiler
226
for any TARGET_ARCH whose compilers were installed by Visual Studio/VCExpress
228
pdir = find_vc_pdir(msvc_version)
230
raise NoVersionFound("No version of Visual Studio found")
232
debug('vc.py: find_batch_file() pdir:%s'%pdir)
234
# filter out e.g. "Exp" from the version name
235
msvc_ver_numeric = ''.join([x for x in msvc_version if x in string_digits + "."])
236
vernum = float(msvc_ver_numeric)
238
pdir = os.path.join(pdir, os.pardir, "Common7", "Tools")
239
batfilename = os.path.join(pdir, "vsvars32.bat")
241
pdir = os.path.join(pdir, "Bin")
242
batfilename = os.path.join(pdir, "vcvars32.bat")
244
batfilename = os.path.join(pdir, "vcvarsall.bat")
246
if not os.path.exists(batfilename):
247
debug("Not found: %s" % batfilename)
250
installed_sdks=get_installed_sdks()
251
for _sdk in installed_sdks:
252
sdk_bat_file=_sdk.get_sdk_vc_script(host_arch,target_arch)
253
sdk_bat_file_path=os.path.join(pdir,sdk_bat_file)
254
debug('vc.py:find_batch_file() sdk_bat_file_path:%s'%sdk_bat_file_path)
255
if os.path.exists(sdk_bat_file_path):
256
return (batfilename,sdk_bat_file_path)
258
debug("vc.py:find_batch_file() not found:%s"%sdk_bat_file_path)
260
return (batfilename,None)
262
__INSTALLED_VCS_RUN = None
264
def cached_get_installed_vcs():
265
global __INSTALLED_VCS_RUN
267
if __INSTALLED_VCS_RUN is None:
268
ret = get_installed_vcs()
269
__INSTALLED_VCS_RUN = ret
271
return __INSTALLED_VCS_RUN
273
def get_installed_vcs():
274
installed_versions = []
276
debug('trying to find VC %s' % ver)
278
if find_vc_pdir(ver):
279
debug('found VC %s' % ver)
280
installed_versions.append(ver)
282
debug('find_vc_pdir return None for ver %s' % ver)
283
except VisualCException, e:
284
debug('did not find VC %s: caught exception %s' % (ver, str(e)))
285
return installed_versions
287
def reset_installed_vcs():
288
"""Make it try again to find VC. This is just for the tests."""
289
__INSTALLED_VCS_RUN = None
291
def script_env(script, args=None):
292
stdout = common.get_output(script, args)
293
# Stupid batch files do not set return code: we take a look at the
294
# beginning of the output for an error message instead
295
olines = stdout.splitlines()
296
if olines[0].startswith("The specified configuration type is missing"):
297
raise BatchFileExecutionError("\n".join(olines[:2]))
299
return common.parse_output(stdout)
301
def get_default_version(env):
302
debug('get_default_version()')
304
msvc_version = env.get('MSVC_VERSION')
305
msvs_version = env.get('MSVS_VERSION')
307
debug('get_default_version(): msvc_version:%s msvs_version:%s'%(msvc_version,msvs_version))
309
if msvs_version and not msvc_version:
311
SCons.Warnings.DeprecatedWarning,
312
"MSVS_VERSION is deprecated: please use MSVC_VERSION instead ")
314
elif msvc_version and msvs_version:
315
if not msvc_version == msvs_version:
317
SCons.Warnings.VisualVersionMismatch,
318
"Requested msvc version (%s) and msvs version (%s) do " \
319
"not match: please use MSVC_VERSION only to request a " \
320
"visual studio version, MSVS_VERSION is deprecated" \
321
% (msvc_version, msvs_version))
324
installed_vcs = cached_get_installed_vcs()
325
debug('installed_vcs:%s' % installed_vcs)
326
if not installed_vcs:
327
msg = 'No installed VCs'
328
debug('msv %s\n' % repr(msg))
329
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
331
msvc_version = installed_vcs[0]
332
debug('msvc_setup_env: using default installed MSVC version %s\n' % repr(msvc_version))
336
def msvc_setup_env_once(env):
338
has_run = env["MSVC_SETUP_RUN"]
344
env["MSVC_SETUP_RUN"] = True
346
def msvc_find_valid_batch_script(env,version):
347
debug('vc.py:msvc_find_valid_batch_script()')
348
# Find the host platform, target platform, and if present the requested
350
(host_platform, target_platform,req_target_platform) = get_host_target(env)
352
# If the user hasn't specifically requested a TARGET_ARCH, and
353
# The TARGET_ARCH is amd64 then also try 32 bits if there are no viable
354
# 64 bit tools installed
355
try_target_archs = [target_platform]
356
if not req_target_platform and target_platform=='amd64':
357
try_target_archs.append('x86')
360
for tp in try_target_archs:
361
# Set to current arch.
362
env['TARGET_ARCH']=tp
364
debug("vc.py:msvc_find_valid_batch_script() trying target_platform:%s"%tp)
365
host_target = (host_platform, tp)
366
if not is_host_target_supported(host_target, version):
367
warn_msg = "host, target = %s not supported for MSVC version %s" % \
368
(host_target, version)
369
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
370
arg = _HOST_TARGET_ARCH_TO_BAT_ARCH[host_target]
372
# Try to locate a batch file for this host/target platform combo
374
(vc_script,sdk_script) = find_batch_file(env,version,host_platform,tp)
375
debug('vc.py:msvc_find_valid_batch_script() vc_script:%s sdk_script:%s'%(vc_script,sdk_script))
376
except VisualCException, e:
378
debug('Caught exception while looking for batch file (%s)' % msg)
379
warn_msg = "VC version %s not installed. " + \
380
"C/C++ compilers are most likely not set correctly.\n" + \
381
" Installed versions are: %s"
382
warn_msg = warn_msg % (version, cached_get_installed_vcs())
383
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
386
# Try to use the located batch file for this host/target platform combo
387
debug('vc.py:msvc_find_valid_batch_script() use_script 2 %s, args:%s\n' % (repr(vc_script), arg))
390
d = script_env(vc_script, args=arg)
391
except BatchFileExecutionError, e:
392
debug('vc.py:msvc_find_valid_batch_script() use_script 3: failed running VC script %s: %s: Error:%s'%(repr(vc_script),arg,e))
394
if not vc_script and sdk_script:
395
debug('vc.py:msvc_find_valid_batch_script() use_script 4: trying sdk script: %s'%(sdk_script))
397
d = script_env(sdk_script,args=[])
398
except BatchFileExecutionError,e:
399
debug('vc.py:msvc_find_valid_batch_script() use_script 5: failed running SDK script %s: Error:%s'%(repr(sdk_script),e))
401
elif not vc_script and not sdk_script:
402
debug('vc.py:msvc_find_valid_batch_script() use_script 6: Neither VC script nor SDK script found')
405
# If we cannot find a viable installed compiler, reset the TARGET_ARCH
406
# To it's initial value
408
env['TARGET_ARCH']=req_target_platform
413
def msvc_setup_env(env):
414
debug('msvc_setup_env()')
416
version = get_default_version(env)
418
warn_msg = "No version of Visual Studio compiler found - C/C++ " \
419
"compilers most likely not set correctly"
420
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
422
debug('msvc_setup_env: using specified MSVC version %s\n' % repr(version))
424
# XXX: we set-up both MSVS version for backward
425
# compatibility with the msvs tool
426
env['MSVC_VERSION'] = version
427
env['MSVS_VERSION'] = version
431
use_script = env.get('MSVC_USE_SCRIPT', True)
432
if SCons.Util.is_String(use_script):
433
debug('vc.py:msvc_setup_env() use_script 1 %s\n' % repr(use_script))
434
d = script_env(use_script)
436
d = msvc_find_valid_batch_script(env,version)
437
debug('vc.py:msvc_setup_env() use_script 2 %s\n' % d)
441
debug('MSVC_USE_SCRIPT set to False')
442
warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \
444
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
447
for k, v in d.items():
448
debug('vc.py:msvc_setup_env() env:%s -> %s'%(k,v))
449
env.PrependENVPath(k, v, delete_existing=True)
451
def msvc_exists(version=None):
452
vcs = cached_get_installed_vcs()
455
return version in vcs