1#!/usr/bin/env python 2# encoding: utf-8 3# Carlos Rafael Giani, 2006 (dv) 4# Tamas Pal, 2007 (folti) 5# Nicolas Mercier, 2009 6# Matt Clarkson, 2012 7 8""" 9Microsoft Visual C++/Intel C++ compiler support 10 11If you get detection problems, first try any of the following:: 12 13 chcp 65001 14 set PYTHONIOENCODING=... 15 set PYTHONLEGACYWINDOWSSTDIO=1 16 17Usage:: 18 19 $ waf configure --msvc_version="msvc 10.0,msvc 9.0" --msvc_target="x64" 20 21or:: 22 23 def configure(conf): 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'] 26 conf.load('msvc') 27 28or:: 29 30 def configure(conf): 31 conf.load('msvc', funs='no_autodetect') 32 conf.check_lib_msvc('gdi32') 33 conf.check_libs_msvc('kernel32 user32') 34 def build(bld): 35 tg = bld.program(source='main.c', target='app', use='KERNEL32 USER32 GDI32') 36 37Platforms and targets will be tested in the order they appear; 38the first good configuration will be used. 39 40To force testing all the configurations that are not used, use the ``--no-msvc-lazy`` option 41or set ``conf.env.MSVC_LAZY_AUTODETECT=False``. 42 43Supported platforms: ia64, x64, x86, x86_amd64, x86_ia64, x86_arm, amd64_x86, amd64_arm 44 45Compilers supported: 46 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) 53 54To use WAF in a VS2008 Make file project (see http://code.google.com/p/waf/issues/detail?id=894) 55You may consider to set the environment variable "VS_UNICODE_OUTPUT" to nothing before calling waf. 56So in your project settings use something like 'cmd.exe /C "set VS_UNICODE_OUTPUT=& set PYTHONUNBUFFERED=true & waf build"'. 57cmd.exe /C "chcp 1252 & set PYTHONUNBUFFERED=true && set && waf configure" 58Setting PYTHONUNBUFFERED gives the unbuffered output. 59""" 60 61import os, sys, re, traceback 62from waflib import Utils, Logs, Options, Errors 63from waflib.TaskGen import after_method, feature 64 65from waflib.Configure import conf 66from waflib.Tools import ccroot, c, cxx, ar 67 68g_msvc_systemlibs = ''' 69aclui activeds ad1 adptif adsiid advapi32 asycfilt authz bhsupp bits bufferoverflowu cabinet 70cap certadm certidl ciuuid clusapi comctl32 comdlg32 comsupp comsuppd comsuppw comsuppwd comsvcs 71credui crypt32 cryptnet cryptui d3d8thk daouuid dbgeng dbghelp dciman32 ddao35 ddao35d 72ddao35u ddao35ud delayimp dhcpcsvc dhcpsapi dlcapi dnsapi dsprop dsuiext dtchelp 73faultrep fcachdll fci fdi framedyd framedyn gdi32 gdiplus glauxglu32 gpedit gpmuuid 74gtrts32w gtrtst32hlink htmlhelp httpapi icm32 icmui imagehlp imm32 iphlpapi iprop 75kernel32 ksguid ksproxy ksuser libcmt libcmtd libcpmt libcpmtd loadperf lz32 mapi 76mapi32 mgmtapi minidump mmc mobsync mpr mprapi mqoa mqrt msacm32 mscms mscoree 77msdasc msimg32 msrating mstask msvcmrt msvcurt msvcurtd mswsock msxml2 mtx mtxdm 78netapi32 nmapinmsupp npptools ntdsapi ntdsbcli ntmsapi ntquery odbc32 odbcbcp 79odbccp32 oldnames ole32 oleacc oleaut32 oledb oledlgolepro32 opends60 opengl32 80osptk parser pdh penter pgobootrun pgort powrprof psapi ptrustm ptrustmd ptrustu 81ptrustud qosname rasapi32 rasdlg rassapi resutils riched20 rpcndr rpcns4 rpcrt4 rtm 82rtutils runtmchk scarddlg scrnsave scrnsavw secur32 sensapi setupapi sfc shell32 83shfolder shlwapi sisbkup snmpapi sporder srclient sti strsafe svcguid tapi32 thunk32 84traffic unicows url urlmon user32 userenv usp10 uuid uxtheme vcomp vcompd vdmdbg 85version vfw32 wbemuuid webpost wiaguid wininet winmm winscard winspool winstrm 86wintrust wldap32 wmiutils wow32 ws2_32 wsnmp32 wsock32 wst wtsapi32 xaswitch xolehlp 87'''.split() 88"""importlibs provided by MSVC/Platform SDK. Do NOT search them""" 89 90all_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""" 94 95all_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""" 97 98all_icl_platforms = [ ('intel64', 'amd64'), ('em64t', 'amd64'), ('ia32', 'x86'), ('Itanium', 'ia64')] 99"""List of icl platforms""" 100 101def options(opt): 102 default_ver = '' 103 vsver = os.getenv('VSCMD_VER') 104 if vsver: 105 m = re.match(r'(^\d+\.\d+).*', vsver) 106 if m: 107 default_ver = 'msvc %s' % m.group(1) 108 opt.add_option('--msvc_version', type='string', help = 'msvc version, eg: "msvc 10.0,msvc 9.0"', default=default_ver) 109 opt.add_option('--msvc_targets', type='string', help = 'msvc targets, eg: "x64,arm"', default='') 110 opt.add_option('--no-msvc-lazy', action='store_false', help = 'lazily check msvc target environments', default=True, dest='msvc_lazy') 111 112@conf 113def setup_msvc(conf, versiondict): 114 """ 115 Checks installed compilers and targets and returns the first combination from the user's 116 options, env, or the global supported lists that checks. 117 118 :param versiondict: dict(platform -> dict(architecture -> configuration)) 119 :type versiondict: dict(string -> dict(string -> target_compiler) 120 :return: the compiler, revision, path, include dirs, library paths and target architecture 121 :rtype: tuple of strings 122 """ 123 platforms = getattr(Options.options, 'msvc_targets', '').split(',') 124 if platforms == ['']: 125 platforms=Utils.to_list(conf.env.MSVC_TARGETS) or [i for i,j in all_msvc_platforms+all_icl_platforms+all_wince_platforms] 126 desired_versions = getattr(Options.options, 'msvc_version', '').split(',') 127 if desired_versions == ['']: 128 desired_versions = conf.env.MSVC_VERSIONS or list(reversed(sorted(versiondict.keys()))) 129 130 # Override lazy detection by evaluating after the fact. 131 lazy_detect = getattr(Options.options, 'msvc_lazy', True) 132 if conf.env.MSVC_LAZY_AUTODETECT is False: 133 lazy_detect = False 134 135 if not lazy_detect: 136 for val in versiondict.values(): 137 for arch in list(val.keys()): 138 cfg = val[arch] 139 cfg.evaluate() 140 if not cfg.is_valid: 141 del val[arch] 142 conf.env.MSVC_INSTALLED_VERSIONS = versiondict 143 144 for version in desired_versions: 145 Logs.debug('msvc: detecting %r - %r', version, desired_versions) 146 try: 147 targets = versiondict[version] 148 except KeyError: 149 continue 150 151 seen = set() 152 for arch in platforms: 153 if arch in seen: 154 continue 155 else: 156 seen.add(arch) 157 try: 158 cfg = targets[arch] 159 except KeyError: 160 continue 161 162 cfg.evaluate() 163 if cfg.is_valid: 164 compiler,revision = version.rsplit(' ', 1) 165 return compiler,revision,cfg.bindirs,cfg.incdirs,cfg.libdirs,cfg.cpu 166 conf.fatal('msvc: Impossible to find a valid architecture for building %r - %r' % (desired_versions, list(versiondict.keys()))) 167 168@conf 169def get_msvc_version(conf, compiler, version, target, vcvars): 170 """ 171 Checks that an installed compiler actually runs and uses vcvars to obtain the 172 environment needed by the compiler. 173 174 :param compiler: compiler type, for looking up the executable name 175 :param version: compiler version, for debugging only 176 :param target: target architecture 177 :param vcvars: batch file to run to check the environment 178 :return: the location of the compiler executable, the location of include dirs, and the library paths 179 :rtype: tuple of strings 180 """ 181 Logs.debug('msvc: get_msvc_version: %r %r %r', compiler, version, target) 182 183 try: 184 conf.msvc_cnt += 1 185 except AttributeError: 186 conf.msvc_cnt = 1 187 batfile = conf.bldnode.make_node('waf-print-msvc-%d.bat' % conf.msvc_cnt) 188 batfile.write("""@echo off 189set INCLUDE= 190set LIB= 191call "%s" %s 192echo PATH=%%PATH%% 193echo INCLUDE=%%INCLUDE%% 194echo LIB=%%LIB%%;%%LIBPATH%% 195""" % (vcvars,target)) 196 sout = conf.cmd_and_log(['cmd.exe', '/E:on', '/V:on', '/C', batfile.abspath()]) 197 lines = sout.splitlines() 198 199 if not lines[0]: 200 lines.pop(0) 201 202 MSVC_PATH = MSVC_INCDIR = MSVC_LIBDIR = None 203 for line in lines: 204 if line.startswith('PATH='): 205 path = line[5:] 206 MSVC_PATH = path.split(';') 207 elif line.startswith('INCLUDE='): 208 MSVC_INCDIR = [i for i in line[8:].split(';') if i] 209 elif line.startswith('LIB='): 210 MSVC_LIBDIR = [i for i in line[4:].split(';') if i] 211 if None in (MSVC_PATH, MSVC_INCDIR, MSVC_LIBDIR): 212 conf.fatal('msvc: Could not find a valid architecture for building (get_msvc_version_3)') 213 214 # Check if the compiler is usable at all. 215 # The detection may return 64-bit versions even on 32-bit systems, and these would fail to run. 216 env = dict(os.environ) 217 env.update(PATH = path) 218 compiler_name, linker_name, lib_name = _get_prog_names(conf, compiler) 219 cxx = conf.find_program(compiler_name, path_list=MSVC_PATH) 220 221 # delete CL if exists. because it could contain parameters which can change cl's behaviour rather catastrophically. 222 if 'CL' in env: 223 del(env['CL']) 224 225 try: 226 conf.cmd_and_log(cxx + ['/help'], env=env) 227 except UnicodeError: 228 st = traceback.format_exc() 229 if conf.logger: 230 conf.logger.error(st) 231 conf.fatal('msvc: Unicode error - check the code page?') 232 except Exception as e: 233 Logs.debug('msvc: get_msvc_version: %r %r %r -> failure %s', compiler, version, target, str(e)) 234 conf.fatal('msvc: cannot run the compiler in get_msvc_version (run with -v to display errors)') 235 else: 236 Logs.debug('msvc: get_msvc_version: %r %r %r -> OK', compiler, version, target) 237 finally: 238 conf.env[compiler_name] = '' 239 240 return (MSVC_PATH, MSVC_INCDIR, MSVC_LIBDIR) 241 242def gather_wince_supported_platforms(): 243 """ 244 Checks SmartPhones SDKs 245 246 :param versions: list to modify 247 :type versions: list 248 """ 249 supported_wince_platforms = [] 250 try: 251 ce_sdk = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Windows CE Tools\\SDKs') 252 except OSError: 253 try: 254 ce_sdk = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows CE Tools\\SDKs') 255 except OSError: 256 ce_sdk = '' 257 if not ce_sdk: 258 return supported_wince_platforms 259 260 index = 0 261 while 1: 262 try: 263 sdk_device = Utils.winreg.EnumKey(ce_sdk, index) 264 sdk = Utils.winreg.OpenKey(ce_sdk, sdk_device) 265 except OSError: 266 break 267 index += 1 268 try: 269 path,type = Utils.winreg.QueryValueEx(sdk, 'SDKRootDir') 270 except OSError: 271 try: 272 path,type = Utils.winreg.QueryValueEx(sdk,'SDKInformation') 273 except OSError: 274 continue 275 path,xml = os.path.split(path) 276 path = str(path) 277 path,device = os.path.split(path) 278 if not device: 279 path,device = os.path.split(path) 280 platforms = [] 281 for arch,compiler in all_wince_platforms: 282 if os.path.isdir(os.path.join(path, device, 'Lib', arch)): 283 platforms.append((arch, compiler, os.path.join(path, device, 'Include', arch), os.path.join(path, device, 'Lib', arch))) 284 if platforms: 285 supported_wince_platforms.append((device, platforms)) 286 return supported_wince_platforms 287 288def gather_msvc_detected_versions(): 289 #Detected MSVC versions! 290 version_pattern = re.compile(r'^(\d\d?\.\d\d?)(Exp)?$') 291 detected_versions = [] 292 for vcver,vcvar in (('VCExpress','Exp'), ('VisualStudio','')): 293 prefix = 'SOFTWARE\\Wow6432node\\Microsoft\\' + vcver 294 try: 295 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, prefix) 296 except OSError: 297 prefix = 'SOFTWARE\\Microsoft\\' + vcver 298 try: 299 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, prefix) 300 except OSError: 301 continue 302 303 index = 0 304 while 1: 305 try: 306 version = Utils.winreg.EnumKey(all_versions, index) 307 except OSError: 308 break 309 index += 1 310 match = version_pattern.match(version) 311 if match: 312 versionnumber = float(match.group(1)) 313 else: 314 continue 315 detected_versions.append((versionnumber, version+vcvar, prefix+'\\'+version)) 316 def fun(tup): 317 return tup[0] 318 319 detected_versions.sort(key = fun) 320 return detected_versions 321 322class target_compiler(object): 323 """ 324 Wrap a compiler configuration; call evaluate() to determine 325 whether the configuration is usable. 326 """ 327 def __init__(self, ctx, compiler, cpu, version, bat_target, bat, callback=None): 328 """ 329 :param ctx: configuration context to use to eventually get the version environment 330 :param compiler: compiler name 331 :param cpu: target cpu 332 :param version: compiler version number 333 :param bat_target: ? 334 :param bat: path to the batch file to run 335 """ 336 self.conf = ctx 337 self.name = None 338 self.is_valid = False 339 self.is_done = False 340 341 self.compiler = compiler 342 self.cpu = cpu 343 self.version = version 344 self.bat_target = bat_target 345 self.bat = bat 346 self.callback = callback 347 348 def evaluate(self): 349 if self.is_done: 350 return 351 self.is_done = True 352 try: 353 vs = self.conf.get_msvc_version(self.compiler, self.version, self.bat_target, self.bat) 354 except Errors.ConfigurationError: 355 self.is_valid = False 356 return 357 if self.callback: 358 vs = self.callback(self, vs) 359 self.is_valid = True 360 (self.bindirs, self.incdirs, self.libdirs) = vs 361 362 def __str__(self): 363 return str((self.compiler, self.cpu, self.version, self.bat_target, self.bat)) 364 365 def __repr__(self): 366 return repr((self.compiler, self.cpu, self.version, self.bat_target, self.bat)) 367 368@conf 369def gather_wsdk_versions(conf, versions): 370 """ 371 Use winreg to add the msvc versions to the input list 372 373 :param versions: list to modify 374 :type versions: list 375 """ 376 version_pattern = re.compile(r'^v..?.?\...?.?') 377 try: 378 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Microsoft SDKs\\Windows') 379 except OSError: 380 try: 381 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows') 382 except OSError: 383 return 384 index = 0 385 while 1: 386 try: 387 version = Utils.winreg.EnumKey(all_versions, index) 388 except OSError: 389 break 390 index += 1 391 if not version_pattern.match(version): 392 continue 393 try: 394 msvc_version = Utils.winreg.OpenKey(all_versions, version) 395 path,type = Utils.winreg.QueryValueEx(msvc_version,'InstallationFolder') 396 except OSError: 397 continue 398 if path and os.path.isfile(os.path.join(path, 'bin', 'SetEnv.cmd')): 399 targets = {} 400 for target,arch in all_msvc_platforms: 401 targets[target] = target_compiler(conf, 'wsdk', arch, version, '/'+target, os.path.join(path, 'bin', 'SetEnv.cmd')) 402 versions['wsdk ' + version[1:]] = targets 403 404@conf 405def gather_msvc_targets(conf, versions, version, vc_path): 406 #Looking for normal MSVC compilers! 407 targets = {} 408 409 if os.path.isfile(os.path.join(vc_path, 'VC', 'Auxiliary', 'Build', 'vcvarsall.bat')): 410 for target,realtarget in all_msvc_platforms[::-1]: 411 targets[target] = target_compiler(conf, 'msvc', realtarget, version, target, os.path.join(vc_path, 'VC', 'Auxiliary', 'Build', 'vcvarsall.bat')) 412 elif os.path.isfile(os.path.join(vc_path, 'vcvarsall.bat')): 413 for target,realtarget in all_msvc_platforms[::-1]: 414 targets[target] = target_compiler(conf, 'msvc', realtarget, version, target, os.path.join(vc_path, 'vcvarsall.bat')) 415 elif os.path.isfile(os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat')): 416 targets['x86'] = target_compiler(conf, 'msvc', 'x86', version, 'x86', os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat')) 417 elif os.path.isfile(os.path.join(vc_path, 'Bin', 'vcvars32.bat')): 418 targets['x86'] = target_compiler(conf, 'msvc', 'x86', version, '', os.path.join(vc_path, 'Bin', 'vcvars32.bat')) 419 if targets: 420 versions['msvc %s' % version] = targets 421 422@conf 423def gather_wince_targets(conf, versions, version, vc_path, vsvars, supported_platforms): 424 #Looking for Win CE compilers! 425 for device,platforms in supported_platforms: 426 targets = {} 427 for platform,compiler,include,lib in platforms: 428 winCEpath = os.path.join(vc_path, 'ce') 429 if not os.path.isdir(winCEpath): 430 continue 431 432 if os.path.isdir(os.path.join(winCEpath, 'lib', platform)): 433 bindirs = [os.path.join(winCEpath, 'bin', compiler), os.path.join(winCEpath, 'bin', 'x86_'+compiler)] 434 incdirs = [os.path.join(winCEpath, 'include'), os.path.join(winCEpath, 'atlmfc', 'include'), include] 435 libdirs = [os.path.join(winCEpath, 'lib', platform), os.path.join(winCEpath, 'atlmfc', 'lib', platform), lib] 436 def combine_common(obj, compiler_env): 437 # TODO this is likely broken, remove in waf 2.1 438 (common_bindirs,_1,_2) = compiler_env 439 return (bindirs + common_bindirs, incdirs, libdirs) 440 targets[platform] = target_compiler(conf, 'msvc', platform, version, 'x86', vsvars, combine_common) 441 if targets: 442 versions[device + ' ' + version] = targets 443 444@conf 445def gather_winphone_targets(conf, versions, version, vc_path, vsvars): 446 #Looking for WinPhone compilers 447 targets = {} 448 for target,realtarget in all_msvc_platforms[::-1]: 449 targets[target] = target_compiler(conf, 'winphone', realtarget, version, target, vsvars) 450 if targets: 451 versions['winphone ' + version] = targets 452 453@conf 454def gather_vswhere_versions(conf, versions): 455 try: 456 import json 457 except ImportError: 458 Logs.error('Visual Studio 2017 detection requires Python 2.6') 459 return 460 461 prg_path = os.environ.get('ProgramFiles(x86)', os.environ.get('ProgramFiles', 'C:\\Program Files (x86)')) 462 463 vswhere = os.path.join(prg_path, 'Microsoft Visual Studio', 'Installer', 'vswhere.exe') 464 args = [vswhere, '-products', '*', '-legacy', '-format', 'json'] 465 try: 466 txt = conf.cmd_and_log(args) 467 except Errors.WafError as e: 468 Logs.debug('msvc: vswhere.exe failed %s', e) 469 return 470 471 if sys.version_info[0] < 3: 472 txt = txt.decode(Utils.console_encoding()) 473 474 arr = json.loads(txt) 475 arr.sort(key=lambda x: x['installationVersion']) 476 for entry in arr: 477 ver = entry['installationVersion'] 478 ver = str('.'.join(ver.split('.')[:2])) 479 path = str(os.path.abspath(entry['installationPath'])) 480 if os.path.exists(path) and ('msvc %s' % ver) not in versions: 481 conf.gather_msvc_targets(versions, ver, path) 482 483@conf 484def gather_msvc_versions(conf, versions): 485 vc_paths = [] 486 for (v,version,reg) in gather_msvc_detected_versions(): 487 try: 488 try: 489 msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, reg + "\\Setup\\VC") 490 except OSError: 491 msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, reg + "\\Setup\\Microsoft Visual C++") 492 path,type = Utils.winreg.QueryValueEx(msvc_version, 'ProductDir') 493 except OSError: 494 try: 495 msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Wow6432node\\Microsoft\\VisualStudio\\SxS\\VS7") 496 path,type = Utils.winreg.QueryValueEx(msvc_version, version) 497 except OSError: 498 continue 499 else: 500 vc_paths.append((version, os.path.abspath(str(path)))) 501 continue 502 else: 503 vc_paths.append((version, os.path.abspath(str(path)))) 504 505 wince_supported_platforms = gather_wince_supported_platforms() 506 507 for version,vc_path in vc_paths: 508 vs_path = os.path.dirname(vc_path) 509 vsvars = os.path.join(vs_path, 'Common7', 'Tools', 'vsvars32.bat') 510 if wince_supported_platforms and os.path.isfile(vsvars): 511 conf.gather_wince_targets(versions, version, vc_path, vsvars, wince_supported_platforms) 512 513 # WP80 works with 11.0Exp and 11.0, both of which resolve to the same vc_path. 514 # Stop after one is found. 515 for version,vc_path in vc_paths: 516 vs_path = os.path.dirname(vc_path) 517 vsvars = os.path.join(vs_path, 'VC', 'WPSDK', 'WP80', 'vcvarsphoneall.bat') 518 if os.path.isfile(vsvars): 519 conf.gather_winphone_targets(versions, '8.0', vc_path, vsvars) 520 break 521 522 for version,vc_path in vc_paths: 523 vs_path = os.path.dirname(vc_path) 524 conf.gather_msvc_targets(versions, version, vc_path) 525 526@conf 527def gather_icl_versions(conf, versions): 528 """ 529 Checks ICL compilers 530 531 :param versions: list to modify 532 :type versions: list 533 """ 534 version_pattern = re.compile(r'^...?.?\....?.?') 535 try: 536 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Compilers\\C++') 537 except OSError: 538 try: 539 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Intel\\Compilers\\C++') 540 except OSError: 541 return 542 index = 0 543 while 1: 544 try: 545 version = Utils.winreg.EnumKey(all_versions, index) 546 except OSError: 547 break 548 index += 1 549 if not version_pattern.match(version): 550 continue 551 targets = {} 552 for target,arch in all_icl_platforms: 553 if target=='intel64': 554 targetDir='EM64T_NATIVE' 555 else: 556 targetDir=target 557 try: 558 Utils.winreg.OpenKey(all_versions,version+'\\'+targetDir) 559 icl_version=Utils.winreg.OpenKey(all_versions,version) 560 path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir') 561 except OSError: 562 pass 563 else: 564 batch_file=os.path.join(path,'bin','iclvars.bat') 565 if os.path.isfile(batch_file): 566 targets[target] = target_compiler(conf, 'intel', arch, version, target, batch_file) 567 for target,arch in all_icl_platforms: 568 try: 569 icl_version = Utils.winreg.OpenKey(all_versions, version+'\\'+target) 570 path,type = Utils.winreg.QueryValueEx(icl_version,'ProductDir') 571 except OSError: 572 continue 573 else: 574 batch_file=os.path.join(path,'bin','iclvars.bat') 575 if os.path.isfile(batch_file): 576 targets[target] = target_compiler(conf, 'intel', arch, version, target, batch_file) 577 major = version[0:2] 578 versions['intel ' + major] = targets 579 580@conf 581def gather_intel_composer_versions(conf, versions): 582 """ 583 Checks ICL compilers that are part of Intel Composer Suites 584 585 :param versions: list to modify 586 :type versions: list 587 """ 588 version_pattern = re.compile(r'^...?.?\...?.?.?') 589 try: 590 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Suites') 591 except OSError: 592 try: 593 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Intel\\Suites') 594 except OSError: 595 return 596 index = 0 597 while 1: 598 try: 599 version = Utils.winreg.EnumKey(all_versions, index) 600 except OSError: 601 break 602 index += 1 603 if not version_pattern.match(version): 604 continue 605 targets = {} 606 for target,arch in all_icl_platforms: 607 if target=='intel64': 608 targetDir='EM64T_NATIVE' 609 else: 610 targetDir=target 611 try: 612 try: 613 defaults = Utils.winreg.OpenKey(all_versions,version+'\\Defaults\\C++\\'+targetDir) 614 except OSError: 615 if targetDir == 'EM64T_NATIVE': 616 defaults = Utils.winreg.OpenKey(all_versions,version+'\\Defaults\\C++\\EM64T') 617 else: 618 raise 619 uid,type = Utils.winreg.QueryValueEx(defaults, 'SubKey') 620 Utils.winreg.OpenKey(all_versions,version+'\\'+uid+'\\C++\\'+targetDir) 621 icl_version=Utils.winreg.OpenKey(all_versions,version+'\\'+uid+'\\C++') 622 path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir') 623 except OSError: 624 pass 625 else: 626 batch_file=os.path.join(path,'bin','iclvars.bat') 627 if os.path.isfile(batch_file): 628 targets[target] = target_compiler(conf, 'intel', arch, version, target, batch_file) 629 # The intel compilervar_arch.bat is broken when used with Visual Studio Express 2012 630 # http://software.intel.com/en-us/forums/topic/328487 631 compilervars_warning_attr = '_compilervars_warning_key' 632 if version[0:2] == '13' and getattr(conf, compilervars_warning_attr, True): 633 setattr(conf, compilervars_warning_attr, False) 634 patch_url = 'http://software.intel.com/en-us/forums/topic/328487' 635 compilervars_arch = os.path.join(path, 'bin', 'compilervars_arch.bat') 636 for vscomntool in ('VS110COMNTOOLS', 'VS100COMNTOOLS'): 637 if vscomntool in os.environ: 638 vs_express_path = os.environ[vscomntool] + r'..\IDE\VSWinExpress.exe' 639 dev_env_path = os.environ[vscomntool] + r'..\IDE\devenv.exe' 640 if (r'if exist "%VS110COMNTOOLS%..\IDE\VSWinExpress.exe"' in Utils.readf(compilervars_arch) and 641 not os.path.exists(vs_express_path) and not os.path.exists(dev_env_path)): 642 Logs.warn(('The Intel compilervar_arch.bat only checks for one Visual Studio SKU ' 643 '(VSWinExpress.exe) but it does not seem to be installed at %r. ' 644 'The intel command line set up will fail to configure unless the file %r' 645 'is patched. See: %s') % (vs_express_path, compilervars_arch, patch_url)) 646 major = version[0:2] 647 versions['intel ' + major] = targets 648 649@conf 650def detect_msvc(self): 651 return self.setup_msvc(self.get_msvc_versions()) 652 653@conf 654def get_msvc_versions(self): 655 """ 656 :return: platform to compiler configurations 657 :rtype: dict 658 """ 659 dct = Utils.ordered_iter_dict() 660 self.gather_icl_versions(dct) 661 self.gather_intel_composer_versions(dct) 662 self.gather_wsdk_versions(dct) 663 self.gather_msvc_versions(dct) 664 self.gather_vswhere_versions(dct) 665 Logs.debug('msvc: detected versions %r', list(dct.keys())) 666 return dct 667 668@conf 669def find_lt_names_msvc(self, libname, is_static=False): 670 """ 671 Win32/MSVC specific code to glean out information from libtool la files. 672 this function is not attached to the task_gen class. Returns a triplet: 673 (library absolute path, library name without extension, whether the library is static) 674 """ 675 lt_names=[ 676 'lib%s.la' % libname, 677 '%s.la' % libname, 678 ] 679 680 for path in self.env.LIBPATH: 681 for la in lt_names: 682 laf=os.path.join(path,la) 683 dll=None 684 if os.path.exists(laf): 685 ltdict = Utils.read_la_file(laf) 686 lt_libdir=None 687 if ltdict.get('libdir', ''): 688 lt_libdir = ltdict['libdir'] 689 if not is_static and ltdict.get('library_names', ''): 690 dllnames=ltdict['library_names'].split() 691 dll=dllnames[0].lower() 692 dll=re.sub(r'\.dll$', '', dll) 693 return (lt_libdir, dll, False) 694 elif ltdict.get('old_library', ''): 695 olib=ltdict['old_library'] 696 if os.path.exists(os.path.join(path,olib)): 697 return (path, olib, True) 698 elif lt_libdir != '' and os.path.exists(os.path.join(lt_libdir,olib)): 699 return (lt_libdir, olib, True) 700 else: 701 return (None, olib, True) 702 else: 703 raise self.errors.WafError('invalid libtool object file: %s' % laf) 704 return (None, None, None) 705 706@conf 707def libname_msvc(self, libname, is_static=False): 708 lib = libname.lower() 709 lib = re.sub(r'\.lib$','',lib) 710 711 if lib in g_msvc_systemlibs: 712 return lib 713 714 lib=re.sub('^lib','',lib) 715 716 if lib == 'm': 717 return None 718 719 (lt_path, lt_libname, lt_static) = self.find_lt_names_msvc(lib, is_static) 720 721 if lt_path != None and lt_libname != None: 722 if lt_static: 723 # file existence check has been made by find_lt_names 724 return os.path.join(lt_path,lt_libname) 725 726 if lt_path != None: 727 _libpaths = [lt_path] + self.env.LIBPATH 728 else: 729 _libpaths = self.env.LIBPATH 730 731 static_libs=[ 732 'lib%ss.lib' % lib, 733 'lib%s.lib' % lib, 734 '%ss.lib' % lib, 735 '%s.lib' %lib, 736 ] 737 738 dynamic_libs=[ 739 'lib%s.dll.lib' % lib, 740 'lib%s.dll.a' % lib, 741 '%s.dll.lib' % lib, 742 '%s.dll.a' % lib, 743 'lib%s_d.lib' % lib, 744 '%s_d.lib' % lib, 745 '%s.lib' %lib, 746 ] 747 748 libnames=static_libs 749 if not is_static: 750 libnames=dynamic_libs + static_libs 751 752 for path in _libpaths: 753 for libn in libnames: 754 if os.path.exists(os.path.join(path, libn)): 755 Logs.debug('msvc: lib found: %s', os.path.join(path,libn)) 756 return re.sub(r'\.lib$', '',libn) 757 758 #if no lib can be found, just return the libname as msvc expects it 759 self.fatal('The library %r could not be found' % libname) 760 return re.sub(r'\.lib$', '', libname) 761 762@conf 763def check_lib_msvc(self, libname, is_static=False, uselib_store=None): 764 """ 765 Ideally we should be able to place the lib in the right env var, either STLIB or LIB, 766 but we don't distinguish static libs from shared libs. 767 This is ok since msvc doesn't have any special linker flag to select static libs (no env.STLIB_MARKER) 768 """ 769 libn = self.libname_msvc(libname, is_static) 770 771 if not uselib_store: 772 uselib_store = libname.upper() 773 774 if False and is_static: # disabled 775 self.env['STLIB_' + uselib_store] = [libn] 776 else: 777 self.env['LIB_' + uselib_store] = [libn] 778 779@conf 780def check_libs_msvc(self, libnames, is_static=False): 781 for libname in Utils.to_list(libnames): 782 self.check_lib_msvc(libname, is_static) 783 784def configure(conf): 785 """ 786 Configuration methods to call for detecting msvc 787 """ 788 conf.autodetect(True) 789 conf.find_msvc() 790 conf.msvc_common_flags() 791 conf.cc_load_tools() 792 conf.cxx_load_tools() 793 conf.cc_add_flags() 794 conf.cxx_add_flags() 795 conf.link_add_flags() 796 conf.visual_studio_add_flags() 797 798@conf 799def no_autodetect(conf): 800 conf.env.NO_MSVC_DETECT = 1 801 configure(conf) 802 803@conf 804def autodetect(conf, arch=False): 805 v = conf.env 806 if v.NO_MSVC_DETECT: 807 return 808 809 compiler, version, path, includes, libdirs, cpu = conf.detect_msvc() 810 if arch: 811 v.DEST_CPU = cpu 812 813 v.PATH = path 814 v.INCLUDES = includes 815 v.LIBPATH = libdirs 816 v.MSVC_COMPILER = compiler 817 try: 818 v.MSVC_VERSION = float(version) 819 except ValueError: 820 v.MSVC_VERSION = float(version[:-3]) 821 822def _get_prog_names(conf, compiler): 823 if compiler == 'intel': 824 compiler_name = 'ICL' 825 linker_name = 'XILINK' 826 lib_name = 'XILIB' 827 else: 828 # assumes CL.exe 829 compiler_name = 'CL' 830 linker_name = 'LINK' 831 lib_name = 'LIB' 832 return compiler_name, linker_name, lib_name 833 834@conf 835def find_msvc(conf): 836 """Due to path format limitations, limit operation only to native Win32. Yeah it sucks.""" 837 if sys.platform == 'cygwin': 838 conf.fatal('MSVC module does not work under cygwin Python!') 839 840 # the autodetection is supposed to be performed before entering in this method 841 v = conf.env 842 path = v.PATH 843 compiler = v.MSVC_COMPILER 844 version = v.MSVC_VERSION 845 846 compiler_name, linker_name, lib_name = _get_prog_names(conf, compiler) 847 v.MSVC_MANIFEST = (compiler == 'msvc' and version >= 8) or (compiler == 'wsdk' and version >= 6) or (compiler == 'intel' and version >= 11) 848 849 # compiler 850 cxx = conf.find_program(compiler_name, var='CXX', path_list=path) 851 852 # before setting anything, check if the compiler is really msvc 853 env = dict(conf.environ) 854 if path: 855 env.update(PATH = ';'.join(path)) 856 if not conf.cmd_and_log(cxx + ['/nologo', '/help'], env=env): 857 conf.fatal('the msvc compiler could not be identified') 858 859 # c/c++ compiler 860 v.CC = v.CXX = cxx 861 v.CC_NAME = v.CXX_NAME = 'msvc' 862 863 # linker 864 if not v.LINK_CXX: 865 conf.find_program(linker_name, path_list=path, errmsg='%s was not found (linker)' % linker_name, var='LINK_CXX') 866 867 if not v.LINK_CC: 868 v.LINK_CC = v.LINK_CXX 869 870 # staticlib linker 871 if not v.AR: 872 stliblink = conf.find_program(lib_name, path_list=path, var='AR') 873 if not stliblink: 874 return 875 v.ARFLAGS = ['/nologo'] 876 877 # manifest tool. Not required for VS 2003 and below. Must have for VS 2005 and later 878 if v.MSVC_MANIFEST: 879 conf.find_program('MT', path_list=path, var='MT') 880 v.MTFLAGS = ['/nologo'] 881 882 try: 883 conf.load('winres') 884 except Errors.ConfigurationError: 885 Logs.warn('Resource compiler not found. Compiling resource file is disabled') 886 887@conf 888def visual_studio_add_flags(self): 889 """visual studio flags found in the system environment""" 890 v = self.env 891 if self.environ.get('INCLUDE'): 892 v.prepend_value('INCLUDES', [x for x in self.environ['INCLUDE'].split(';') if x]) # notice the 'S' 893 if self.environ.get('LIB'): 894 v.prepend_value('LIBPATH', [x for x in self.environ['LIB'].split(';') if x]) 895 896@conf 897def msvc_common_flags(conf): 898 """ 899 Setup the flags required for executing the msvc compiler 900 """ 901 v = conf.env 902 903 v.DEST_BINFMT = 'pe' 904 v.append_value('CFLAGS', ['/nologo']) 905 v.append_value('CXXFLAGS', ['/nologo']) 906 v.append_value('LINKFLAGS', ['/nologo']) 907 v.DEFINES_ST = '/D%s' 908 909 v.CC_SRC_F = '' 910 v.CC_TGT_F = ['/c', '/Fo'] 911 v.CXX_SRC_F = '' 912 v.CXX_TGT_F = ['/c', '/Fo'] 913 914 if (v.MSVC_COMPILER == 'msvc' and v.MSVC_VERSION >= 8) or (v.MSVC_COMPILER == 'wsdk' and v.MSVC_VERSION >= 6): 915 v.CC_TGT_F = ['/FC'] + v.CC_TGT_F 916 v.CXX_TGT_F = ['/FC'] + v.CXX_TGT_F 917 918 v.CPPPATH_ST = '/I%s' # template for adding include paths 919 920 v.AR_TGT_F = v.CCLNK_TGT_F = v.CXXLNK_TGT_F = '/OUT:' 921 922 # CRT specific flags 923 v.CFLAGS_CRT_MULTITHREADED = v.CXXFLAGS_CRT_MULTITHREADED = ['/MT'] 924 v.CFLAGS_CRT_MULTITHREADED_DLL = v.CXXFLAGS_CRT_MULTITHREADED_DLL = ['/MD'] 925 926 v.CFLAGS_CRT_MULTITHREADED_DBG = v.CXXFLAGS_CRT_MULTITHREADED_DBG = ['/MTd'] 927 v.CFLAGS_CRT_MULTITHREADED_DLL_DBG = v.CXXFLAGS_CRT_MULTITHREADED_DLL_DBG = ['/MDd'] 928 929 v.LIB_ST = '%s.lib' 930 v.LIBPATH_ST = '/LIBPATH:%s' 931 v.STLIB_ST = '%s.lib' 932 v.STLIBPATH_ST = '/LIBPATH:%s' 933 934 if v.MSVC_MANIFEST: 935 v.append_value('LINKFLAGS', ['/MANIFEST']) 936 937 v.CFLAGS_cshlib = [] 938 v.CXXFLAGS_cxxshlib = [] 939 v.LINKFLAGS_cshlib = v.LINKFLAGS_cxxshlib = ['/DLL'] 940 v.cshlib_PATTERN = v.cxxshlib_PATTERN = '%s.dll' 941 v.implib_PATTERN = '%s.lib' 942 v.IMPLIB_ST = '/IMPLIB:%s' 943 944 v.LINKFLAGS_cstlib = [] 945 v.cstlib_PATTERN = v.cxxstlib_PATTERN = '%s.lib' 946 947 v.cprogram_PATTERN = v.cxxprogram_PATTERN = '%s.exe' 948 949 v.def_PATTERN = '/def:%s' 950 951 952####################################################################################################### 953##### conf above, build below 954 955@after_method('apply_link') 956@feature('c', 'cxx') 957def apply_flags_msvc(self): 958 """ 959 Add additional flags implied by msvc, such as subsystems and pdb files:: 960 961 def build(bld): 962 bld.stlib(source='main.c', target='bar', subsystem='gruik') 963 """ 964 if self.env.CC_NAME != 'msvc' or not getattr(self, 'link_task', None): 965 return 966 967 is_static = isinstance(self.link_task, ccroot.stlink_task) 968 969 subsystem = getattr(self, 'subsystem', '') 970 if subsystem: 971 subsystem = '/subsystem:%s' % subsystem 972 flags = is_static and 'ARFLAGS' or 'LINKFLAGS' 973 self.env.append_value(flags, subsystem) 974 975 if not is_static: 976 for f in self.env.LINKFLAGS: 977 d = f.lower() 978 if d[1:] in ('debug', 'debug:full', 'debug:fastlink'): 979 pdbnode = self.link_task.outputs[0].change_ext('.pdb') 980 self.link_task.outputs.append(pdbnode) 981 982 if getattr(self, 'install_task', None): 983 self.pdb_install_task = self.add_install_files( 984 install_to=self.install_task.install_to, install_from=pdbnode) 985 break 986 987@feature('cprogram', 'cshlib', 'cxxprogram', 'cxxshlib') 988@after_method('apply_link') 989def apply_manifest(self): 990 """ 991 Special linker for MSVC with support for embedding manifests into DLL's 992 and executables compiled by Visual Studio 2005 or probably later. Without 993 the manifest file, the binaries are unusable. 994 See: http://msdn2.microsoft.com/en-us/library/ms235542(VS.80).aspx 995 """ 996 if self.env.CC_NAME == 'msvc' and self.env.MSVC_MANIFEST and getattr(self, 'link_task', None): 997 out_node = self.link_task.outputs[0] 998 man_node = out_node.parent.find_or_declare(out_node.name + '.manifest') 999 self.link_task.outputs.append(man_node) 1000 self.env.DO_MANIFEST = True 1001 1002def make_winapp(self, family): 1003 append = self.env.append_unique 1004 append('DEFINES', 'WINAPI_FAMILY=%s' % family) 1005 append('CXXFLAGS', ['/ZW', '/TP']) 1006 for lib_path in self.env.LIBPATH: 1007 append('CXXFLAGS','/AI%s'%lib_path) 1008 1009@feature('winphoneapp') 1010@after_method('process_use') 1011@after_method('propagate_uselib_vars') 1012def make_winphone_app(self): 1013 """ 1014 Insert configuration flags for windows phone applications (adds /ZW, /TP...) 1015 """ 1016 make_winapp(self, 'WINAPI_FAMILY_PHONE_APP') 1017 self.env.append_unique('LINKFLAGS', ['/NODEFAULTLIB:ole32.lib', 'PhoneAppModelHost.lib']) 1018 1019@feature('winapp') 1020@after_method('process_use') 1021@after_method('propagate_uselib_vars') 1022def make_windows_app(self): 1023 """ 1024 Insert configuration flags for windows applications (adds /ZW, /TP...) 1025 """ 1026 make_winapp(self, 'WINAPI_FAMILY_DESKTOP_APP') 1027