summaryrefslogtreecommitdiff
path: root/waflib/Tools/msvc.py
diff options
context:
space:
mode:
Diffstat (limited to 'waflib/Tools/msvc.py')
-rw-r--r--waflib/Tools/msvc.py869
1 files changed, 512 insertions, 357 deletions
diff --git a/waflib/Tools/msvc.py b/waflib/Tools/msvc.py
index 17b347d4..d98432e0 100644
--- a/waflib/Tools/msvc.py
+++ b/waflib/Tools/msvc.py
@@ -8,12 +8,6 @@
"""
Microsoft Visual C++/Intel C++ compiler support
-If you get detection problems, first try any of the following::
-
- chcp 65001
- set PYTHONIOENCODING=...
- set PYTHONLEGACYWINDOWSSTDIO=1
-
Usage::
$ waf configure --msvc_version="msvc 10.0,msvc 9.0" --msvc_target="x64"
@@ -21,8 +15,8 @@ Usage::
or::
def configure(conf):
- conf.env.MSVC_VERSIONS = ['msvc 10.0', 'msvc 9.0', 'msvc 8.0', 'msvc 7.1', 'msvc 7.0', 'msvc 6.0', 'wsdk 7.0', 'intel 11', 'PocketPC 9.0', 'Smartphone 8.0']
- conf.env.MSVC_TARGETS = ['x64']
+ conf.env['MSVC_VERSIONS'] = ['msvc 10.0', 'msvc 9.0', 'msvc 8.0', 'msvc 7.1', 'msvc 7.0', 'msvc 6.0', 'wsdk 7.0', 'intel 11', 'PocketPC 9.0', 'Smartphone 8.0']
+ conf.env['MSVC_TARGETS'] = ['x64']
conf.load('msvc')
or::
@@ -37,14 +31,14 @@ or::
Platforms and targets will be tested in the order they appear;
the first good configuration will be used.
-To force testing all the configurations that are not used, use the ``--no-msvc-lazy`` option
-or set ``conf.env.MSVC_LAZY_AUTODETECT=False``.
+To skip testing all the configurations that are not used, use the ``--msvc_lazy_autodetect`` option
+or set ``conf.env['MSVC_LAZY_AUTODETECT']=True``.
Supported platforms: ia64, x64, x86, x86_amd64, x86_ia64, x86_arm, amd64_x86, amd64_arm
Compilers supported:
-* msvc => Visual Studio, versions 6.0 (VC 98, VC .NET 2002) to 15 (Visual Studio 2017)
+* msvc => Visual Studio, versions 6.0 (VC 98, VC .NET 2002) to 12.0 (Visual Studio 2013)
* wsdk => Windows SDK, versions 6.0, 6.1, 7.0, 7.1, 8.0
* icl => Intel compiler, versions 9, 10, 11, 13
* winphone => Visual Studio to target Windows Phone 8 native (version 8.0 for now)
@@ -58,12 +52,13 @@ cmd.exe /C "chcp 1252 & set PYTHONUNBUFFERED=true && set && waf configure"
Setting PYTHONUNBUFFERED gives the unbuffered output.
"""
-import os, sys, re, traceback
-from waflib import Utils, Logs, Options, Errors
+import os, sys, re, tempfile
+from waflib import Utils, Task, Logs, Options, Errors
+from waflib.Logs import debug, warn
from waflib.TaskGen import after_method, feature
from waflib.Configure import conf
-from waflib.Tools import ccroot, c, cxx, ar
+from waflib.Tools import ccroot, c, cxx, ar, winres
g_msvc_systemlibs = '''
aclui activeds ad1 adptif adsiid advapi32 asycfilt authz bhsupp bits bufferoverflowu cabinet
@@ -87,9 +82,7 @@ wintrust wldap32 wmiutils wow32 ws2_32 wsnmp32 wsock32 wst wtsapi32 xaswitch xol
'''.split()
"""importlibs provided by MSVC/Platform SDK. Do NOT search them"""
-all_msvc_platforms = [ ('x64', 'amd64'), ('x86', 'x86'), ('ia64', 'ia64'),
- ('x86_amd64', 'amd64'), ('x86_ia64', 'ia64'), ('x86_arm', 'arm'), ('x86_arm64', 'arm64'),
- ('amd64_x86', 'x86'), ('amd64_arm', 'arm'), ('amd64_arm64', 'arm64') ]
+all_msvc_platforms = [ ('x64', 'amd64'), ('x86', 'x86'), ('ia64', 'ia64'), ('x86_amd64', 'amd64'), ('x86_ia64', 'ia64'), ('x86_arm', 'arm'), ('amd64_x86', 'x86'), ('amd64_arm', 'arm') ]
"""List of msvc platforms"""
all_wince_platforms = [ ('armv4', 'arm'), ('armv4i', 'arm'), ('mipsii', 'mips'), ('mipsii_fp', 'mips'), ('mipsiv', 'mips'), ('mipsiv_fp', 'mips'), ('sh4', 'sh'), ('x86', 'cex86') ]
@@ -101,63 +94,45 @@ all_icl_platforms = [ ('intel64', 'amd64'), ('em64t', 'amd64'), ('ia32', 'x86'),
def options(opt):
opt.add_option('--msvc_version', type='string', help = 'msvc version, eg: "msvc 10.0,msvc 9.0"', default='')
opt.add_option('--msvc_targets', type='string', help = 'msvc targets, eg: "x64,arm"', default='')
- opt.add_option('--no-msvc-lazy', action='store_false', help = 'lazily check msvc target environments', default=True, dest='msvc_lazy')
+ opt.add_option('--msvc_lazy_autodetect', action='store_true', help = 'lazily check msvc target environments')
-@conf
-def setup_msvc(conf, versiondict):
+def setup_msvc(conf, versions, arch = False):
"""
Checks installed compilers and targets and returns the first combination from the user's
options, env, or the global supported lists that checks.
- :param versiondict: dict(platform -> dict(architecture -> configuration))
- :type versiondict: dict(string -> dict(string -> target_compiler)
- :return: the compiler, revision, path, include dirs, library paths and target architecture
+ :param versions: A list of tuples of all installed compilers and available targets.
+ :param arch: Whether to return the target architecture.
+ :return: the compiler, revision, path, include dirs, library paths, and (optionally) target architecture
:rtype: tuple of strings
"""
platforms = getattr(Options.options, 'msvc_targets', '').split(',')
if platforms == ['']:
- platforms=Utils.to_list(conf.env.MSVC_TARGETS) or [i for i,j in all_msvc_platforms+all_icl_platforms+all_wince_platforms]
+ platforms=Utils.to_list(conf.env['MSVC_TARGETS']) or [i for i,j in all_msvc_platforms+all_icl_platforms+all_wince_platforms]
desired_versions = getattr(Options.options, 'msvc_version', '').split(',')
if desired_versions == ['']:
- desired_versions = conf.env.MSVC_VERSIONS or list(reversed(sorted(versiondict.keys())))
-
- # Override lazy detection by evaluating after the fact.
- lazy_detect = getattr(Options.options, 'msvc_lazy', True)
- if conf.env.MSVC_LAZY_AUTODETECT is False:
- lazy_detect = False
-
- if not lazy_detect:
- for val in versiondict.values():
- for arch in list(val.keys()):
- cfg = val[arch]
- cfg.evaluate()
- if not cfg.is_valid:
- del val[arch]
- conf.env.MSVC_INSTALLED_VERSIONS = versiondict
+ desired_versions = conf.env['MSVC_VERSIONS'] or [v for v,_ in versions][::-1]
+ versiondict = dict(versions)
for version in desired_versions:
- Logs.debug('msvc: detecting %r - %r', version, desired_versions)
try:
- targets = versiondict[version]
- except KeyError:
- continue
-
- seen = set()
- for arch in platforms:
- if arch in seen:
- continue
- else:
- seen.add(arch)
- try:
- cfg = targets[arch]
- except KeyError:
- continue
-
- cfg.evaluate()
- if cfg.is_valid:
- compiler,revision = version.rsplit(' ', 1)
- return compiler,revision,cfg.bindirs,cfg.incdirs,cfg.libdirs,cfg.cpu
- conf.fatal('msvc: Impossible to find a valid architecture for building %r - %r' % (desired_versions, list(versiondict.keys())))
+ targets = dict(versiondict[version])
+ for target in platforms:
+ try:
+ try:
+ realtarget,(p1,p2,p3) = targets[target]
+ except conf.errors.ConfigurationError:
+ # lazytup target evaluation errors
+ del(targets[target])
+ else:
+ compiler,revision = version.rsplit(' ', 1)
+ if arch:
+ return compiler,revision,p1,p2,p3,realtarget
+ else:
+ return compiler,revision,p1,p2,p3
+ except KeyError: continue
+ except KeyError: continue
+ conf.fatal('msvc: Impossible to find a valid architecture for building (in setup_msvc)')
@conf
def get_msvc_version(conf, compiler, version, target, vcvars):
@@ -172,7 +147,7 @@ def get_msvc_version(conf, compiler, version, target, vcvars):
:return: the location of the compiler executable, the location of include dirs, and the library paths
:rtype: tuple of strings
"""
- Logs.debug('msvc: get_msvc_version: %r %r %r', compiler, version, target)
+ debug('msvc: get_msvc_version: %r %r %r', compiler, version, target)
try:
conf.msvc_cnt += 1
@@ -212,27 +187,67 @@ echo LIB=%%LIB%%;%%LIBPATH%%
compiler_name, linker_name, lib_name = _get_prog_names(conf, compiler)
cxx = conf.find_program(compiler_name, path_list=MSVC_PATH)
- # delete CL if exists. because it could contain parameters which can change cl's behaviour rather catastrophically.
+ # delete CL if exists. because it could contain parameters wich can change cl's behaviour rather catastrophically.
if 'CL' in env:
del(env['CL'])
try:
- conf.cmd_and_log(cxx + ['/help'], env=env)
- except UnicodeError:
- st = traceback.format_exc()
- if conf.logger:
- conf.logger.error(st)
- conf.fatal('msvc: Unicode error - check the code page?')
- except Exception as e:
- Logs.debug('msvc: get_msvc_version: %r %r %r -> failure %s', compiler, version, target, str(e))
- conf.fatal('msvc: cannot run the compiler in get_msvc_version (run with -v to display errors)')
- else:
- Logs.debug('msvc: get_msvc_version: %r %r %r -> OK', compiler, version, target)
+ try:
+ conf.cmd_and_log(cxx + ['/help'], env=env)
+ except UnicodeError:
+ st = Utils.ex_stack()
+ if conf.logger:
+ conf.logger.error(st)
+ conf.fatal('msvc: Unicode error - check the code page?')
+ except Exception as e:
+ debug('msvc: get_msvc_version: %r %r %r -> failure %s' % (compiler, version, target, str(e)))
+ conf.fatal('msvc: cannot run the compiler in get_msvc_version (run with -v to display errors)')
+ else:
+ debug('msvc: get_msvc_version: %r %r %r -> OK', compiler, version, target)
finally:
conf.env[compiler_name] = ''
return (MSVC_PATH, MSVC_INCDIR, MSVC_LIBDIR)
+@conf
+def gather_wsdk_versions(conf, versions):
+ """
+ Use winreg to add the msvc versions to the input list
+
+ :param versions: list to modify
+ :type versions: list
+ """
+ version_pattern = re.compile('^v..?.?\...?.?')
+ try:
+ all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Microsoft SDKs\\Windows')
+ except WindowsError:
+ try:
+ all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows')
+ except WindowsError:
+ return
+ index = 0
+ while 1:
+ try:
+ version = Utils.winreg.EnumKey(all_versions, index)
+ except WindowsError:
+ break
+ index = index + 1
+ if not version_pattern.match(version):
+ continue
+ try:
+ msvc_version = Utils.winreg.OpenKey(all_versions, version)
+ path,type = Utils.winreg.QueryValueEx(msvc_version,'InstallationFolder')
+ except WindowsError:
+ continue
+ if path and os.path.isfile(os.path.join(path, 'bin', 'SetEnv.cmd')):
+ targets = []
+ for target,arch in all_msvc_platforms:
+ try:
+ targets.append((target, (arch, get_compiler_env(conf, 'wsdk', version, '/'+target, os.path.join(path, 'bin', 'SetEnv.cmd')))))
+ except conf.errors.ConfigurationError:
+ pass
+ versions.append(('wsdk ' + version[1:], targets))
+
def gather_wince_supported_platforms():
"""
Checks SmartPhones SDKs
@@ -243,31 +258,31 @@ def gather_wince_supported_platforms():
supported_wince_platforms = []
try:
ce_sdk = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Windows CE Tools\\SDKs')
- except OSError:
+ except WindowsError:
try:
ce_sdk = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows CE Tools\\SDKs')
- except OSError:
+ except WindowsError:
ce_sdk = ''
if not ce_sdk:
return supported_wince_platforms
- index = 0
+ ce_index = 0
while 1:
try:
- sdk_device = Utils.winreg.EnumKey(ce_sdk, index)
- sdk = Utils.winreg.OpenKey(ce_sdk, sdk_device)
- except OSError:
+ sdk_device = Utils.winreg.EnumKey(ce_sdk, ce_index)
+ except WindowsError:
break
- index += 1
+ ce_index = ce_index + 1
+ sdk = Utils.winreg.OpenKey(ce_sdk, sdk_device)
try:
path,type = Utils.winreg.QueryValueEx(sdk, 'SDKRootDir')
- except OSError:
+ except WindowsError:
try:
path,type = Utils.winreg.QueryValueEx(sdk,'SDKInformation')
- except OSError:
+ path,xml = os.path.split(path)
+ except WindowsError:
continue
- path,xml = os.path.split(path)
- path = str(path)
+ path=str(path)
path,device = os.path.split(path)
if not device:
path,device = os.path.split(path)
@@ -284,140 +299,122 @@ def gather_msvc_detected_versions():
version_pattern = re.compile('^(\d\d?\.\d\d?)(Exp)?$')
detected_versions = []
for vcver,vcvar in (('VCExpress','Exp'), ('VisualStudio','')):
- prefix = 'SOFTWARE\\Wow6432node\\Microsoft\\' + vcver
try:
+ prefix = 'SOFTWARE\\Wow6432node\\Microsoft\\'+vcver
all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, prefix)
- except OSError:
- prefix = 'SOFTWARE\\Microsoft\\' + vcver
+ except WindowsError:
try:
+ prefix = 'SOFTWARE\\Microsoft\\'+vcver
all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, prefix)
- except OSError:
+ except WindowsError:
continue
index = 0
while 1:
try:
version = Utils.winreg.EnumKey(all_versions, index)
- except OSError:
+ except WindowsError:
break
- index += 1
+ index = index + 1
match = version_pattern.match(version)
- if match:
- versionnumber = float(match.group(1))
- else:
+ if not match:
continue
- detected_versions.append((versionnumber, version+vcvar, prefix+'\\'+version))
+ else:
+ versionnumber = float(match.group(1))
+ detected_versions.append((versionnumber, version+vcvar, prefix+"\\"+version))
def fun(tup):
return tup[0]
detected_versions.sort(key = fun)
return detected_versions
-class target_compiler(object):
- """
- Wrap a compiler configuration; call evaluate() to determine
- whether the configuration is usable.
- """
- def __init__(self, ctx, compiler, cpu, version, bat_target, bat, callback=None):
- """
- :param ctx: configuration context to use to eventually get the version environment
- :param compiler: compiler name
- :param cpu: target cpu
- :param version: compiler version number
- :param bat_target: ?
- :param bat: path to the batch file to run
- """
- self.conf = ctx
- self.name = None
- self.is_valid = False
- self.is_done = False
-
- self.compiler = compiler
- self.cpu = cpu
- self.version = version
- self.bat_target = bat_target
- self.bat = bat
- self.callback = callback
-
- def evaluate(self):
- if self.is_done:
- return
- self.is_done = True
- try:
- vs = self.conf.get_msvc_version(self.compiler, self.version, self.bat_target, self.bat)
- except Errors.ConfigurationError:
- self.is_valid = False
- return
- if self.callback:
- vs = self.callback(self, vs)
- self.is_valid = True
- (self.bindirs, self.incdirs, self.libdirs) = vs
-
- def __str__(self):
- return str((self.compiler, self.cpu, self.version, self.bat_target, self.bat))
+def get_compiler_env(conf, compiler, version, bat_target, bat, select=None):
+ """
+ Gets the compiler environment variables as a tuple. Evaluation is eager by default.
+ If set to lazy with ``--msvc_lazy_autodetect`` or ``env.MSVC_LAZY_AUTODETECT``
+ the environment is evaluated when the tuple is destructured or iterated. This means
+ destructuring can throw :py:class:`conf.errors.ConfigurationError`.
+
+ :param conf: configuration context to use to eventually get the version environment
+ :param compiler: compiler name
+ :param version: compiler version number
+ :param bat: path to the batch file to run
+ :param select: optional function to take the realized environment variables tup and map it (e.g. to combine other constant paths)
+ """
+ lazy = getattr(Options.options, 'msvc_lazy_autodetect', False) or conf.env['MSVC_LAZY_AUTODETECT']
- def __repr__(self):
- return repr((self.compiler, self.cpu, self.version, self.bat_target, self.bat))
+ def msvc_thunk():
+ vs = conf.get_msvc_version(compiler, version, bat_target, bat)
+ if select:
+ return select(vs)
+ else:
+ return vs
+ return lazytup(msvc_thunk, lazy, ([], [], []))
-@conf
-def gather_wsdk_versions(conf, versions):
+class lazytup(object):
"""
- Use winreg to add the msvc versions to the input list
+ A tuple that evaluates its elements from a function when iterated or destructured.
- :param versions: list to modify
- :type versions: list
+ :param fn: thunk to evaluate the tuple on demand
+ :param lazy: whether to delay evaluation or evaluate in the constructor
+ :param default: optional default for :py:func:`repr` if it should not evaluate
"""
- version_pattern = re.compile('^v..?.?\...?.?')
- try:
- all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Microsoft SDKs\\Windows')
- except OSError:
- try:
- all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows')
- except OSError:
+ def __init__(self, fn, lazy=True, default=None):
+ self.fn = fn
+ self.default = default
+ if not lazy:
+ self.evaluate()
+ def __len__(self):
+ self.evaluate()
+ return len(self.value)
+ def __iter__(self):
+ self.evaluate()
+ for i, v in enumerate(self.value):
+ yield v
+ def __getitem__(self, i):
+ self.evaluate()
+ return self.value[i]
+ def __repr__(self):
+ if hasattr(self, 'value'):
+ return repr(self.value)
+ elif self.default:
+ return repr(self.default)
+ else:
+ self.evaluate()
+ return repr(self.value)
+ def evaluate(self):
+ if hasattr(self, 'value'):
return
- index = 0
- while 1:
- try:
- version = Utils.winreg.EnumKey(all_versions, index)
- except OSError:
- break
- index += 1
- if not version_pattern.match(version):
- continue
- try:
- msvc_version = Utils.winreg.OpenKey(all_versions, version)
- path,type = Utils.winreg.QueryValueEx(msvc_version,'InstallationFolder')
- except OSError:
- continue
- if path and os.path.isfile(os.path.join(path, 'bin', 'SetEnv.cmd')):
- targets = {}
- for target,arch in all_msvc_platforms:
- targets[target] = target_compiler(conf, 'wsdk', arch, version, '/'+target, os.path.join(path, 'bin', 'SetEnv.cmd'))
- versions['wsdk ' + version[1:]] = targets
+ self.value = self.fn()
@conf
def gather_msvc_targets(conf, versions, version, vc_path):
#Looking for normal MSVC compilers!
- targets = {}
-
- if os.path.isfile(os.path.join(vc_path, 'VC', 'Auxiliary', 'Build', 'vcvarsall.bat')):
- for target,realtarget in all_msvc_platforms[::-1]:
- targets[target] = target_compiler(conf, 'msvc', realtarget, version, target, os.path.join(vc_path, 'VC', 'Auxiliary', 'Build', 'vcvarsall.bat'))
- elif os.path.isfile(os.path.join(vc_path, 'vcvarsall.bat')):
+ targets = []
+ if os.path.isfile(os.path.join(vc_path, 'vcvarsall.bat')):
for target,realtarget in all_msvc_platforms[::-1]:
- targets[target] = target_compiler(conf, 'msvc', realtarget, version, target, os.path.join(vc_path, 'vcvarsall.bat'))
+ try:
+ targets.append((target, (realtarget, get_compiler_env(conf, 'msvc', version, target, os.path.join(vc_path, 'vcvarsall.bat')))))
+ except conf.errors.ConfigurationError:
+ pass
elif os.path.isfile(os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat')):
- targets['x86'] = target_compiler(conf, 'msvc', 'x86', version, 'x86', os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat'))
+ try:
+ targets.append(('x86', ('x86', get_compiler_env(conf, 'msvc', version, 'x86', os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat')))))
+ except conf.errors.ConfigurationError:
+ pass
elif os.path.isfile(os.path.join(vc_path, 'Bin', 'vcvars32.bat')):
- targets['x86'] = target_compiler(conf, 'msvc', 'x86', version, '', os.path.join(vc_path, 'Bin', 'vcvars32.bat'))
+ try:
+ targets.append(('x86', ('x86', get_compiler_env(conf, 'msvc', version, '', os.path.join(vc_path, 'Bin', 'vcvars32.bat')))))
+ except conf.errors.ConfigurationError:
+ pass
if targets:
- versions['msvc %s' % version] = targets
+ versions.append(('msvc '+ version, targets))
@conf
def gather_wince_targets(conf, versions, version, vc_path, vsvars, supported_platforms):
#Looking for Win CE compilers!
for device,platforms in supported_platforms:
- targets = {}
+ cetargets = []
for platform,compiler,include,lib in platforms:
winCEpath = os.path.join(vc_path, 'ce')
if not os.path.isdir(winCEpath):
@@ -427,52 +424,27 @@ def gather_wince_targets(conf, versions, version, vc_path, vsvars, supported_pla
bindirs = [os.path.join(winCEpath, 'bin', compiler), os.path.join(winCEpath, 'bin', 'x86_'+compiler)]
incdirs = [os.path.join(winCEpath, 'include'), os.path.join(winCEpath, 'atlmfc', 'include'), include]
libdirs = [os.path.join(winCEpath, 'lib', platform), os.path.join(winCEpath, 'atlmfc', 'lib', platform), lib]
- def combine_common(obj, compiler_env):
- # TODO this is likely broken, remove in waf 2.1
+ def combine_common(compiler_env):
(common_bindirs,_1,_2) = compiler_env
return (bindirs + common_bindirs, incdirs, libdirs)
- targets[platform] = target_compiler(conf, 'msvc', platform, version, 'x86', vsvars, combine_common)
- if targets:
- versions[device + ' ' + version] = targets
+ try:
+ cetargets.append((platform, (platform, get_compiler_env(conf, 'msvc', version, 'x86', vsvars, combine_common))))
+ except conf.errors.ConfigurationError:
+ continue
+ if cetargets:
+ versions.append((device + ' ' + version, cetargets))
@conf
def gather_winphone_targets(conf, versions, version, vc_path, vsvars):
#Looking for WinPhone compilers
- targets = {}
+ targets = []
for target,realtarget in all_msvc_platforms[::-1]:
- targets[target] = target_compiler(conf, 'winphone', realtarget, version, target, vsvars)
+ try:
+ targets.append((target, (realtarget, get_compiler_env(conf, 'winphone', version, target, vsvars))))
+ except conf.errors.ConfigurationError:
+ pass
if targets:
- versions['winphone ' + version] = targets
-
-@conf
-def gather_vswhere_versions(conf, versions):
- try:
- import json
- except ImportError:
- Logs.error('Visual Studio 2017 detection requires Python 2.6')
- return
-
- prg_path = os.environ.get('ProgramFiles(x86)', os.environ.get('ProgramFiles', 'C:\\Program Files (x86)'))
-
- vswhere = os.path.join(prg_path, 'Microsoft Visual Studio', 'Installer', 'vswhere.exe')
- args = [vswhere, '-products', '*', '-legacy', '-format', 'json']
- try:
- txt = conf.cmd_and_log(args)
- except Errors.WafError as e:
- Logs.debug('msvc: vswhere.exe failed %s', e)
- return
-
- if sys.version_info[0] < 3:
- txt = txt.decode(Utils.console_encoding())
-
- arr = json.loads(txt)
- arr.sort(key=lambda x: x['installationVersion'])
- for entry in arr:
- ver = entry['installationVersion']
- ver = str('.'.join(ver.split('.')[:2]))
- path = str(os.path.abspath(entry['installationPath']))
- if os.path.exists(path) and ('msvc %s' % ver) not in versions:
- conf.gather_msvc_targets(versions, ver, path)
+ versions.append(('winphone '+ version, targets))
@conf
def gather_msvc_versions(conf, versions):
@@ -481,20 +453,12 @@ def gather_msvc_versions(conf, versions):
try:
try:
msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, reg + "\\Setup\\VC")
- except OSError:
+ except WindowsError:
msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, reg + "\\Setup\\Microsoft Visual C++")
path,type = Utils.winreg.QueryValueEx(msvc_version, 'ProductDir')
- except OSError:
- try:
- msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Wow6432node\\Microsoft\\VisualStudio\\SxS\\VS7")
- path,type = Utils.winreg.QueryValueEx(msvc_version, version)
- except OSError:
- continue
- else:
- vc_paths.append((version, os.path.abspath(str(path))))
- continue
- else:
vc_paths.append((version, os.path.abspath(str(path))))
+ except WindowsError:
+ continue
wince_supported_platforms = gather_wince_supported_platforms()
@@ -528,48 +492,50 @@ def gather_icl_versions(conf, versions):
version_pattern = re.compile('^...?.?\....?.?')
try:
all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Compilers\\C++')
- except OSError:
+ except WindowsError:
try:
all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Intel\\Compilers\\C++')
- except OSError:
+ except WindowsError:
return
index = 0
while 1:
try:
version = Utils.winreg.EnumKey(all_versions, index)
- except OSError:
+ except WindowsError:
break
- index += 1
+ index = index + 1
if not version_pattern.match(version):
continue
- targets = {}
+ targets = []
for target,arch in all_icl_platforms:
- if target=='intel64':
- targetDir='EM64T_NATIVE'
- else:
- targetDir=target
try:
+ if target=='intel64': targetDir='EM64T_NATIVE'
+ else: targetDir=target
Utils.winreg.OpenKey(all_versions,version+'\\'+targetDir)
icl_version=Utils.winreg.OpenKey(all_versions,version)
path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir')
- except OSError:
- pass
- else:
batch_file=os.path.join(path,'bin','iclvars.bat')
if os.path.isfile(batch_file):
- targets[target] = target_compiler(conf, 'intel', arch, version, target, batch_file)
+ try:
+ targets.append((target,(arch,get_compiler_env(conf,'intel',version,target,batch_file))))
+ except conf.errors.ConfigurationError:
+ pass
+ except WindowsError:
+ pass
for target,arch in all_icl_platforms:
try:
icl_version = Utils.winreg.OpenKey(all_versions, version+'\\'+target)
path,type = Utils.winreg.QueryValueEx(icl_version,'ProductDir')
- except OSError:
- continue
- else:
batch_file=os.path.join(path,'bin','iclvars.bat')
if os.path.isfile(batch_file):
- targets[target] = target_compiler(conf, 'intel', arch, version, target, batch_file)
+ try:
+ targets.append((target, (arch, get_compiler_env(conf, 'intel', version, target, batch_file))))
+ except conf.errors.ConfigurationError:
+ pass
+ except WindowsError:
+ continue
major = version[0:2]
- versions['intel ' + major] = targets
+ versions.append(('intel ' + major, targets))
@conf
def gather_intel_composer_versions(conf, versions):
@@ -582,44 +548,42 @@ def gather_intel_composer_versions(conf, versions):
version_pattern = re.compile('^...?.?\...?.?.?')
try:
all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Suites')
- except OSError:
+ except WindowsError:
try:
all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Intel\\Suites')
- except OSError:
+ except WindowsError:
return
index = 0
while 1:
try:
version = Utils.winreg.EnumKey(all_versions, index)
- except OSError:
+ except WindowsError:
break
- index += 1
+ index = index + 1
if not version_pattern.match(version):
continue
- targets = {}
+ targets = []
for target,arch in all_icl_platforms:
- if target=='intel64':
- targetDir='EM64T_NATIVE'
- else:
- targetDir=target
try:
+ if target=='intel64': targetDir='EM64T_NATIVE'
+ else: targetDir=target
try:
defaults = Utils.winreg.OpenKey(all_versions,version+'\\Defaults\\C++\\'+targetDir)
- except OSError:
- if targetDir == 'EM64T_NATIVE':
+ except WindowsError:
+ if targetDir=='EM64T_NATIVE':
defaults = Utils.winreg.OpenKey(all_versions,version+'\\Defaults\\C++\\EM64T')
else:
- raise
+ raise WindowsError
uid,type = Utils.winreg.QueryValueEx(defaults, 'SubKey')
Utils.winreg.OpenKey(all_versions,version+'\\'+uid+'\\C++\\'+targetDir)
icl_version=Utils.winreg.OpenKey(all_versions,version+'\\'+uid+'\\C++')
path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir')
- except OSError:
- pass
- else:
batch_file=os.path.join(path,'bin','iclvars.bat')
if os.path.isfile(batch_file):
- targets[target] = target_compiler(conf, 'intel', arch, version, target, batch_file)
+ try:
+ targets.append((target,(arch,get_compiler_env(conf,'intel',version,target,batch_file))))
+ except conf.errors.ConfigurationError:
+ pass
# The intel compilervar_arch.bat is broken when used with Visual Studio Express 2012
# http://software.intel.com/en-us/forums/topic/328487
compilervars_warning_attr = '_compilervars_warning_key'
@@ -637,41 +601,72 @@ def gather_intel_composer_versions(conf, versions):
'(VSWinExpress.exe) but it does not seem to be installed at %r. '
'The intel command line set up will fail to configure unless the file %r'
'is patched. See: %s') % (vs_express_path, compilervars_arch, patch_url))
+ except WindowsError:
+ pass
major = version[0:2]
- versions['intel ' + major] = targets
+ versions.append(('intel ' + major, targets))
@conf
-def detect_msvc(self):
- return self.setup_msvc(self.get_msvc_versions())
+def get_msvc_versions(conf, eval_and_save=True):
+ """
+ :return: list of compilers installed
+ :rtype: list of string
+ """
+ if conf.env['MSVC_INSTALLED_VERSIONS']:
+ return conf.env['MSVC_INSTALLED_VERSIONS']
+
+ # Gather all the compiler versions and targets. This phase can be lazy
+ # per lazy detection settings.
+ lst = []
+ conf.gather_icl_versions(lst)
+ conf.gather_intel_composer_versions(lst)
+ conf.gather_wsdk_versions(lst)
+ conf.gather_msvc_versions(lst)
+
+ # Override lazy detection by evaluating after the fact.
+ if eval_and_save:
+ def checked_target(t):
+ target,(arch,paths) = t
+ try:
+ paths.evaluate()
+ except conf.errors.ConfigurationError:
+ return None
+ else:
+ return t
+ lst = [(version, list(filter(checked_target, targets))) for version, targets in lst]
+ conf.env['MSVC_INSTALLED_VERSIONS'] = lst
+
+ return lst
@conf
-def get_msvc_versions(self):
+def print_all_msvc_detected(conf):
"""
- :return: platform to compiler configurations
- :rtype: dict
+ Print the contents of *conf.env.MSVC_INSTALLED_VERSIONS*
"""
- dct = Utils.ordered_iter_dict()
- self.gather_icl_versions(dct)
- self.gather_intel_composer_versions(dct)
- self.gather_wsdk_versions(dct)
- self.gather_msvc_versions(dct)
- self.gather_vswhere_versions(dct)
- Logs.debug('msvc: detected versions %r', list(dct.keys()))
- return dct
+ for version,targets in conf.env['MSVC_INSTALLED_VERSIONS']:
+ Logs.info(version)
+ for target,l in targets:
+ Logs.info("\t"+target)
+
+@conf
+def detect_msvc(conf, arch = False):
+ # Save installed versions only if lazy detection is disabled.
+ lazy_detect = getattr(Options.options, 'msvc_lazy_autodetect', False) or conf.env['MSVC_LAZY_AUTODETECT']
+ versions = get_msvc_versions(conf, not lazy_detect)
+ return setup_msvc(conf, versions, arch)
@conf
def find_lt_names_msvc(self, libname, is_static=False):
"""
Win32/MSVC specific code to glean out information from libtool la files.
- this function is not attached to the task_gen class. Returns a triplet:
- (library absolute path, library name without extension, whether the library is static)
+ this function is not attached to the task_gen class
"""
lt_names=[
'lib%s.la' % libname,
'%s.la' % libname,
]
- for path in self.env.LIBPATH:
+ for path in self.env['LIBPATH']:
for la in lt_names:
laf=os.path.join(path,la)
dll=None
@@ -713,14 +708,14 @@ def libname_msvc(self, libname, is_static=False):
(lt_path, lt_libname, lt_static) = self.find_lt_names_msvc(lib, is_static)
if lt_path != None and lt_libname != None:
- if lt_static:
- # file existence check has been made by find_lt_names
+ if lt_static == True:
+ # file existance check has been made by find_lt_names
return os.path.join(lt_path,lt_libname)
if lt_path != None:
- _libpaths = [lt_path] + self.env.LIBPATH
+ _libpaths=[lt_path] + self.env['LIBPATH']
else:
- _libpaths = self.env.LIBPATH
+ _libpaths=self.env['LIBPATH']
static_libs=[
'lib%ss.lib' % lib,
@@ -746,11 +741,11 @@ def libname_msvc(self, libname, is_static=False):
for path in _libpaths:
for libn in libnames:
if os.path.exists(os.path.join(path, libn)):
- Logs.debug('msvc: lib found: %s', os.path.join(path,libn))
+ debug('msvc: lib found: %s' % os.path.join(path,libn))
return re.sub('\.lib$', '',libn)
#if no lib can be found, just return the libname as msvc expects it
- self.fatal('The library %r could not be found' % libname)
+ self.fatal("The library %r could not be found" % libname)
return re.sub('\.lib$', '', libname)
@conf
@@ -758,7 +753,7 @@ def check_lib_msvc(self, libname, is_static=False, uselib_store=None):
"""
Ideally we should be able to place the lib in the right env var, either STLIB or LIB,
but we don't distinguish static libs from shared libs.
- This is ok since msvc doesn't have any special linker flag to select static libs (no env.STLIB_MARKER)
+ This is ok since msvc doesn't have any special linker flag to select static libs (no env['STLIB_MARKER'])
"""
libn = self.libname_msvc(libname, is_static)
@@ -795,26 +790,27 @@ def no_autodetect(conf):
configure(conf)
@conf
-def autodetect(conf, arch=False):
+def autodetect(conf, arch = False):
v = conf.env
if v.NO_MSVC_DETECT:
return
-
- compiler, version, path, includes, libdirs, cpu = conf.detect_msvc()
if arch:
- v.DEST_CPU = cpu
+ compiler, version, path, includes, libdirs, arch = conf.detect_msvc(True)
+ v['DEST_CPU'] = arch
+ else:
+ compiler, version, path, includes, libdirs = conf.detect_msvc()
- v.PATH = path
- v.INCLUDES = includes
- v.LIBPATH = libdirs
- v.MSVC_COMPILER = compiler
+ v['PATH'] = path
+ v['INCLUDES'] = includes
+ v['LIBPATH'] = libdirs
+ v['MSVC_COMPILER'] = compiler
try:
- v.MSVC_VERSION = float(version)
- except ValueError:
- v.MSVC_VERSION = float(version[:-3])
+ v['MSVC_VERSION'] = float(version)
+ except Exception:
+ v['MSVC_VERSION'] = float(version[:-3])
def _get_prog_names(conf, compiler):
- if compiler == 'intel':
+ if compiler=='intel':
compiler_name = 'ICL'
linker_name = 'XILINK'
lib_name = 'XILIB'
@@ -833,9 +829,9 @@ def find_msvc(conf):
# the autodetection is supposed to be performed before entering in this method
v = conf.env
- path = v.PATH
- compiler = v.MSVC_COMPILER
- version = v.MSVC_VERSION
+ path = v['PATH']
+ compiler = v['MSVC_COMPILER']
+ version = v['MSVC_VERSION']
compiler_name, linker_name, lib_name = _get_prog_names(conf, compiler)
v.MSVC_MANIFEST = (compiler == 'msvc' and version >= 8) or (compiler == 'wsdk' and version >= 6) or (compiler == 'intel' and version >= 11)
@@ -845,47 +841,48 @@ def find_msvc(conf):
# before setting anything, check if the compiler is really msvc
env = dict(conf.environ)
- if path:
- env.update(PATH = ';'.join(path))
+ if path: env.update(PATH = ';'.join(path))
if not conf.cmd_and_log(cxx + ['/nologo', '/help'], env=env):
conf.fatal('the msvc compiler could not be identified')
# c/c++ compiler
- v.CC = v.CXX = cxx
- v.CC_NAME = v.CXX_NAME = 'msvc'
+ v['CC'] = v['CXX'] = cxx
+ v['CC_NAME'] = v['CXX_NAME'] = 'msvc'
# linker
- if not v.LINK_CXX:
- conf.find_program(linker_name, path_list=path, errmsg='%s was not found (linker)' % linker_name, var='LINK_CXX')
+ if not v['LINK_CXX']:
+ link = conf.find_program(linker_name, path_list=path)
+ if link: v['LINK_CXX'] = link
+ else: conf.fatal('%s was not found (linker)' % linker_name)
+ v['LINK'] = link
- if not v.LINK_CC:
- v.LINK_CC = v.LINK_CXX
+ if not v['LINK_CC']:
+ v['LINK_CC'] = v['LINK_CXX']
# staticlib linker
- if not v.AR:
+ if not v['AR']:
stliblink = conf.find_program(lib_name, path_list=path, var='AR')
- if not stliblink:
- return
- v.ARFLAGS = ['/nologo']
+ if not stliblink: return
+ v['ARFLAGS'] = ['/NOLOGO']
# manifest tool. Not required for VS 2003 and below. Must have for VS 2005 and later
if v.MSVC_MANIFEST:
conf.find_program('MT', path_list=path, var='MT')
- v.MTFLAGS = ['/nologo']
+ v['MTFLAGS'] = ['/NOLOGO']
try:
conf.load('winres')
- except Errors.ConfigurationError:
- Logs.warn('Resource compiler not found. Compiling resource file is disabled')
+ except Errors.WafError:
+ warn('Resource compiler not found. Compiling resource file is disabled')
@conf
def visual_studio_add_flags(self):
"""visual studio flags found in the system environment"""
v = self.env
- if self.environ.get('INCLUDE'):
- v.prepend_value('INCLUDES', [x for x in self.environ['INCLUDE'].split(';') if x]) # notice the 'S'
- if self.environ.get('LIB'):
- v.prepend_value('LIBPATH', [x for x in self.environ['LIB'].split(';') if x])
+ try: v.prepend_value('INCLUDES', [x for x in self.environ['INCLUDE'].split(';') if x]) # notice the 'S'
+ except Exception: pass
+ try: v.prepend_value('LIBPATH', [x for x in self.environ['LIB'].split(';') if x])
+ except Exception: pass
@conf
def msvc_common_flags(conf):
@@ -894,53 +891,62 @@ def msvc_common_flags(conf):
"""
v = conf.env
- v.DEST_BINFMT = 'pe'
+ v['DEST_BINFMT'] = 'pe'
v.append_value('CFLAGS', ['/nologo'])
v.append_value('CXXFLAGS', ['/nologo'])
- v.append_value('LINKFLAGS', ['/nologo'])
- v.DEFINES_ST = '/D%s'
+ v['DEFINES_ST'] = '/D%s'
- v.CC_SRC_F = ''
- v.CC_TGT_F = ['/c', '/Fo']
- v.CXX_SRC_F = ''
- v.CXX_TGT_F = ['/c', '/Fo']
+ v['CC_SRC_F'] = ''
+ v['CC_TGT_F'] = ['/c', '/Fo']
+ v['CXX_SRC_F'] = ''
+ v['CXX_TGT_F'] = ['/c', '/Fo']
if (v.MSVC_COMPILER == 'msvc' and v.MSVC_VERSION >= 8) or (v.MSVC_COMPILER == 'wsdk' and v.MSVC_VERSION >= 6):
- v.CC_TGT_F = ['/FC'] + v.CC_TGT_F
- v.CXX_TGT_F = ['/FC'] + v.CXX_TGT_F
+ v['CC_TGT_F']= ['/FC'] + v['CC_TGT_F']
+ v['CXX_TGT_F']= ['/FC'] + v['CXX_TGT_F']
+
+ v['CPPPATH_ST'] = '/I%s' # template for adding include paths
- v.CPPPATH_ST = '/I%s' # template for adding include paths
+ v['AR_TGT_F'] = v['CCLNK_TGT_F'] = v['CXXLNK_TGT_F'] = '/OUT:'
- v.AR_TGT_F = v.CCLNK_TGT_F = v.CXXLNK_TGT_F = '/OUT:'
+ # Subsystem specific flags
+ v['CFLAGS_CONSOLE'] = v['CXXFLAGS_CONSOLE'] = ['/SUBSYSTEM:CONSOLE']
+ v['CFLAGS_NATIVE'] = v['CXXFLAGS_NATIVE'] = ['/SUBSYSTEM:NATIVE']
+ v['CFLAGS_POSIX'] = v['CXXFLAGS_POSIX'] = ['/SUBSYSTEM:POSIX']
+ v['CFLAGS_WINDOWS'] = v['CXXFLAGS_WINDOWS'] = ['/SUBSYSTEM:WINDOWS']
+ v['CFLAGS_WINDOWSCE'] = v['CXXFLAGS_WINDOWSCE'] = ['/SUBSYSTEM:WINDOWSCE']
# CRT specific flags
- v.CFLAGS_CRT_MULTITHREADED = v.CXXFLAGS_CRT_MULTITHREADED = ['/MT']
- v.CFLAGS_CRT_MULTITHREADED_DLL = v.CXXFLAGS_CRT_MULTITHREADED_DLL = ['/MD']
+ v['CFLAGS_CRT_MULTITHREADED'] = v['CXXFLAGS_CRT_MULTITHREADED'] = ['/MT']
+ v['CFLAGS_CRT_MULTITHREADED_DLL'] = v['CXXFLAGS_CRT_MULTITHREADED_DLL'] = ['/MD']
- v.CFLAGS_CRT_MULTITHREADED_DBG = v.CXXFLAGS_CRT_MULTITHREADED_DBG = ['/MTd']
- v.CFLAGS_CRT_MULTITHREADED_DLL_DBG = v.CXXFLAGS_CRT_MULTITHREADED_DLL_DBG = ['/MDd']
+ v['CFLAGS_CRT_MULTITHREADED_DBG'] = v['CXXFLAGS_CRT_MULTITHREADED_DBG'] = ['/MTd']
+ v['CFLAGS_CRT_MULTITHREADED_DLL_DBG'] = v['CXXFLAGS_CRT_MULTITHREADED_DLL_DBG'] = ['/MDd']
- v.LIB_ST = '%s.lib'
- v.LIBPATH_ST = '/LIBPATH:%s'
- v.STLIB_ST = '%s.lib'
- v.STLIBPATH_ST = '/LIBPATH:%s'
+ # linker
+ v['LIB_ST'] = '%s.lib' # template for adding shared libs
+ v['LIBPATH_ST'] = '/LIBPATH:%s' # template for adding libpaths
+ v['STLIB_ST'] = '%s.lib'
+ v['STLIBPATH_ST'] = '/LIBPATH:%s'
- if v.MSVC_MANIFEST:
+ v.append_value('LINKFLAGS', ['/NOLOGO'])
+ if v['MSVC_MANIFEST']:
v.append_value('LINKFLAGS', ['/MANIFEST'])
- v.CFLAGS_cshlib = []
- v.CXXFLAGS_cxxshlib = []
- v.LINKFLAGS_cshlib = v.LINKFLAGS_cxxshlib = ['/DLL']
- v.cshlib_PATTERN = v.cxxshlib_PATTERN = '%s.dll'
- v.implib_PATTERN = '%s.lib'
- v.IMPLIB_ST = '/IMPLIB:%s'
-
- v.LINKFLAGS_cstlib = []
- v.cstlib_PATTERN = v.cxxstlib_PATTERN = '%s.lib'
+ # shared library
+ v['CFLAGS_cshlib'] = []
+ v['CXXFLAGS_cxxshlib'] = []
+ v['LINKFLAGS_cshlib'] = v['LINKFLAGS_cxxshlib'] = ['/DLL']
+ v['cshlib_PATTERN'] = v['cxxshlib_PATTERN'] = '%s.dll'
+ v['implib_PATTERN'] = '%s.lib'
+ v['IMPLIB_ST'] = '/IMPLIB:%s'
- v.cprogram_PATTERN = v.cxxprogram_PATTERN = '%s.exe'
+ # static library
+ v['LINKFLAGS_cstlib'] = []
+ v['cstlib_PATTERN'] = v['cxxstlib_PATTERN'] = '%s.lib'
- v.def_PATTERN = '/def:%s'
+ # program
+ v['cprogram_PATTERN'] = v['cxxprogram_PATTERN'] = '%s.exe'
#######################################################################################################
@@ -974,10 +980,12 @@ def apply_flags_msvc(self):
self.link_task.outputs.append(pdbnode)
if getattr(self, 'install_task', None):
- self.pdb_install_task = self.add_install_files(
- install_to=self.install_task.install_to, install_from=pdbnode)
+ self.pdb_install_task = self.bld.install_files(self.install_task.dest, pdbnode, env=self.env)
+
break
+# split the manifest file processing from the link task, like for the rc processing
+
@feature('cprogram', 'cshlib', 'cxxprogram', 'cxxshlib')
@after_method('apply_link')
def apply_manifest(self):
@@ -987,16 +995,161 @@ def apply_manifest(self):
the manifest file, the binaries are unusable.
See: http://msdn2.microsoft.com/en-us/library/ms235542(VS.80).aspx
"""
+
if self.env.CC_NAME == 'msvc' and self.env.MSVC_MANIFEST and getattr(self, 'link_task', None):
out_node = self.link_task.outputs[0]
man_node = out_node.parent.find_or_declare(out_node.name + '.manifest')
self.link_task.outputs.append(man_node)
- self.env.DO_MANIFEST = True
+ self.link_task.do_manifest = True
+
+def exec_mf(self):
+ """
+ Create the manifest file
+ """
+ env = self.env
+ mtool = env['MT']
+ if not mtool:
+ return 0
+
+ self.do_manifest = False
+
+ outfile = self.outputs[0].abspath()
+
+ manifest = None
+ for out_node in self.outputs:
+ if out_node.name.endswith('.manifest'):
+ manifest = out_node.abspath()
+ break
+ if manifest is None:
+ # Should never get here. If we do, it means the manifest file was
+ # never added to the outputs list, thus we don't have a manifest file
+ # to embed, so we just return.
+ return 0
+
+ # embedding mode. Different for EXE's and DLL's.
+ # see: http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx
+ mode = ''
+ if 'cprogram' in self.generator.features or 'cxxprogram' in self.generator.features:
+ mode = '1'
+ elif 'cshlib' in self.generator.features or 'cxxshlib' in self.generator.features:
+ mode = '2'
+
+ debug('msvc: embedding manifest in mode %r' % mode)
+
+ lst = [] + mtool
+ lst.extend(Utils.to_list(env['MTFLAGS']))
+ lst.extend(['-manifest', manifest])
+ lst.append('-outputresource:%s;%s' % (outfile, mode))
+
+ return self.exec_command(lst)
+
+def quote_response_command(self, flag):
+ if flag.find(' ') > -1:
+ for x in ('/LIBPATH:', '/IMPLIB:', '/OUT:', '/I'):
+ if flag.startswith(x):
+ flag = '%s"%s"' % (x, flag[len(x):])
+ break
+ else:
+ flag = '"%s"' % flag
+ return flag
+
+def exec_response_command(self, cmd, **kw):
+ # not public yet
+ try:
+ tmp = None
+ if sys.platform.startswith('win') and isinstance(cmd, list) and len(' '.join(cmd)) >= 8192:
+ program = cmd[0] #unquoted program name, otherwise exec_command will fail
+ cmd = [self.quote_response_command(x) for x in cmd]
+ (fd, tmp) = tempfile.mkstemp()
+ os.write(fd, '\r\n'.join(i.replace('\\', '\\\\') for i in cmd[1:]).encode())
+ os.close(fd)
+ cmd = [program, '@' + tmp]
+ # no return here, that's on purpose
+ ret = self.generator.bld.exec_command(cmd, **kw)
+ finally:
+ if tmp:
+ try:
+ os.remove(tmp)
+ except OSError:
+ pass # anti-virus and indexers can keep the files open -_-
+ return ret
+
+########## stupid evil command modification: concatenate the tokens /Fx, /doc, and /x: with the next token
+
+def exec_command_msvc(self, *k, **kw):
+ """
+ Change the command-line execution for msvc programs.
+ Instead of quoting all the paths and keep using the shell, we can just join the options msvc is interested in
+ """
+ if isinstance(k[0], list):
+ lst = []
+ carry = ''
+ for a in k[0]:
+ if a == '/Fo' or a == '/doc' or a[-1] == ':':
+ carry = a
+ else:
+ lst.append(carry + a)
+ carry = ''
+ k = [lst]
+
+ if self.env['PATH']:
+ env = dict(self.env.env or os.environ)
+ env.update(PATH = ';'.join(self.env['PATH']))
+ kw['env'] = env
+
+ bld = self.generator.bld
+ try:
+ if not kw.get('cwd', None):
+ kw['cwd'] = bld.cwd
+ except AttributeError:
+ bld.cwd = kw['cwd'] = bld.variant_dir
+
+ ret = self.exec_response_command(k[0], **kw)
+ if not ret and getattr(self, 'do_manifest', None):
+ ret = self.exec_mf()
+ return ret
+
+def wrap_class(class_name):
+ """
+ Manifest file processing and @response file workaround for command-line length limits on Windows systems
+ The indicated task class is replaced by a subclass to prevent conflicts in case the class is wrapped more than once
+ """
+ cls = Task.classes.get(class_name, None)
+
+ if not cls:
+ return None
+
+ derived_class = type(class_name, (cls,), {})
+
+ def exec_command(self, *k, **kw):
+ if self.env['CC_NAME'] == 'msvc':
+ return self.exec_command_msvc(*k, **kw)
+ else:
+ return super(derived_class, self).exec_command(*k, **kw)
+
+ # Chain-up monkeypatch needed since exec_command() is in base class API
+ derived_class.exec_command = exec_command
+
+ # No chain-up behavior needed since the following methods aren't in
+ # base class API
+ derived_class.exec_response_command = exec_response_command
+ derived_class.quote_response_command = quote_response_command
+ derived_class.exec_command_msvc = exec_command_msvc
+ derived_class.exec_mf = exec_mf
+
+ if hasattr(cls, 'hcode'):
+ derived_class.hcode = cls.hcode
+
+ return derived_class
+
+for k in 'c cxx cprogram cxxprogram cshlib cxxshlib cstlib cxxstlib'.split():
+ wrap_class(k)
def make_winapp(self, family):
append = self.env.append_unique
append('DEFINES', 'WINAPI_FAMILY=%s' % family)
- append('CXXFLAGS', ['/ZW', '/TP'])
+ append('CXXFLAGS', '/ZW')
+ append('CXXFLAGS', '/TP')
for lib_path in self.env.LIBPATH:
append('CXXFLAGS','/AI%s'%lib_path)
@@ -1008,7 +1161,9 @@ def make_winphone_app(self):
Insert configuration flags for windows phone applications (adds /ZW, /TP...)
"""
make_winapp(self, 'WINAPI_FAMILY_PHONE_APP')
- self.env.append_unique('LINKFLAGS', ['/NODEFAULTLIB:ole32.lib', 'PhoneAppModelHost.lib'])
+ conf.env.append_unique('LINKFLAGS', '/NODEFAULTLIB:ole32.lib')
+ conf.env.append_unique('LINKFLAGS', 'PhoneAppModelHost.lib')
+
@feature('winapp')
@after_method('process_use')