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 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') 105 106@conf 107def setup_msvc(conf, versiondict): 108 """ 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. 111 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 116 """ 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()))) 123 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: 127 lazy_detect = False 128 129 if not lazy_detect: 130 for val in versiondict.values(): 131 for arch in list(val.keys()): 132 cfg = val[arch] 133 cfg.evaluate() 134 if not cfg.is_valid: 135 del val[arch] 136 conf.env.MSVC_INSTALLED_VERSIONS = versiondict 137 138 for version in desired_versions: 139 Logs.debug('msvc: detecting %r - %r', version, desired_versions) 140 try: 141 targets = versiondict[version] 142 except KeyError: 143 continue 144 145 seen = set() 146 for arch in platforms: 147 if arch in seen: 148 continue 149 else: 150 seen.add(arch) 151 try: 152 cfg = targets[arch] 153 except KeyError: 154 continue 155 156 cfg.evaluate() 157 if cfg.is_valid: 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()))) 161 162@conf 163def get_msvc_version(conf, compiler, version, target, vcvars): 164 """ 165 Checks that an installed compiler actually runs and uses vcvars to obtain the 166 environment needed by the compiler. 167 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 174 """ 175 Logs.debug('msvc: get_msvc_version: %r %r %r', compiler, version, target) 176 177 try: 178 conf.msvc_cnt += 1 179 except AttributeError: 180 conf.msvc_cnt = 1 181 batfile = conf.bldnode.make_node('waf-print-msvc-%d.bat' % conf.msvc_cnt) 182 batfile.write("""@echo off 183set INCLUDE= 184set LIB= 185call "%s" %s 186echo PATH=%%PATH%% 187echo INCLUDE=%%INCLUDE%% 188echo 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() 192 193 if not lines[0]: 194 lines.pop(0) 195 196 MSVC_PATH = MSVC_INCDIR = MSVC_LIBDIR = None 197 for line in lines: 198 if line.startswith('PATH='): 199 path = line[5:] 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)') 207 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) 214 215 # delete CL if exists. because it could contain parameters which can change cl's behaviour rather catastrophically. 216 if 'CL' in env: 217 del(env['CL']) 218 219 try: 220 conf.cmd_and_log(cxx + ['/help'], env=env) 221 except UnicodeError: 222 st = traceback.format_exc() 223 if conf.logger: 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)') 229 else: 230 Logs.debug('msvc: get_msvc_version: %r %r %r -> OK', compiler, version, target) 231 finally: 232 conf.env[compiler_name] = '' 233 234 return (MSVC_PATH, MSVC_INCDIR, MSVC_LIBDIR) 235 236def gather_wince_supported_platforms(): 237 """ 238 Checks SmartPhones SDKs 239 240 :param versions: list to modify 241 :type versions: list 242 """ 243 supported_wince_platforms = [] 244 try: 245 ce_sdk = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Windows CE Tools\\SDKs') 246 except OSError: 247 try: 248 ce_sdk = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows CE Tools\\SDKs') 249 except OSError: 250 ce_sdk = '' 251 if not ce_sdk: 252 return supported_wince_platforms 253 254 index = 0 255 while 1: 256 try: 257 sdk_device = Utils.winreg.EnumKey(ce_sdk, index) 258 sdk = Utils.winreg.OpenKey(ce_sdk, sdk_device) 259 except OSError: 260 break 261 index += 1 262 try: 263 path,type = Utils.winreg.QueryValueEx(sdk, 'SDKRootDir') 264 except OSError: 265 try: 266 path,type = Utils.winreg.QueryValueEx(sdk,'SDKInformation') 267 except OSError: 268 continue 269 path,xml = os.path.split(path) 270 path = str(path) 271 path,device = os.path.split(path) 272 if not device: 273 path,device = os.path.split(path) 274 platforms = [] 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))) 278 if platforms: 279 supported_wince_platforms.append((device, platforms)) 280 return supported_wince_platforms 281 282def 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 288 try: 289 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, prefix) 290 except OSError: 291 prefix = 'SOFTWARE\\Microsoft\\' + vcver 292 try: 293 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, prefix) 294 except OSError: 295 continue 296 297 index = 0 298 while 1: 299 try: 300 version = Utils.winreg.EnumKey(all_versions, index) 301 except OSError: 302 break 303 index += 1 304 match = version_pattern.match(version) 305 if match: 306 versionnumber = float(match.group(1)) 307 else: 308 continue 309 detected_versions.append((versionnumber, version+vcvar, prefix+'\\'+version)) 310 def fun(tup): 311 return tup[0] 312 313 detected_versions.sort(key = fun) 314 return detected_versions 315 316class target_compiler(object): 317 """ 318 Wrap a compiler configuration; call evaluate() to determine 319 whether the configuration is usable. 320 """ 321 def __init__(self, ctx, compiler, cpu, version, bat_target, bat, callback=None): 322 """ 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 327 :param bat_target: ? 328 :param bat: path to the batch file to run 329 """ 330 self.conf = ctx 331 self.name = None 332 self.is_valid = False 333 self.is_done = False 334 335 self.compiler = compiler 336 self.cpu = cpu 337 self.version = version 338 self.bat_target = bat_target 339 self.bat = bat 340 self.callback = callback 341 342 def evaluate(self): 343 if self.is_done: 344 return 345 self.is_done = True 346 try: 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 350 return 351 if self.callback: 352 vs = self.callback(self, vs) 353 self.is_valid = True 354 (self.bindirs, self.incdirs, self.libdirs) = vs 355 356 def __str__(self): 357 return str((self.compiler, self.cpu, self.version, self.bat_target, self.bat)) 358 359 def __repr__(self): 360 return repr((self.compiler, self.cpu, self.version, self.bat_target, self.bat)) 361 362@conf 363def gather_wsdk_versions(conf, versions): 364 """ 365 Use winreg to add the msvc versions to the input list 366 367 :param versions: list to modify 368 :type versions: list 369 """ 370 version_pattern = re.compile('^v..?.?\...?.?') 371 try: 372 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Microsoft SDKs\\Windows') 373 except OSError: 374 try: 375 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows') 376 except OSError: 377 return 378 index = 0 379 while 1: 380 try: 381 version = Utils.winreg.EnumKey(all_versions, index) 382 except OSError: 383 break 384 index += 1 385 if not version_pattern.match(version): 386 continue 387 try: 388 msvc_version = Utils.winreg.OpenKey(all_versions, version) 389 path,type = Utils.winreg.QueryValueEx(msvc_version,'InstallationFolder') 390 except OSError: 391 continue 392 if path and os.path.isfile(os.path.join(path, 'bin', 'SetEnv.cmd')): 393 targets = {} 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 397 398@conf 399def gather_msvc_targets(conf, versions, version, vc_path): 400 #Looking for normal MSVC compilers! 401 targets = {} 402 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')) 413 if targets: 414 versions['msvc %s' % version] = targets 415 416@conf 417def gather_wince_targets(conf, versions, version, vc_path, vsvars, supported_platforms): 418 #Looking for Win CE compilers! 419 for device,platforms in supported_platforms: 420 targets = {} 421 for platform,compiler,include,lib in platforms: 422 winCEpath = os.path.join(vc_path, 'ce') 423 if not os.path.isdir(winCEpath): 424 continue 425 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) 435 if targets: 436 versions[device + ' ' + version] = targets 437 438@conf 439def gather_winphone_targets(conf, versions, version, vc_path, vsvars): 440 #Looking for WinPhone compilers 441 targets = {} 442 for target,realtarget in all_msvc_platforms[::-1]: 443 targets[target] = target_compiler(conf, 'winphone', realtarget, version, target, vsvars) 444 if targets: 445 versions['winphone ' + version] = targets 446 447@conf 448def gather_vswhere_versions(conf, versions): 449 try: 450 import json 451 except ImportError: 452 Logs.error('Visual Studio 2017 detection requires Python 2.6') 453 return 454 455 prg_path = os.environ.get('ProgramFiles(x86)', os.environ.get('ProgramFiles', 'C:\\Program Files (x86)')) 456 457 vswhere = os.path.join(prg_path, 'Microsoft Visual Studio', 'Installer', 'vswhere.exe') 458 args = [vswhere, '-products', '*', '-legacy', '-format', 'json'] 459 try: 460 txt = conf.cmd_and_log(args) 461 except Errors.WafError as e: 462 Logs.debug('msvc: vswhere.exe failed %s', e) 463 return 464 465 if sys.version_info[0] < 3: 466 txt = txt.decode(Utils.console_encoding()) 467 468 arr = json.loads(txt) 469 arr.sort(key=lambda x: x['installationVersion']) 470 for entry in arr: 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) 476 477@conf 478def gather_msvc_versions(conf, versions): 479 vc_paths = [] 480 for (v,version,reg) in gather_msvc_detected_versions(): 481 try: 482 try: 483 msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, reg + "\\Setup\\VC") 484 except OSError: 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') 487 except OSError: 488 try: 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) 491 except OSError: 492 continue 493 else: 494 vc_paths.append((version, os.path.abspath(str(path)))) 495 continue 496 else: 497 vc_paths.append((version, os.path.abspath(str(path)))) 498 499 wince_supported_platforms = gather_wince_supported_platforms() 500 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) 506 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) 514 break 515 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) 519 520@conf 521def gather_icl_versions(conf, versions): 522 """ 523 Checks ICL compilers 524 525 :param versions: list to modify 526 :type versions: list 527 """ 528 version_pattern = re.compile('^...?.?\....?.?') 529 try: 530 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Compilers\\C++') 531 except OSError: 532 try: 533 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Intel\\Compilers\\C++') 534 except OSError: 535 return 536 index = 0 537 while 1: 538 try: 539 version = Utils.winreg.EnumKey(all_versions, index) 540 except OSError: 541 break 542 index += 1 543 if not version_pattern.match(version): 544 continue 545 targets = {} 546 for target,arch in all_icl_platforms: 547 if target=='intel64': 548 targetDir='EM64T_NATIVE' 549 else: 550 targetDir=target 551 try: 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') 555 except OSError: 556 pass 557 else: 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: 562 try: 563 icl_version = Utils.winreg.OpenKey(all_versions, version+'\\'+target) 564 path,type = Utils.winreg.QueryValueEx(icl_version,'ProductDir') 565 except OSError: 566 continue 567 else: 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) 571 major = version[0:2] 572 versions['intel ' + major] = targets 573 574@conf 575def gather_intel_composer_versions(conf, versions): 576 """ 577 Checks ICL compilers that are part of Intel Composer Suites 578 579 :param versions: list to modify 580 :type versions: list 581 """ 582 version_pattern = re.compile('^...?.?\...?.?.?') 583 try: 584 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Suites') 585 except OSError: 586 try: 587 all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Intel\\Suites') 588 except OSError: 589 return 590 index = 0 591 while 1: 592 try: 593 version = Utils.winreg.EnumKey(all_versions, index) 594 except OSError: 595 break 596 index += 1 597 if not version_pattern.match(version): 598 continue 599 targets = {} 600 for target,arch in all_icl_platforms: 601 if target=='intel64': 602 targetDir='EM64T_NATIVE' 603 else: 604 targetDir=target 605 try: 606 try: 607 defaults = Utils.winreg.OpenKey(all_versions,version+'\\Defaults\\C++\\'+targetDir) 608 except OSError: 609 if targetDir == 'EM64T_NATIVE': 610 defaults = Utils.winreg.OpenKey(all_versions,version+'\\Defaults\\C++\\EM64T') 611 else: 612 raise 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') 617 except OSError: 618 pass 619 else: 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)) 640 major = version[0:2] 641 versions['intel ' + major] = targets 642 643@conf 644def detect_msvc(self): 645 return self.setup_msvc(self.get_msvc_versions()) 646 647@conf 648def get_msvc_versions(self): 649 """ 650 :return: platform to compiler configurations 651 :rtype: dict 652 """ 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())) 660 return dct 661 662@conf 663def find_lt_names_msvc(self, libname, is_static=False): 664 """ 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) 668 """ 669 lt_names=[ 670 'lib%s.la' % libname, 671 '%s.la' % libname, 672 ] 673 674 for path in self.env.LIBPATH: 675 for la in lt_names: 676 laf=os.path.join(path,la) 677 dll=None 678 if os.path.exists(laf): 679 ltdict = Utils.read_la_file(laf) 680 lt_libdir=None 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) 694 else: 695 return (None, olib, True) 696 else: 697 raise self.errors.WafError('invalid libtool object file: %s' % laf) 698 return (None, None, None) 699 700@conf 701def libname_msvc(self, libname, is_static=False): 702 lib = libname.lower() 703 lib = re.sub('\.lib$','',lib) 704 705 if lib in g_msvc_systemlibs: 706 return lib 707 708 lib=re.sub('^lib','',lib) 709 710 if lib == 'm': 711 return None 712 713 (lt_path, lt_libname, lt_static) = self.find_lt_names_msvc(lib, is_static) 714 715 if lt_path != None and lt_libname != None: 716 if lt_static: 717 # file existence check has been made by find_lt_names 718 return os.path.join(lt_path,lt_libname) 719 720 if lt_path != None: 721 _libpaths = [lt_path] + self.env.LIBPATH 722 else: 723 _libpaths = self.env.LIBPATH 724 725 static_libs=[ 726 'lib%ss.lib' % lib, 727 'lib%s.lib' % lib, 728 '%ss.lib' % lib, 729 '%s.lib' %lib, 730 ] 731 732 dynamic_libs=[ 733 'lib%s.dll.lib' % lib, 734 'lib%s.dll.a' % lib, 735 '%s.dll.lib' % lib, 736 '%s.dll.a' % lib, 737 'lib%s_d.lib' % lib, 738 '%s_d.lib' % lib, 739 '%s.lib' %lib, 740 ] 741 742 libnames=static_libs 743 if not is_static: 744 libnames=dynamic_libs + static_libs 745 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) 751 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) 755 756@conf 757def check_lib_msvc(self, libname, is_static=False, uselib_store=None): 758 """ 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) 762 """ 763 libn = self.libname_msvc(libname, is_static) 764 765 if not uselib_store: 766 uselib_store = libname.upper() 767 768 if False and is_static: # disabled 769 self.env['STLIB_' + uselib_store] = [libn] 770 else: 771 self.env['LIB_' + uselib_store] = [libn] 772 773@conf 774def check_libs_msvc(self, libnames, is_static=False): 775 for libname in Utils.to_list(libnames): 776 self.check_lib_msvc(libname, is_static) 777 778def configure(conf): 779 """ 780 Configuration methods to call for detecting msvc 781 """ 782 conf.autodetect(True) 783 conf.find_msvc() 784 conf.msvc_common_flags() 785 conf.cc_load_tools() 786 conf.cxx_load_tools() 787 conf.cc_add_flags() 788 conf.cxx_add_flags() 789 conf.link_add_flags() 790 conf.visual_studio_add_flags() 791 792@conf 793def no_autodetect(conf): 794 conf.env.NO_MSVC_DETECT = 1 795 configure(conf) 796 797@conf 798def autodetect(conf, arch=False): 799 v = conf.env 800 if v.NO_MSVC_DETECT: 801 return 802 803 compiler, version, path, includes, libdirs, cpu = conf.detect_msvc() 804 if arch: 805 v.DEST_CPU = cpu 806 807 v.PATH = path 808 v.INCLUDES = includes 809 v.LIBPATH = libdirs 810 v.MSVC_COMPILER = compiler 811 try: 812 v.MSVC_VERSION = float(version) 813 except ValueError: 814 v.MSVC_VERSION = float(version[:-3]) 815 816def _get_prog_names(conf, compiler): 817 if compiler == 'intel': 818 compiler_name = 'ICL' 819 linker_name = 'XILINK' 820 lib_name = 'XILIB' 821 else: 822 # assumes CL.exe 823 compiler_name = 'CL' 824 linker_name = 'LINK' 825 lib_name = 'LIB' 826 return compiler_name, linker_name, lib_name 827 828@conf 829def find_msvc(conf): 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!') 833 834 # the autodetection is supposed to be performed before entering in this method 835 v = conf.env 836 path = v.PATH 837 compiler = v.MSVC_COMPILER 838 version = v.MSVC_VERSION 839 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) 842 843 # compiler 844 cxx = conf.find_program(compiler_name, var='CXX', path_list=path) 845 846 # before setting anything, check if the compiler is really msvc 847 env = dict(conf.environ) 848 if path: 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') 852 853 # c/c++ compiler 854 v.CC = v.CXX = cxx 855 v.CC_NAME = v.CXX_NAME = 'msvc' 856 857 # linker 858 if not v.LINK_CXX: 859 conf.find_program(linker_name, path_list=path, errmsg='%s was not found (linker)' % linker_name, var='LINK_CXX') 860 861 if not v.LINK_CC: 862 v.LINK_CC = v.LINK_CXX 863 864 # staticlib linker 865 if not v.AR: 866 stliblink = conf.find_program(lib_name, path_list=path, var='AR') 867 if not stliblink: 868 return 869 v.ARFLAGS = ['/nologo'] 870 871 # manifest tool. Not required for VS 2003 and below. Must have for VS 2005 and later 872 if v.MSVC_MANIFEST: 873 conf.find_program('MT', path_list=path, var='MT') 874 v.MTFLAGS = ['/nologo'] 875 876 try: 877 conf.load('winres') 878 except Errors.ConfigurationError: 879 Logs.warn('Resource compiler not found. Compiling resource file is disabled') 880 881@conf 882def visual_studio_add_flags(self): 883 """visual studio flags found in the system environment""" 884 v = self.env 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]) 889 890@conf 891def msvc_common_flags(conf): 892 """ 893 Setup the flags required for executing the msvc compiler 894 """ 895 v = conf.env 896 897 v.DEST_BINFMT = 'pe' 898 v.append_value('CFLAGS', ['/nologo']) 899 v.append_value('CXXFLAGS', ['/nologo']) 900 v.append_value('LINKFLAGS', ['/nologo']) 901 v.DEFINES_ST = '/D%s' 902 903 v.CC_SRC_F = '' 904 v.CC_TGT_F = ['/c', '/Fo'] 905 v.CXX_SRC_F = '' 906 v.CXX_TGT_F = ['/c', '/Fo'] 907 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 911 912 v.CPPPATH_ST = '/I%s' # template for adding include paths 913 914 v.AR_TGT_F = v.CCLNK_TGT_F = v.CXXLNK_TGT_F = '/OUT:' 915 916 # CRT specific flags 917 v.CFLAGS_CRT_MULTITHREADED = v.CXXFLAGS_CRT_MULTITHREADED = ['/MT'] 918 v.CFLAGS_CRT_MULTITHREADED_DLL = v.CXXFLAGS_CRT_MULTITHREADED_DLL = ['/MD'] 919 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'] 922 923 v.LIB_ST = '%s.lib' 924 v.LIBPATH_ST = '/LIBPATH:%s' 925 v.STLIB_ST = '%s.lib' 926 v.STLIBPATH_ST = '/LIBPATH:%s' 927 928 if v.MSVC_MANIFEST: 929 v.append_value('LINKFLAGS', ['/MANIFEST']) 930 931 v.CFLAGS_cshlib = [] 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' 937 938 v.LINKFLAGS_cstlib = [] 939 v.cstlib_PATTERN = v.cxxstlib_PATTERN = '%s.lib' 940 941 v.cprogram_PATTERN = v.cxxprogram_PATTERN = '%s.exe' 942 943 v.def_PATTERN = '/def:%s' 944 945 946####################################################################################################### 947##### conf above, build below 948 949@after_method('apply_link') 950@feature('c', 'cxx') 951def apply_flags_msvc(self): 952 """ 953 Add additional flags implied by msvc, such as subsystems and pdb files:: 954 955 def build(bld): 956 bld.stlib(source='main.c', target='bar', subsystem='gruik') 957 """ 958 if self.env.CC_NAME != 'msvc' or not getattr(self, 'link_task', None): 959 return 960 961 is_static = isinstance(self.link_task, ccroot.stlink_task) 962 963 subsystem = getattr(self, 'subsystem', '') 964 if subsystem: 965 subsystem = '/subsystem:%s' % subsystem 966 flags = is_static and 'ARFLAGS' or 'LINKFLAGS' 967 self.env.append_value(flags, subsystem) 968 969 if not is_static: 970 for f in self.env.LINKFLAGS: 971 d = f.lower() 972 if d[1:] == 'debug': 973 pdbnode = self.link_task.outputs[0].change_ext('.pdb') 974 self.link_task.outputs.append(pdbnode) 975 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) 979 break 980 981@feature('cprogram', 'cshlib', 'cxxprogram', 'cxxshlib') 982@after_method('apply_link') 983def apply_manifest(self): 984 """ 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 989 """ 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 995 996def 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) 1002 1003@feature('winphoneapp') 1004@after_method('process_use') 1005@after_method('propagate_uselib_vars') 1006def make_winphone_app(self): 1007 """ 1008 Insert configuration flags for windows phone applications (adds /ZW, /TP...) 1009 """ 1010 make_winapp(self, 'WINAPI_FAMILY_PHONE_APP') 1011 self.env.append_unique('LINKFLAGS', ['/NODEFAULTLIB:ole32.lib', 'PhoneAppModelHost.lib']) 1012 1013@feature('winapp') 1014@after_method('process_use') 1015@after_method('propagate_uselib_vars') 1016def make_windows_app(self): 1017 """ 1018 Insert configuration flags for windows applications (adds /ZW, /TP...) 1019 """ 1020 make_winapp(self, 'WINAPI_FAMILY_DESKTOP_APP') 1021