3 # Carlos Rafael Giani, 2006 (dv)
4 # Tamas Pal, 2007 (folti)
5 # Nicolas Mercier, 2009
9 Microsoft Visual C++/Intel C++ compiler support
11 If you get detection problems, first try any of the following::
14 set PYTHONIOENCODING=...
15 set PYTHONLEGACYWINDOWSSTDIO=1
19 $ waf configure --msvc_version="msvc 10.0,msvc 9.0" --msvc_target="x64"
24 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']
25 conf.env.MSVC_TARGETS = ['x64']
31 conf.load('msvc', funs='no_autodetect')
32 conf.check_lib_msvc('gdi32')
33 conf.check_libs_msvc('kernel32 user32')
35 tg = bld.program(source='main.c', target='app', use='KERNEL32 USER32 GDI32')
37 Platforms and targets will be tested in the order they appear;
38 the first good configuration will be used.
40 To force testing all the configurations that are not used, use the ``--no-msvc-lazy`` option
41 or set ``conf.env.MSVC_LAZY_AUTODETECT=False``.
43 Supported platforms: ia64, x64, x86, x86_amd64, x86_ia64, x86_arm, amd64_x86, amd64_arm
47 * msvc => Visual Studio, versions 6.0 (VC 98, VC .NET 2002) to 15 (Visual Studio 2017)
48 * wsdk => Windows SDK, versions 6.0, 6.1, 7.0, 7.1, 8.0
49 * icl => Intel compiler, versions 9, 10, 11, 13
50 * winphone => Visual Studio to target Windows Phone 8 native (version 8.0 for now)
51 * Smartphone => Compiler/SDK for Smartphone devices (armv4/v4i)
52 * PocketPC => Compiler/SDK for PocketPC devices (armv4/v4i)
54 To use WAF in a VS2008 Make file project (see http://code.google.com/p/waf/issues/detail?id=894)
55 You may consider to set the environment variable "VS_UNICODE_OUTPUT" to nothing before calling waf.
56 So in your project settings use something like 'cmd.exe /C "set VS_UNICODE_OUTPUT=& set PYTHONUNBUFFERED=true & waf build"'.
57 cmd.exe /C "chcp 1252 & set PYTHONUNBUFFERED=true && set && waf configure"
58 Setting PYTHONUNBUFFERED gives the unbuffered output.
61 import os, sys, re, traceback
62 from waflib import Utils, Logs, Options, Errors
63 from waflib.TaskGen import after_method, feature
65 from waflib.Configure import conf
66 from waflib.Tools import ccroot, c, cxx, ar
68 g_msvc_systemlibs = '''
69 aclui activeds ad1 adptif adsiid advapi32 asycfilt authz bhsupp bits bufferoverflowu cabinet
70 cap certadm certidl ciuuid clusapi comctl32 comdlg32 comsupp comsuppd comsuppw comsuppwd comsvcs
71 credui crypt32 cryptnet cryptui d3d8thk daouuid dbgeng dbghelp dciman32 ddao35 ddao35d
72 ddao35u ddao35ud delayimp dhcpcsvc dhcpsapi dlcapi dnsapi dsprop dsuiext dtchelp
73 faultrep fcachdll fci fdi framedyd framedyn gdi32 gdiplus glauxglu32 gpedit gpmuuid
74 gtrts32w gtrtst32hlink htmlhelp httpapi icm32 icmui imagehlp imm32 iphlpapi iprop
75 kernel32 ksguid ksproxy ksuser libcmt libcmtd libcpmt libcpmtd loadperf lz32 mapi
76 mapi32 mgmtapi minidump mmc mobsync mpr mprapi mqoa mqrt msacm32 mscms mscoree
77 msdasc msimg32 msrating mstask msvcmrt msvcurt msvcurtd mswsock msxml2 mtx mtxdm
78 netapi32 nmapinmsupp npptools ntdsapi ntdsbcli ntmsapi ntquery odbc32 odbcbcp
79 odbccp32 oldnames ole32 oleacc oleaut32 oledb oledlgolepro32 opends60 opengl32
80 osptk parser pdh penter pgobootrun pgort powrprof psapi ptrustm ptrustmd ptrustu
81 ptrustud qosname rasapi32 rasdlg rassapi resutils riched20 rpcndr rpcns4 rpcrt4 rtm
82 rtutils runtmchk scarddlg scrnsave scrnsavw secur32 sensapi setupapi sfc shell32
83 shfolder shlwapi sisbkup snmpapi sporder srclient sti strsafe svcguid tapi32 thunk32
84 traffic unicows url urlmon user32 userenv usp10 uuid uxtheme vcomp vcompd vdmdbg
85 version vfw32 wbemuuid webpost wiaguid wininet winmm winscard winspool winstrm
86 wintrust wldap32 wmiutils wow32 ws2_32 wsnmp32 wsock32 wst wtsapi32 xaswitch xolehlp
88 """importlibs provided by MSVC/Platform SDK. Do NOT search them"""
90 all_msvc_platforms = [ ('x64', 'amd64'), ('x86', 'x86'), ('ia64', 'ia64'),
91 ('x86_amd64', 'amd64'), ('x86_ia64', 'ia64'), ('x86_arm', 'arm'), ('x86_arm64', 'arm64'),
92 ('amd64_x86', 'x86'), ('amd64_arm', 'arm'), ('amd64_arm64', 'arm64') ]
93 """List of msvc platforms"""
95 all_wince_platforms = [ ('armv4', 'arm'), ('armv4i', 'arm'), ('mipsii', 'mips'), ('mipsii_fp', 'mips'), ('mipsiv', 'mips'), ('mipsiv_fp', 'mips'), ('sh4', 'sh'), ('x86', 'cex86') ]
96 """List of wince platforms"""
98 all_icl_platforms = [ ('intel64', 'amd64'), ('em64t', 'amd64'), ('ia32', 'x86'), ('Itanium', 'ia64')]
99 """List of icl platforms"""
102 opt.add_option('--msvc_version', type='string', help = 'msvc version, eg: "msvc 10.0,msvc 9.0"', default='')
103 opt.add_option('--msvc_targets', type='string', help = 'msvc targets, eg: "x64,arm"', default='')
104 opt.add_option('--no-msvc-lazy', action='store_false', help = 'lazily check msvc target environments', default=True, dest='msvc_lazy')
107 def setup_msvc(conf, versiondict):
109 Checks installed compilers and targets and returns the first combination from the user's
110 options, env, or the global supported lists that checks.
112 :param versiondict: dict(platform -> dict(architecture -> configuration))
113 :type versiondict: dict(string -> dict(string -> target_compiler)
114 :return: the compiler, revision, path, include dirs, library paths and target architecture
115 :rtype: tuple of strings
117 platforms = getattr(Options.options, 'msvc_targets', '').split(',')
118 if platforms == ['']:
119 platforms=Utils.to_list(conf.env.MSVC_TARGETS) or [i for i,j in all_msvc_platforms+all_icl_platforms+all_wince_platforms]
120 desired_versions = getattr(Options.options, 'msvc_version', '').split(',')
121 if desired_versions == ['']:
122 desired_versions = conf.env.MSVC_VERSIONS or list(reversed(sorted(versiondict.keys())))
124 # Override lazy detection by evaluating after the fact.
125 lazy_detect = getattr(Options.options, 'msvc_lazy', True)
126 if conf.env.MSVC_LAZY_AUTODETECT is False:
130 for val in versiondict.values():
131 for arch in list(val.keys()):
136 conf.env.MSVC_INSTALLED_VERSIONS = versiondict
138 for version in desired_versions:
139 Logs.debug('msvc: detecting %r - %r', version, desired_versions)
141 targets = versiondict[version]
146 for arch in platforms:
158 compiler,revision = version.rsplit(' ', 1)
159 return compiler,revision,cfg.bindirs,cfg.incdirs,cfg.libdirs,cfg.cpu
160 conf.fatal('msvc: Impossible to find a valid architecture for building %r - %r' % (desired_versions, list(versiondict.keys())))
163 def get_msvc_version(conf, compiler, version, target, vcvars):
165 Checks that an installed compiler actually runs and uses vcvars to obtain the
166 environment needed by the compiler.
168 :param compiler: compiler type, for looking up the executable name
169 :param version: compiler version, for debugging only
170 :param target: target architecture
171 :param vcvars: batch file to run to check the environment
172 :return: the location of the compiler executable, the location of include dirs, and the library paths
173 :rtype: tuple of strings
175 Logs.debug('msvc: get_msvc_version: %r %r %r', compiler, version, target)
179 except AttributeError:
181 batfile = conf.bldnode.make_node('waf-print-msvc-%d.bat' % conf.msvc_cnt)
182 batfile.write("""@echo off
187 echo INCLUDE=%%INCLUDE%%
188 echo LIB=%%LIB%%;%%LIBPATH%%
189 """ % (vcvars,target))
190 sout = conf.cmd_and_log(['cmd.exe', '/E:on', '/V:on', '/C', batfile.abspath()])
191 lines = sout.splitlines()
196 MSVC_PATH = MSVC_INCDIR = MSVC_LIBDIR = None
198 if line.startswith('PATH='):
200 MSVC_PATH = path.split(';')
201 elif line.startswith('INCLUDE='):
202 MSVC_INCDIR = [i for i in line[8:].split(';') if i]
203 elif line.startswith('LIB='):
204 MSVC_LIBDIR = [i for i in line[4:].split(';') if i]
205 if None in (MSVC_PATH, MSVC_INCDIR, MSVC_LIBDIR):
206 conf.fatal('msvc: Could not find a valid architecture for building (get_msvc_version_3)')
208 # Check if the compiler is usable at all.
209 # The detection may return 64-bit versions even on 32-bit systems, and these would fail to run.
210 env = dict(os.environ)
211 env.update(PATH = path)
212 compiler_name, linker_name, lib_name = _get_prog_names(conf, compiler)
213 cxx = conf.find_program(compiler_name, path_list=MSVC_PATH)
215 # delete CL if exists. because it could contain parameters which can change cl's behaviour rather catastrophically.
220 conf.cmd_and_log(cxx + ['/help'], env=env)
222 st = traceback.format_exc()
224 conf.logger.error(st)
225 conf.fatal('msvc: Unicode error - check the code page?')
226 except Exception as e:
227 Logs.debug('msvc: get_msvc_version: %r %r %r -> failure %s', compiler, version, target, str(e))
228 conf.fatal('msvc: cannot run the compiler in get_msvc_version (run with -v to display errors)')
230 Logs.debug('msvc: get_msvc_version: %r %r %r -> OK', compiler, version, target)
232 conf.env[compiler_name] = ''
234 return (MSVC_PATH, MSVC_INCDIR, MSVC_LIBDIR)
236 def gather_wince_supported_platforms():
238 Checks SmartPhones SDKs
240 :param versions: list to modify
243 supported_wince_platforms = []
245 ce_sdk = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Windows CE Tools\\SDKs')
248 ce_sdk = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows CE Tools\\SDKs')
252 return supported_wince_platforms
257 sdk_device = Utils.winreg.EnumKey(ce_sdk, index)
258 sdk = Utils.winreg.OpenKey(ce_sdk, sdk_device)
263 path,type = Utils.winreg.QueryValueEx(sdk, 'SDKRootDir')
266 path,type = Utils.winreg.QueryValueEx(sdk,'SDKInformation')
269 path,xml = os.path.split(path)
271 path,device = os.path.split(path)
273 path,device = os.path.split(path)
275 for arch,compiler in all_wince_platforms:
276 if os.path.isdir(os.path.join(path, device, 'Lib', arch)):
277 platforms.append((arch, compiler, os.path.join(path, device, 'Include', arch), os.path.join(path, device, 'Lib', arch)))
279 supported_wince_platforms.append((device, platforms))
280 return supported_wince_platforms
282 def gather_msvc_detected_versions():
283 #Detected MSVC versions!
284 version_pattern = re.compile('^(\d\d?\.\d\d?)(Exp)?$')
285 detected_versions = []
286 for vcver,vcvar in (('VCExpress','Exp'), ('VisualStudio','')):
287 prefix = 'SOFTWARE\\Wow6432node\\Microsoft\\' + vcver
289 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, prefix)
291 prefix = 'SOFTWARE\\Microsoft\\' + vcver
293 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, prefix)
300 version = Utils.winreg.EnumKey(all_versions, index)
304 match = version_pattern.match(version)
306 versionnumber = float(match.group(1))
309 detected_versions.append((versionnumber, version+vcvar, prefix+'\\'+version))
313 detected_versions.sort(key = fun)
314 return detected_versions
316 class target_compiler(object):
318 Wrap a compiler configuration; call evaluate() to determine
319 whether the configuration is usable.
321 def __init__(self, ctx, compiler, cpu, version, bat_target, bat, callback=None):
323 :param ctx: configuration context to use to eventually get the version environment
324 :param compiler: compiler name
325 :param cpu: target cpu
326 :param version: compiler version number
328 :param bat: path to the batch file to run
332 self.is_valid = False
335 self.compiler = compiler
337 self.version = version
338 self.bat_target = bat_target
340 self.callback = callback
347 vs = self.conf.get_msvc_version(self.compiler, self.version, self.bat_target, self.bat)
348 except Errors.ConfigurationError:
349 self.is_valid = False
352 vs = self.callback(self, vs)
354 (self.bindirs, self.incdirs, self.libdirs) = vs
357 return str((self.compiler, self.cpu, self.version, self.bat_target, self.bat))
360 return repr((self.compiler, self.cpu, self.version, self.bat_target, self.bat))
363 def gather_wsdk_versions(conf, versions):
365 Use winreg to add the msvc versions to the input list
367 :param versions: list to modify
370 version_pattern = re.compile('^v..?.?\...?.?')
372 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Microsoft SDKs\\Windows')
375 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows')
381 version = Utils.winreg.EnumKey(all_versions, index)
385 if not version_pattern.match(version):
388 msvc_version = Utils.winreg.OpenKey(all_versions, version)
389 path,type = Utils.winreg.QueryValueEx(msvc_version,'InstallationFolder')
392 if path and os.path.isfile(os.path.join(path, 'bin', 'SetEnv.cmd')):
394 for target,arch in all_msvc_platforms:
395 targets[target] = target_compiler(conf, 'wsdk', arch, version, '/'+target, os.path.join(path, 'bin', 'SetEnv.cmd'))
396 versions['wsdk ' + version[1:]] = targets
399 def gather_msvc_targets(conf, versions, version, vc_path):
400 #Looking for normal MSVC compilers!
403 if os.path.isfile(os.path.join(vc_path, 'VC', 'Auxiliary', 'Build', 'vcvarsall.bat')):
404 for target,realtarget in all_msvc_platforms[::-1]:
405 targets[target] = target_compiler(conf, 'msvc', realtarget, version, target, os.path.join(vc_path, 'VC', 'Auxiliary', 'Build', 'vcvarsall.bat'))
406 elif os.path.isfile(os.path.join(vc_path, 'vcvarsall.bat')):
407 for target,realtarget in all_msvc_platforms[::-1]:
408 targets[target] = target_compiler(conf, 'msvc', realtarget, version, target, os.path.join(vc_path, 'vcvarsall.bat'))
409 elif os.path.isfile(os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat')):
410 targets['x86'] = target_compiler(conf, 'msvc', 'x86', version, 'x86', os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat'))
411 elif os.path.isfile(os.path.join(vc_path, 'Bin', 'vcvars32.bat')):
412 targets['x86'] = target_compiler(conf, 'msvc', 'x86', version, '', os.path.join(vc_path, 'Bin', 'vcvars32.bat'))
414 versions['msvc %s' % version] = targets
417 def gather_wince_targets(conf, versions, version, vc_path, vsvars, supported_platforms):
418 #Looking for Win CE compilers!
419 for device,platforms in supported_platforms:
421 for platform,compiler,include,lib in platforms:
422 winCEpath = os.path.join(vc_path, 'ce')
423 if not os.path.isdir(winCEpath):
426 if os.path.isdir(os.path.join(winCEpath, 'lib', platform)):
427 bindirs = [os.path.join(winCEpath, 'bin', compiler), os.path.join(winCEpath, 'bin', 'x86_'+compiler)]
428 incdirs = [os.path.join(winCEpath, 'include'), os.path.join(winCEpath, 'atlmfc', 'include'), include]
429 libdirs = [os.path.join(winCEpath, 'lib', platform), os.path.join(winCEpath, 'atlmfc', 'lib', platform), lib]
430 def combine_common(obj, compiler_env):
431 # TODO this is likely broken, remove in waf 2.1
432 (common_bindirs,_1,_2) = compiler_env
433 return (bindirs + common_bindirs, incdirs, libdirs)
434 targets[platform] = target_compiler(conf, 'msvc', platform, version, 'x86', vsvars, combine_common)
436 versions[device + ' ' + version] = targets
439 def gather_winphone_targets(conf, versions, version, vc_path, vsvars):
440 #Looking for WinPhone compilers
442 for target,realtarget in all_msvc_platforms[::-1]:
443 targets[target] = target_compiler(conf, 'winphone', realtarget, version, target, vsvars)
445 versions['winphone ' + version] = targets
448 def gather_vswhere_versions(conf, versions):
452 Logs.error('Visual Studio 2017 detection requires Python 2.6')
455 prg_path = os.environ.get('ProgramFiles(x86)', os.environ.get('ProgramFiles', 'C:\\Program Files (x86)'))
457 vswhere = os.path.join(prg_path, 'Microsoft Visual Studio', 'Installer', 'vswhere.exe')
458 args = [vswhere, '-products', '*', '-legacy', '-format', 'json']
460 txt = conf.cmd_and_log(args)
461 except Errors.WafError as e:
462 Logs.debug('msvc: vswhere.exe failed %s', e)
465 if sys.version_info[0] < 3:
466 txt = txt.decode(Utils.console_encoding())
468 arr = json.loads(txt)
469 arr.sort(key=lambda x: x['installationVersion'])
471 ver = entry['installationVersion']
472 ver = str('.'.join(ver.split('.')[:2]))
473 path = str(os.path.abspath(entry['installationPath']))
474 if os.path.exists(path) and ('msvc %s' % ver) not in versions:
475 conf.gather_msvc_targets(versions, ver, path)
478 def gather_msvc_versions(conf, versions):
480 for (v,version,reg) in gather_msvc_detected_versions():
483 msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, reg + "\\Setup\\VC")
485 msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, reg + "\\Setup\\Microsoft Visual C++")
486 path,type = Utils.winreg.QueryValueEx(msvc_version, 'ProductDir')
489 msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Wow6432node\\Microsoft\\VisualStudio\\SxS\\VS7")
490 path,type = Utils.winreg.QueryValueEx(msvc_version, version)
494 vc_paths.append((version, os.path.abspath(str(path))))
497 vc_paths.append((version, os.path.abspath(str(path))))
499 wince_supported_platforms = gather_wince_supported_platforms()
501 for version,vc_path in vc_paths:
502 vs_path = os.path.dirname(vc_path)
503 vsvars = os.path.join(vs_path, 'Common7', 'Tools', 'vsvars32.bat')
504 if wince_supported_platforms and os.path.isfile(vsvars):
505 conf.gather_wince_targets(versions, version, vc_path, vsvars, wince_supported_platforms)
507 # WP80 works with 11.0Exp and 11.0, both of which resolve to the same vc_path.
508 # Stop after one is found.
509 for version,vc_path in vc_paths:
510 vs_path = os.path.dirname(vc_path)
511 vsvars = os.path.join(vs_path, 'VC', 'WPSDK', 'WP80', 'vcvarsphoneall.bat')
512 if os.path.isfile(vsvars):
513 conf.gather_winphone_targets(versions, '8.0', vc_path, vsvars)
516 for version,vc_path in vc_paths:
517 vs_path = os.path.dirname(vc_path)
518 conf.gather_msvc_targets(versions, version, vc_path)
521 def gather_icl_versions(conf, versions):
525 :param versions: list to modify
528 version_pattern = re.compile('^...?.?\....?.?')
530 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Compilers\\C++')
533 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Intel\\Compilers\\C++')
539 version = Utils.winreg.EnumKey(all_versions, index)
543 if not version_pattern.match(version):
546 for target,arch in all_icl_platforms:
547 if target=='intel64':
548 targetDir='EM64T_NATIVE'
552 Utils.winreg.OpenKey(all_versions,version+'\\'+targetDir)
553 icl_version=Utils.winreg.OpenKey(all_versions,version)
554 path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir')
558 batch_file=os.path.join(path,'bin','iclvars.bat')
559 if os.path.isfile(batch_file):
560 targets[target] = target_compiler(conf, 'intel', arch, version, target, batch_file)
561 for target,arch in all_icl_platforms:
563 icl_version = Utils.winreg.OpenKey(all_versions, version+'\\'+target)
564 path,type = Utils.winreg.QueryValueEx(icl_version,'ProductDir')
568 batch_file=os.path.join(path,'bin','iclvars.bat')
569 if os.path.isfile(batch_file):
570 targets[target] = target_compiler(conf, 'intel', arch, version, target, batch_file)
572 versions['intel ' + major] = targets
575 def gather_intel_composer_versions(conf, versions):
577 Checks ICL compilers that are part of Intel Composer Suites
579 :param versions: list to modify
582 version_pattern = re.compile('^...?.?\...?.?.?')
584 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Suites')
587 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Intel\\Suites')
593 version = Utils.winreg.EnumKey(all_versions, index)
597 if not version_pattern.match(version):
600 for target,arch in all_icl_platforms:
601 if target=='intel64':
602 targetDir='EM64T_NATIVE'
607 defaults = Utils.winreg.OpenKey(all_versions,version+'\\Defaults\\C++\\'+targetDir)
609 if targetDir == 'EM64T_NATIVE':
610 defaults = Utils.winreg.OpenKey(all_versions,version+'\\Defaults\\C++\\EM64T')
613 uid,type = Utils.winreg.QueryValueEx(defaults, 'SubKey')
614 Utils.winreg.OpenKey(all_versions,version+'\\'+uid+'\\C++\\'+targetDir)
615 icl_version=Utils.winreg.OpenKey(all_versions,version+'\\'+uid+'\\C++')
616 path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir')
620 batch_file=os.path.join(path,'bin','iclvars.bat')
621 if os.path.isfile(batch_file):
622 targets[target] = target_compiler(conf, 'intel', arch, version, target, batch_file)
623 # The intel compilervar_arch.bat is broken when used with Visual Studio Express 2012
624 # http://software.intel.com/en-us/forums/topic/328487
625 compilervars_warning_attr = '_compilervars_warning_key'
626 if version[0:2] == '13' and getattr(conf, compilervars_warning_attr, True):
627 setattr(conf, compilervars_warning_attr, False)
628 patch_url = 'http://software.intel.com/en-us/forums/topic/328487'
629 compilervars_arch = os.path.join(path, 'bin', 'compilervars_arch.bat')
630 for vscomntool in ('VS110COMNTOOLS', 'VS100COMNTOOLS'):
631 if vscomntool in os.environ:
632 vs_express_path = os.environ[vscomntool] + r'..\IDE\VSWinExpress.exe'
633 dev_env_path = os.environ[vscomntool] + r'..\IDE\devenv.exe'
634 if (r'if exist "%VS110COMNTOOLS%..\IDE\VSWinExpress.exe"' in Utils.readf(compilervars_arch) and
635 not os.path.exists(vs_express_path) and not os.path.exists(dev_env_path)):
636 Logs.warn(('The Intel compilervar_arch.bat only checks for one Visual Studio SKU '
637 '(VSWinExpress.exe) but it does not seem to be installed at %r. '
638 'The intel command line set up will fail to configure unless the file %r'
639 'is patched. See: %s') % (vs_express_path, compilervars_arch, patch_url))
641 versions['intel ' + major] = targets
644 def detect_msvc(self):
645 return self.setup_msvc(self.get_msvc_versions())
648 def get_msvc_versions(self):
650 :return: platform to compiler configurations
653 dct = Utils.ordered_iter_dict()
654 self.gather_icl_versions(dct)
655 self.gather_intel_composer_versions(dct)
656 self.gather_wsdk_versions(dct)
657 self.gather_msvc_versions(dct)
658 self.gather_vswhere_versions(dct)
659 Logs.debug('msvc: detected versions %r', list(dct.keys()))
663 def find_lt_names_msvc(self, libname, is_static=False):
665 Win32/MSVC specific code to glean out information from libtool la files.
666 this function is not attached to the task_gen class. Returns a triplet:
667 (library absolute path, library name without extension, whether the library is static)
670 'lib%s.la' % libname,
674 for path in self.env.LIBPATH:
676 laf=os.path.join(path,la)
678 if os.path.exists(laf):
679 ltdict = Utils.read_la_file(laf)
681 if ltdict.get('libdir', ''):
682 lt_libdir = ltdict['libdir']
683 if not is_static and ltdict.get('library_names', ''):
684 dllnames=ltdict['library_names'].split()
685 dll=dllnames[0].lower()
686 dll=re.sub('\.dll$', '', dll)
687 return (lt_libdir, dll, False)
688 elif ltdict.get('old_library', ''):
689 olib=ltdict['old_library']
690 if os.path.exists(os.path.join(path,olib)):
691 return (path, olib, True)
692 elif lt_libdir != '' and os.path.exists(os.path.join(lt_libdir,olib)):
693 return (lt_libdir, olib, True)
695 return (None, olib, True)
697 raise self.errors.WafError('invalid libtool object file: %s' % laf)
698 return (None, None, None)
701 def libname_msvc(self, libname, is_static=False):
702 lib = libname.lower()
703 lib = re.sub('\.lib$','',lib)
705 if lib in g_msvc_systemlibs:
708 lib=re.sub('^lib','',lib)
713 (lt_path, lt_libname, lt_static) = self.find_lt_names_msvc(lib, is_static)
715 if lt_path != None and lt_libname != None:
717 # file existence check has been made by find_lt_names
718 return os.path.join(lt_path,lt_libname)
721 _libpaths = [lt_path] + self.env.LIBPATH
723 _libpaths = self.env.LIBPATH
733 'lib%s.dll.lib' % lib,
744 libnames=dynamic_libs + static_libs
746 for path in _libpaths:
747 for libn in libnames:
748 if os.path.exists(os.path.join(path, libn)):
749 Logs.debug('msvc: lib found: %s', os.path.join(path,libn))
750 return re.sub('\.lib$', '',libn)
752 #if no lib can be found, just return the libname as msvc expects it
753 self.fatal('The library %r could not be found' % libname)
754 return re.sub('\.lib$', '', libname)
757 def check_lib_msvc(self, libname, is_static=False, uselib_store=None):
759 Ideally we should be able to place the lib in the right env var, either STLIB or LIB,
760 but we don't distinguish static libs from shared libs.
761 This is ok since msvc doesn't have any special linker flag to select static libs (no env.STLIB_MARKER)
763 libn = self.libname_msvc(libname, is_static)
766 uselib_store = libname.upper()
768 if False and is_static: # disabled
769 self.env['STLIB_' + uselib_store] = [libn]
771 self.env['LIB_' + uselib_store] = [libn]
774 def check_libs_msvc(self, libnames, is_static=False):
775 for libname in Utils.to_list(libnames):
776 self.check_lib_msvc(libname, is_static)
780 Configuration methods to call for detecting msvc
782 conf.autodetect(True)
784 conf.msvc_common_flags()
786 conf.cxx_load_tools()
789 conf.link_add_flags()
790 conf.visual_studio_add_flags()
793 def no_autodetect(conf):
794 conf.env.NO_MSVC_DETECT = 1
798 def autodetect(conf, arch=False):
803 compiler, version, path, includes, libdirs, cpu = conf.detect_msvc()
808 v.INCLUDES = includes
810 v.MSVC_COMPILER = compiler
812 v.MSVC_VERSION = float(version)
814 v.MSVC_VERSION = float(version[:-3])
816 def _get_prog_names(conf, compiler):
817 if compiler == 'intel':
818 compiler_name = 'ICL'
819 linker_name = 'XILINK'
826 return compiler_name, linker_name, lib_name
830 """Due to path format limitations, limit operation only to native Win32. Yeah it sucks."""
831 if sys.platform == 'cygwin':
832 conf.fatal('MSVC module does not work under cygwin Python!')
834 # the autodetection is supposed to be performed before entering in this method
837 compiler = v.MSVC_COMPILER
838 version = v.MSVC_VERSION
840 compiler_name, linker_name, lib_name = _get_prog_names(conf, compiler)
841 v.MSVC_MANIFEST = (compiler == 'msvc' and version >= 8) or (compiler == 'wsdk' and version >= 6) or (compiler == 'intel' and version >= 11)
844 cxx = conf.find_program(compiler_name, var='CXX', path_list=path)
846 # before setting anything, check if the compiler is really msvc
847 env = dict(conf.environ)
849 env.update(PATH = ';'.join(path))
850 if not conf.cmd_and_log(cxx + ['/nologo', '/help'], env=env):
851 conf.fatal('the msvc compiler could not be identified')
855 v.CC_NAME = v.CXX_NAME = 'msvc'
859 conf.find_program(linker_name, path_list=path, errmsg='%s was not found (linker)' % linker_name, var='LINK_CXX')
862 v.LINK_CC = v.LINK_CXX
866 stliblink = conf.find_program(lib_name, path_list=path, var='AR')
869 v.ARFLAGS = ['/nologo']
871 # manifest tool. Not required for VS 2003 and below. Must have for VS 2005 and later
873 conf.find_program('MT', path_list=path, var='MT')
874 v.MTFLAGS = ['/nologo']
878 except Errors.ConfigurationError:
879 Logs.warn('Resource compiler not found. Compiling resource file is disabled')
882 def visual_studio_add_flags(self):
883 """visual studio flags found in the system environment"""
885 if self.environ.get('INCLUDE'):
886 v.prepend_value('INCLUDES', [x for x in self.environ['INCLUDE'].split(';') if x]) # notice the 'S'
887 if self.environ.get('LIB'):
888 v.prepend_value('LIBPATH', [x for x in self.environ['LIB'].split(';') if x])
891 def msvc_common_flags(conf):
893 Setup the flags required for executing the msvc compiler
898 v.append_value('CFLAGS', ['/nologo'])
899 v.append_value('CXXFLAGS', ['/nologo'])
900 v.append_value('LINKFLAGS', ['/nologo'])
901 v.DEFINES_ST = '/D%s'
904 v.CC_TGT_F = ['/c', '/Fo']
906 v.CXX_TGT_F = ['/c', '/Fo']
908 if (v.MSVC_COMPILER == 'msvc' and v.MSVC_VERSION >= 8) or (v.MSVC_COMPILER == 'wsdk' and v.MSVC_VERSION >= 6):
909 v.CC_TGT_F = ['/FC'] + v.CC_TGT_F
910 v.CXX_TGT_F = ['/FC'] + v.CXX_TGT_F
912 v.CPPPATH_ST = '/I%s' # template for adding include paths
914 v.AR_TGT_F = v.CCLNK_TGT_F = v.CXXLNK_TGT_F = '/OUT:'
917 v.CFLAGS_CRT_MULTITHREADED = v.CXXFLAGS_CRT_MULTITHREADED = ['/MT']
918 v.CFLAGS_CRT_MULTITHREADED_DLL = v.CXXFLAGS_CRT_MULTITHREADED_DLL = ['/MD']
920 v.CFLAGS_CRT_MULTITHREADED_DBG = v.CXXFLAGS_CRT_MULTITHREADED_DBG = ['/MTd']
921 v.CFLAGS_CRT_MULTITHREADED_DLL_DBG = v.CXXFLAGS_CRT_MULTITHREADED_DLL_DBG = ['/MDd']
924 v.LIBPATH_ST = '/LIBPATH:%s'
925 v.STLIB_ST = '%s.lib'
926 v.STLIBPATH_ST = '/LIBPATH:%s'
929 v.append_value('LINKFLAGS', ['/MANIFEST'])
932 v.CXXFLAGS_cxxshlib = []
933 v.LINKFLAGS_cshlib = v.LINKFLAGS_cxxshlib = ['/DLL']
934 v.cshlib_PATTERN = v.cxxshlib_PATTERN = '%s.dll'
935 v.implib_PATTERN = '%s.lib'
936 v.IMPLIB_ST = '/IMPLIB:%s'
938 v.LINKFLAGS_cstlib = []
939 v.cstlib_PATTERN = v.cxxstlib_PATTERN = '%s.lib'
941 v.cprogram_PATTERN = v.cxxprogram_PATTERN = '%s.exe'
943 v.def_PATTERN = '/def:%s'
946 #######################################################################################################
947 ##### conf above, build below
949 @after_method('apply_link')
951 def apply_flags_msvc(self):
953 Add additional flags implied by msvc, such as subsystems and pdb files::
956 bld.stlib(source='main.c', target='bar', subsystem='gruik')
958 if self.env.CC_NAME != 'msvc' or not getattr(self, 'link_task', None):
961 is_static = isinstance(self.link_task, ccroot.stlink_task)
963 subsystem = getattr(self, 'subsystem', '')
965 subsystem = '/subsystem:%s' % subsystem
966 flags = is_static and 'ARFLAGS' or 'LINKFLAGS'
967 self.env.append_value(flags, subsystem)
970 for f in self.env.LINKFLAGS:
973 pdbnode = self.link_task.outputs[0].change_ext('.pdb')
974 self.link_task.outputs.append(pdbnode)
976 if getattr(self, 'install_task', None):
977 self.pdb_install_task = self.add_install_files(
978 install_to=self.install_task.install_to, install_from=pdbnode)
981 @feature('cprogram', 'cshlib', 'cxxprogram', 'cxxshlib')
982 @after_method('apply_link')
983 def apply_manifest(self):
985 Special linker for MSVC with support for embedding manifests into DLL's
986 and executables compiled by Visual Studio 2005 or probably later. Without
987 the manifest file, the binaries are unusable.
988 See: http://msdn2.microsoft.com/en-us/library/ms235542(VS.80).aspx
990 if self.env.CC_NAME == 'msvc' and self.env.MSVC_MANIFEST and getattr(self, 'link_task', None):
991 out_node = self.link_task.outputs[0]
992 man_node = out_node.parent.find_or_declare(out_node.name + '.manifest')
993 self.link_task.outputs.append(man_node)
994 self.env.DO_MANIFEST = True
996 def make_winapp(self, family):
997 append = self.env.append_unique
998 append('DEFINES', 'WINAPI_FAMILY=%s' % family)
999 append('CXXFLAGS', ['/ZW', '/TP'])
1000 for lib_path in self.env.LIBPATH:
1001 append('CXXFLAGS','/AI%s'%lib_path)
1003 @feature('winphoneapp')
1004 @after_method('process_use')
1005 @after_method('propagate_uselib_vars')
1006 def make_winphone_app(self):
1008 Insert configuration flags for windows phone applications (adds /ZW, /TP...)
1010 make_winapp(self, 'WINAPI_FAMILY_PHONE_APP')
1011 self.env.append_unique('LINKFLAGS', ['/NODEFAULTLIB:ole32.lib', 'PhoneAppModelHost.lib'])
1014 @after_method('process_use')
1015 @after_method('propagate_uselib_vars')
1016 def make_windows_app(self):
1018 Insert configuration flags for windows applications (adds /ZW, /TP...)
1020 make_winapp(self, 'WINAPI_FAMILY_DESKTOP_APP')