diff options
Diffstat (limited to 'waflib/Tools/msvc.py')
-rw-r--r-- | waflib/Tools/msvc.py | 869 |
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') |