jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1069 lines
35KB

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