c_config.py 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352
  1. #!/usr/bin/env python
  2. # encoding: utf-8
  3. # Thomas Nagy, 2005-2018 (ita)
  4. """
  5. C/C++/D configuration helpers
  6. """
  7. from __future__ import with_statement
  8. import os, re, shlex
  9. from waflib import Build, Utils, Task, Options, Logs, Errors, Runner
  10. from waflib.TaskGen import after_method, feature
  11. from waflib.Configure import conf
  12. WAF_CONFIG_H = 'config.h'
  13. """default name for the config.h file"""
  14. DEFKEYS = 'define_key'
  15. INCKEYS = 'include_key'
  16. SNIP_EMPTY_PROGRAM = '''
  17. int main(int argc, char **argv) {
  18. (void)argc; (void)argv;
  19. return 0;
  20. }
  21. '''
  22. MACRO_TO_DESTOS = {
  23. '__linux__' : 'linux',
  24. '__GNU__' : 'gnu', # hurd
  25. '__FreeBSD__' : 'freebsd',
  26. '__NetBSD__' : 'netbsd',
  27. '__OpenBSD__' : 'openbsd',
  28. '__sun' : 'sunos',
  29. '__hpux' : 'hpux',
  30. '__sgi' : 'irix',
  31. '_AIX' : 'aix',
  32. '__CYGWIN__' : 'cygwin',
  33. '__MSYS__' : 'cygwin',
  34. '_UWIN' : 'uwin',
  35. '_WIN64' : 'win32',
  36. '_WIN32' : 'win32',
  37. # Note about darwin: this is also tested with 'defined __APPLE__ && defined __MACH__' somewhere below in this file.
  38. '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' : 'darwin',
  39. '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' : 'darwin', # iphone
  40. '__QNX__' : 'qnx',
  41. '__native_client__' : 'nacl' # google native client platform
  42. }
  43. MACRO_TO_DEST_CPU = {
  44. '__x86_64__' : 'x86_64',
  45. '__amd64__' : 'x86_64',
  46. '__i386__' : 'x86',
  47. '__ia64__' : 'ia',
  48. '__mips__' : 'mips',
  49. '__sparc__' : 'sparc',
  50. '__alpha__' : 'alpha',
  51. '__aarch64__' : 'aarch64',
  52. '__thumb__' : 'thumb',
  53. '__arm__' : 'arm',
  54. '__hppa__' : 'hppa',
  55. '__powerpc__' : 'powerpc',
  56. '__ppc__' : 'powerpc',
  57. '__convex__' : 'convex',
  58. '__m68k__' : 'm68k',
  59. '__s390x__' : 's390x',
  60. '__s390__' : 's390',
  61. '__sh__' : 'sh',
  62. '__xtensa__' : 'xtensa',
  63. }
  64. @conf
  65. def parse_flags(self, line, uselib_store, env=None, force_static=False, posix=None):
  66. """
  67. Parses flags from the input lines, and adds them to the relevant use variables::
  68. def configure(conf):
  69. conf.parse_flags('-O3', 'FOO')
  70. # conf.env.CXXFLAGS_FOO = ['-O3']
  71. # conf.env.CFLAGS_FOO = ['-O3']
  72. :param line: flags
  73. :type line: string
  74. :param uselib_store: where to add the flags
  75. :type uselib_store: string
  76. :param env: config set or conf.env by default
  77. :type env: :py:class:`waflib.ConfigSet.ConfigSet`
  78. """
  79. assert(isinstance(line, str))
  80. env = env or self.env
  81. # Issue 811 and 1371
  82. if posix is None:
  83. posix = True
  84. if '\\' in line:
  85. posix = ('\\ ' in line) or ('\\\\' in line)
  86. lex = shlex.shlex(line, posix=posix)
  87. lex.whitespace_split = True
  88. lex.commenters = ''
  89. lst = list(lex)
  90. # append_unique is not always possible
  91. # for example, apple flags may require both -arch i386 and -arch ppc
  92. uselib = uselib_store
  93. def app(var, val):
  94. env.append_value('%s_%s' % (var, uselib), val)
  95. def appu(var, val):
  96. env.append_unique('%s_%s' % (var, uselib), val)
  97. static = False
  98. while lst:
  99. x = lst.pop(0)
  100. st = x[:2]
  101. ot = x[2:]
  102. if st == '-I' or st == '/I':
  103. if not ot:
  104. ot = lst.pop(0)
  105. appu('INCLUDES', ot)
  106. elif st == '-i':
  107. tmp = [x, lst.pop(0)]
  108. app('CFLAGS', tmp)
  109. app('CXXFLAGS', tmp)
  110. elif st == '-D' or (env.CXX_NAME == 'msvc' and st == '/D'): # not perfect but..
  111. if not ot:
  112. ot = lst.pop(0)
  113. app('DEFINES', ot)
  114. elif st == '-l':
  115. if not ot:
  116. ot = lst.pop(0)
  117. prefix = 'STLIB' if (force_static or static) else 'LIB'
  118. app(prefix, ot)
  119. elif st == '-L':
  120. if not ot:
  121. ot = lst.pop(0)
  122. prefix = 'STLIBPATH' if (force_static or static) else 'LIBPATH'
  123. appu(prefix, ot)
  124. elif x.startswith('/LIBPATH:'):
  125. prefix = 'STLIBPATH' if (force_static or static) else 'LIBPATH'
  126. appu(prefix, x.replace('/LIBPATH:', ''))
  127. elif x.startswith('-std='):
  128. prefix = 'CXXFLAGS' if '++' in x else 'CFLAGS'
  129. app(prefix, x)
  130. elif x.startswith('+') or x in ('-pthread', '-fPIC', '-fpic', '-fPIE', '-fpie'):
  131. app('CFLAGS', x)
  132. app('CXXFLAGS', x)
  133. app('LINKFLAGS', x)
  134. elif x == '-framework':
  135. appu('FRAMEWORK', lst.pop(0))
  136. elif x.startswith('-F'):
  137. appu('FRAMEWORKPATH', x[2:])
  138. elif x == '-Wl,-rpath' or x == '-Wl,-R':
  139. app('RPATH', lst.pop(0).lstrip('-Wl,'))
  140. elif x.startswith('-Wl,-R,'):
  141. app('RPATH', x[7:])
  142. elif x.startswith('-Wl,-R'):
  143. app('RPATH', x[6:])
  144. elif x.startswith('-Wl,-rpath,'):
  145. app('RPATH', x[11:])
  146. elif x == '-Wl,-Bstatic' or x == '-Bstatic':
  147. static = True
  148. elif x == '-Wl,-Bdynamic' or x == '-Bdynamic':
  149. static = False
  150. elif x.startswith('-Wl') or x in ('-rdynamic', '-pie'):
  151. app('LINKFLAGS', x)
  152. elif x.startswith(('-m', '-f', '-dynamic', '-O', '-g')):
  153. # Adding the -W option breaks python builds on Openindiana
  154. app('CFLAGS', x)
  155. app('CXXFLAGS', x)
  156. elif x.startswith('-bundle'):
  157. app('LINKFLAGS', x)
  158. elif x.startswith(('-undefined', '-Xlinker')):
  159. arg = lst.pop(0)
  160. app('LINKFLAGS', [x, arg])
  161. elif x.startswith(('-arch', '-isysroot')):
  162. tmp = [x, lst.pop(0)]
  163. app('CFLAGS', tmp)
  164. app('CXXFLAGS', tmp)
  165. app('LINKFLAGS', tmp)
  166. elif x.endswith(('.a', '.so', '.dylib', '.lib')):
  167. appu('LINKFLAGS', x) # not cool, #762
  168. else:
  169. self.to_log('Unhandled flag %r' % x)
  170. @conf
  171. def validate_cfg(self, kw):
  172. """
  173. Searches for the program *pkg-config* if missing, and validates the
  174. parameters to pass to :py:func:`waflib.Tools.c_config.exec_cfg`.
  175. :param path: the **-config program to use** (default is *pkg-config*)
  176. :type path: list of string
  177. :param msg: message to display to describe the test executed
  178. :type msg: string
  179. :param okmsg: message to display when the test is successful
  180. :type okmsg: string
  181. :param errmsg: message to display in case of error
  182. :type errmsg: string
  183. """
  184. if not 'path' in kw:
  185. if not self.env.PKGCONFIG:
  186. self.find_program('pkg-config', var='PKGCONFIG')
  187. kw['path'] = self.env.PKGCONFIG
  188. # verify that exactly one action is requested
  189. s = ('atleast_pkgconfig_version' in kw) + ('modversion' in kw) + ('package' in kw)
  190. if s != 1:
  191. raise ValueError('exactly one of atleast_pkgconfig_version, modversion and package must be set')
  192. if not 'msg' in kw:
  193. if 'atleast_pkgconfig_version' in kw:
  194. kw['msg'] = 'Checking for pkg-config version >= %r' % kw['atleast_pkgconfig_version']
  195. elif 'modversion' in kw:
  196. kw['msg'] = 'Checking for %r version' % kw['modversion']
  197. else:
  198. kw['msg'] = 'Checking for %r' %(kw['package'])
  199. # let the modversion check set the okmsg to the detected version
  200. if not 'okmsg' in kw and not 'modversion' in kw:
  201. kw['okmsg'] = 'yes'
  202. if not 'errmsg' in kw:
  203. kw['errmsg'] = 'not found'
  204. # pkg-config version
  205. if 'atleast_pkgconfig_version' in kw:
  206. pass
  207. elif 'modversion' in kw:
  208. if not 'uselib_store' in kw:
  209. kw['uselib_store'] = kw['modversion']
  210. if not 'define_name' in kw:
  211. kw['define_name'] = '%s_VERSION' % Utils.quote_define_name(kw['uselib_store'])
  212. else:
  213. if not 'uselib_store' in kw:
  214. kw['uselib_store'] = Utils.to_list(kw['package'])[0].upper()
  215. if not 'define_name' in kw:
  216. kw['define_name'] = self.have_define(kw['uselib_store'])
  217. @conf
  218. def exec_cfg(self, kw):
  219. """
  220. Executes ``pkg-config`` or other ``-config`` applications to collect configuration flags:
  221. * if atleast_pkgconfig_version is given, check that pkg-config has the version n and return
  222. * if modversion is given, then return the module version
  223. * else, execute the *-config* program with the *args* and *variables* given, and set the flags on the *conf.env.FLAGS_name* variable
  224. :param atleast_pkgconfig_version: minimum pkg-config version to use (disable other tests)
  225. :type atleast_pkgconfig_version: string
  226. :param package: package name, for example *gtk+-2.0*
  227. :type package: string
  228. :param uselib_store: if the test is successful, define HAVE\_*name*. It is also used to define *conf.env.FLAGS_name* variables.
  229. :type uselib_store: string
  230. :param modversion: if provided, return the version of the given module and define *name*\_VERSION
  231. :type modversion: string
  232. :param args: arguments to give to *package* when retrieving flags
  233. :type args: list of string
  234. :param variables: return the values of particular variables
  235. :type variables: list of string
  236. :param define_variable: additional variables to define (also in conf.env.PKG_CONFIG_DEFINES)
  237. :type define_variable: dict(string: string)
  238. """
  239. path = Utils.to_list(kw['path'])
  240. env = self.env.env or None
  241. if kw.get('pkg_config_path'):
  242. if not env:
  243. env = dict(self.environ)
  244. env['PKG_CONFIG_PATH'] = kw['pkg_config_path']
  245. def define_it():
  246. define_name = kw['define_name']
  247. # by default, add HAVE_X to the config.h, else provide DEFINES_X for use=X
  248. if kw.get('global_define', 1):
  249. self.define(define_name, 1, False)
  250. else:
  251. self.env.append_unique('DEFINES_%s' % kw['uselib_store'], "%s=1" % define_name)
  252. if kw.get('add_have_to_env', 1):
  253. self.env[define_name] = 1
  254. # pkg-config version
  255. if 'atleast_pkgconfig_version' in kw:
  256. cmd = path + ['--atleast-pkgconfig-version=%s' % kw['atleast_pkgconfig_version']]
  257. self.cmd_and_log(cmd, env=env)
  258. return
  259. # single version for a module
  260. if 'modversion' in kw:
  261. version = self.cmd_and_log(path + ['--modversion', kw['modversion']], env=env).strip()
  262. if not 'okmsg' in kw:
  263. kw['okmsg'] = version
  264. self.define(kw['define_name'], version)
  265. return version
  266. lst = [] + path
  267. defi = kw.get('define_variable')
  268. if not defi:
  269. defi = self.env.PKG_CONFIG_DEFINES or {}
  270. for key, val in defi.items():
  271. lst.append('--define-variable=%s=%s' % (key, val))
  272. static = kw.get('force_static', False)
  273. if 'args' in kw:
  274. args = Utils.to_list(kw['args'])
  275. if '--static' in args or '--static-libs' in args:
  276. static = True
  277. lst += args
  278. # tools like pkgconf expect the package argument after the -- ones -_-
  279. lst.extend(Utils.to_list(kw['package']))
  280. # retrieving variables of a module
  281. if 'variables' in kw:
  282. v_env = kw.get('env', self.env)
  283. vars = Utils.to_list(kw['variables'])
  284. for v in vars:
  285. val = self.cmd_and_log(lst + ['--variable=' + v], env=env).strip()
  286. var = '%s_%s' % (kw['uselib_store'], v)
  287. v_env[var] = val
  288. return
  289. # so we assume the command-line will output flags to be parsed afterwards
  290. ret = self.cmd_and_log(lst, env=env)
  291. define_it()
  292. self.parse_flags(ret, kw['uselib_store'], kw.get('env', self.env), force_static=static, posix=kw.get('posix'))
  293. return ret
  294. @conf
  295. def check_cfg(self, *k, **kw):
  296. """
  297. Checks for configuration flags using a **-config**-like program (pkg-config, sdl-config, etc).
  298. This wraps internal calls to :py:func:`waflib.Tools.c_config.validate_cfg` and :py:func:`waflib.Tools.c_config.exec_cfg`
  299. A few examples::
  300. def configure(conf):
  301. conf.load('compiler_c')
  302. conf.check_cfg(package='glib-2.0', args='--libs --cflags')
  303. conf.check_cfg(package='pango')
  304. conf.check_cfg(package='pango', uselib_store='MYPANGO', args=['--cflags', '--libs'])
  305. conf.check_cfg(package='pango',
  306. args=['pango >= 0.1.0', 'pango < 9.9.9', '--cflags', '--libs'],
  307. msg="Checking for 'pango 0.1.0'")
  308. conf.check_cfg(path='sdl-config', args='--cflags --libs', package='', uselib_store='SDL')
  309. conf.check_cfg(path='mpicc', args='--showme:compile --showme:link',
  310. package='', uselib_store='OPEN_MPI', mandatory=False)
  311. # variables
  312. conf.check_cfg(package='gtk+-2.0', variables=['includedir', 'prefix'], uselib_store='FOO')
  313. print(conf.env.FOO_includedir)
  314. """
  315. self.validate_cfg(kw)
  316. if 'msg' in kw:
  317. self.start_msg(kw['msg'], **kw)
  318. ret = None
  319. try:
  320. ret = self.exec_cfg(kw)
  321. except self.errors.WafError:
  322. if 'errmsg' in kw:
  323. self.end_msg(kw['errmsg'], 'YELLOW', **kw)
  324. if Logs.verbose > 1:
  325. raise
  326. else:
  327. self.fatal('The configuration failed')
  328. else:
  329. if not ret:
  330. ret = True
  331. kw['success'] = ret
  332. if 'okmsg' in kw:
  333. self.end_msg(self.ret_msg(kw['okmsg'], kw), **kw)
  334. return ret
  335. def build_fun(bld):
  336. """
  337. Build function that is used for running configuration tests with ``conf.check()``
  338. """
  339. if bld.kw['compile_filename']:
  340. node = bld.srcnode.make_node(bld.kw['compile_filename'])
  341. node.write(bld.kw['code'])
  342. o = bld(features=bld.kw['features'], source=bld.kw['compile_filename'], target='testprog')
  343. for k, v in bld.kw.items():
  344. setattr(o, k, v)
  345. if not bld.kw.get('quiet'):
  346. bld.conf.to_log("==>\n%s\n<==" % bld.kw['code'])
  347. @conf
  348. def validate_c(self, kw):
  349. """
  350. Pre-checks the parameters that will be given to :py:func:`waflib.Configure.run_build`
  351. :param compiler: c or cxx (tries to guess what is best)
  352. :type compiler: string
  353. :param type: cprogram, cshlib, cstlib - not required if *features are given directly*
  354. :type type: binary to create
  355. :param feature: desired features for the task generator that will execute the test, for example ``cxx cxxstlib``
  356. :type feature: list of string
  357. :param fragment: provide a piece of code for the test (default is to let the system create one)
  358. :type fragment: string
  359. :param uselib_store: define variables after the test is executed (IMPORTANT!)
  360. :type uselib_store: string
  361. :param use: parameters to use for building (just like the normal *use* keyword)
  362. :type use: list of string
  363. :param define_name: define to set when the check is over
  364. :type define_name: string
  365. :param execute: execute the resulting binary
  366. :type execute: bool
  367. :param define_ret: if execute is set to True, use the execution output in both the define and the return value
  368. :type define_ret: bool
  369. :param header_name: check for a particular header
  370. :type header_name: string
  371. :param auto_add_header_name: if header_name was set, add the headers in env.INCKEYS so the next tests will include these headers
  372. :type auto_add_header_name: bool
  373. """
  374. for x in ('type_name', 'field_name', 'function_name'):
  375. if x in kw:
  376. Logs.warn('Invalid argument %r in test' % x)
  377. if not 'build_fun' in kw:
  378. kw['build_fun'] = build_fun
  379. if not 'env' in kw:
  380. kw['env'] = self.env.derive()
  381. env = kw['env']
  382. if not 'compiler' in kw and not 'features' in kw:
  383. kw['compiler'] = 'c'
  384. if env.CXX_NAME and Task.classes.get('cxx'):
  385. kw['compiler'] = 'cxx'
  386. if not self.env.CXX:
  387. self.fatal('a c++ compiler is required')
  388. else:
  389. if not self.env.CC:
  390. self.fatal('a c compiler is required')
  391. if not 'compile_mode' in kw:
  392. kw['compile_mode'] = 'c'
  393. if 'cxx' in Utils.to_list(kw.get('features', [])) or kw.get('compiler') == 'cxx':
  394. kw['compile_mode'] = 'cxx'
  395. if not 'type' in kw:
  396. kw['type'] = 'cprogram'
  397. if not 'features' in kw:
  398. if not 'header_name' in kw or kw.get('link_header_test', True):
  399. kw['features'] = [kw['compile_mode'], kw['type']] # "c ccprogram"
  400. else:
  401. kw['features'] = [kw['compile_mode']]
  402. else:
  403. kw['features'] = Utils.to_list(kw['features'])
  404. if not 'compile_filename' in kw:
  405. kw['compile_filename'] = 'test.c' + ((kw['compile_mode'] == 'cxx') and 'pp' or '')
  406. def to_header(dct):
  407. if 'header_name' in dct:
  408. dct = Utils.to_list(dct['header_name'])
  409. return ''.join(['#include <%s>\n' % x for x in dct])
  410. return ''
  411. if 'framework_name' in kw:
  412. # OSX, not sure this is used anywhere
  413. fwkname = kw['framework_name']
  414. if not 'uselib_store' in kw:
  415. kw['uselib_store'] = fwkname.upper()
  416. if not kw.get('no_header'):
  417. fwk = '%s/%s.h' % (fwkname, fwkname)
  418. if kw.get('remove_dot_h'):
  419. fwk = fwk[:-2]
  420. val = kw.get('header_name', [])
  421. kw['header_name'] = Utils.to_list(val) + [fwk]
  422. kw['msg'] = 'Checking for framework %s' % fwkname
  423. kw['framework'] = fwkname
  424. elif 'header_name' in kw:
  425. if not 'msg' in kw:
  426. kw['msg'] = 'Checking for header %s' % kw['header_name']
  427. l = Utils.to_list(kw['header_name'])
  428. assert len(l), 'list of headers in header_name is empty'
  429. kw['code'] = to_header(kw) + SNIP_EMPTY_PROGRAM
  430. if not 'uselib_store' in kw:
  431. kw['uselib_store'] = l[0].upper()
  432. if not 'define_name' in kw:
  433. kw['define_name'] = self.have_define(l[0])
  434. if 'lib' in kw:
  435. if not 'msg' in kw:
  436. kw['msg'] = 'Checking for library %s' % kw['lib']
  437. if not 'uselib_store' in kw:
  438. kw['uselib_store'] = kw['lib'].upper()
  439. if 'stlib' in kw:
  440. if not 'msg' in kw:
  441. kw['msg'] = 'Checking for static library %s' % kw['stlib']
  442. if not 'uselib_store' in kw:
  443. kw['uselib_store'] = kw['stlib'].upper()
  444. if 'fragment' in kw:
  445. # an additional code fragment may be provided to replace the predefined code
  446. # in custom headers
  447. kw['code'] = kw['fragment']
  448. if not 'msg' in kw:
  449. kw['msg'] = 'Checking for code snippet'
  450. if not 'errmsg' in kw:
  451. kw['errmsg'] = 'no'
  452. for (flagsname,flagstype) in (('cxxflags','compiler'), ('cflags','compiler'), ('linkflags','linker')):
  453. if flagsname in kw:
  454. if not 'msg' in kw:
  455. kw['msg'] = 'Checking for %s flags %s' % (flagstype, kw[flagsname])
  456. if not 'errmsg' in kw:
  457. kw['errmsg'] = 'no'
  458. if not 'execute' in kw:
  459. kw['execute'] = False
  460. if kw['execute']:
  461. kw['features'].append('test_exec')
  462. kw['chmod'] = Utils.O755
  463. if not 'errmsg' in kw:
  464. kw['errmsg'] = 'not found'
  465. if not 'okmsg' in kw:
  466. kw['okmsg'] = 'yes'
  467. if not 'code' in kw:
  468. kw['code'] = SNIP_EMPTY_PROGRAM
  469. # if there are headers to append automatically to the next tests
  470. if self.env[INCKEYS]:
  471. kw['code'] = '\n'.join(['#include <%s>' % x for x in self.env[INCKEYS]]) + '\n' + kw['code']
  472. # in case defines lead to very long command-lines
  473. if kw.get('merge_config_header') or env.merge_config_header:
  474. kw['code'] = '%s\n\n%s' % (self.get_config_header(), kw['code'])
  475. env.DEFINES = [] # modify the copy
  476. if not kw.get('success'):
  477. kw['success'] = None
  478. if 'define_name' in kw:
  479. self.undefine(kw['define_name'])
  480. if not 'msg' in kw:
  481. self.fatal('missing "msg" in conf.check(...)')
  482. @conf
  483. def post_check(self, *k, **kw):
  484. """
  485. Sets the variables after a test executed in
  486. :py:func:`waflib.Tools.c_config.check` was run successfully
  487. """
  488. is_success = 0
  489. if kw['execute']:
  490. if kw['success'] is not None:
  491. if kw.get('define_ret'):
  492. is_success = kw['success']
  493. else:
  494. is_success = (kw['success'] == 0)
  495. else:
  496. is_success = (kw['success'] == 0)
  497. if kw.get('define_name'):
  498. comment = kw.get('comment', '')
  499. define_name = kw['define_name']
  500. if kw['execute'] and kw.get('define_ret') and isinstance(is_success, str):
  501. if kw.get('global_define', 1):
  502. self.define(define_name, is_success, quote=kw.get('quote', 1), comment=comment)
  503. else:
  504. if kw.get('quote', 1):
  505. succ = '"%s"' % is_success
  506. else:
  507. succ = int(is_success)
  508. val = '%s=%s' % (define_name, succ)
  509. var = 'DEFINES_%s' % kw['uselib_store']
  510. self.env.append_value(var, val)
  511. else:
  512. if kw.get('global_define', 1):
  513. self.define_cond(define_name, is_success, comment=comment)
  514. else:
  515. var = 'DEFINES_%s' % kw['uselib_store']
  516. self.env.append_value(var, '%s=%s' % (define_name, int(is_success)))
  517. # define conf.env.HAVE_X to 1
  518. if kw.get('add_have_to_env', 1):
  519. if kw.get('uselib_store'):
  520. self.env[self.have_define(kw['uselib_store'])] = 1
  521. elif kw['execute'] and kw.get('define_ret'):
  522. self.env[define_name] = is_success
  523. else:
  524. self.env[define_name] = int(is_success)
  525. if 'header_name' in kw:
  526. if kw.get('auto_add_header_name'):
  527. self.env.append_value(INCKEYS, Utils.to_list(kw['header_name']))
  528. if is_success and 'uselib_store' in kw:
  529. from waflib.Tools import ccroot
  530. # See get_uselib_vars in ccroot.py
  531. _vars = set()
  532. for x in kw['features']:
  533. if x in ccroot.USELIB_VARS:
  534. _vars |= ccroot.USELIB_VARS[x]
  535. for k in _vars:
  536. x = k.lower()
  537. if x in kw:
  538. self.env.append_value(k + '_' + kw['uselib_store'], kw[x])
  539. return is_success
  540. @conf
  541. def check(self, *k, **kw):
  542. """
  543. Performs a configuration test by calling :py:func:`waflib.Configure.run_build`.
  544. For the complete list of parameters, see :py:func:`waflib.Tools.c_config.validate_c`.
  545. To force a specific compiler, pass ``compiler='c'`` or ``compiler='cxx'`` to the list of arguments
  546. Besides build targets, complete builds can be given through a build function. All files will
  547. be written to a temporary directory::
  548. def build(bld):
  549. lib_node = bld.srcnode.make_node('libdir/liblc1.c')
  550. lib_node.parent.mkdir()
  551. lib_node.write('#include <stdio.h>\\nint lib_func(void) { FILE *f = fopen("foo", "r");}\\n', 'w')
  552. bld(features='c cshlib', source=[lib_node], linkflags=conf.env.EXTRA_LDFLAGS, target='liblc')
  553. conf.check(build_fun=build, msg=msg)
  554. """
  555. self.validate_c(kw)
  556. self.start_msg(kw['msg'], **kw)
  557. ret = None
  558. try:
  559. ret = self.run_build(*k, **kw)
  560. except self.errors.ConfigurationError:
  561. self.end_msg(kw['errmsg'], 'YELLOW', **kw)
  562. if Logs.verbose > 1:
  563. raise
  564. else:
  565. self.fatal('The configuration failed')
  566. else:
  567. kw['success'] = ret
  568. ret = self.post_check(*k, **kw)
  569. if not ret:
  570. self.end_msg(kw['errmsg'], 'YELLOW', **kw)
  571. self.fatal('The configuration failed %r' % ret)
  572. else:
  573. self.end_msg(self.ret_msg(kw['okmsg'], kw), **kw)
  574. return ret
  575. class test_exec(Task.Task):
  576. """
  577. A task that runs programs after they are built. See :py:func:`waflib.Tools.c_config.test_exec_fun`.
  578. """
  579. color = 'PINK'
  580. def run(self):
  581. if getattr(self.generator, 'rpath', None):
  582. if getattr(self.generator, 'define_ret', False):
  583. self.generator.bld.retval = self.generator.bld.cmd_and_log([self.inputs[0].abspath()])
  584. else:
  585. self.generator.bld.retval = self.generator.bld.exec_command([self.inputs[0].abspath()])
  586. else:
  587. env = self.env.env or {}
  588. env.update(dict(os.environ))
  589. for var in ('LD_LIBRARY_PATH', 'DYLD_LIBRARY_PATH', 'PATH'):
  590. env[var] = self.inputs[0].parent.abspath() + os.path.pathsep + env.get(var, '')
  591. if getattr(self.generator, 'define_ret', False):
  592. self.generator.bld.retval = self.generator.bld.cmd_and_log([self.inputs[0].abspath()], env=env)
  593. else:
  594. self.generator.bld.retval = self.generator.bld.exec_command([self.inputs[0].abspath()], env=env)
  595. @feature('test_exec')
  596. @after_method('apply_link')
  597. def test_exec_fun(self):
  598. """
  599. The feature **test_exec** is used to create a task that will to execute the binary
  600. created (link task output) during the build. The exit status will be set
  601. on the build context, so only one program may have the feature *test_exec*.
  602. This is used by configuration tests::
  603. def configure(conf):
  604. conf.check(execute=True)
  605. """
  606. self.create_task('test_exec', self.link_task.outputs[0])
  607. @conf
  608. def check_cxx(self, *k, **kw):
  609. """
  610. Runs a test with a task generator of the form::
  611. conf.check(features='cxx cxxprogram', ...)
  612. """
  613. kw['compiler'] = 'cxx'
  614. return self.check(*k, **kw)
  615. @conf
  616. def check_cc(self, *k, **kw):
  617. """
  618. Runs a test with a task generator of the form::
  619. conf.check(features='c cprogram', ...)
  620. """
  621. kw['compiler'] = 'c'
  622. return self.check(*k, **kw)
  623. @conf
  624. def set_define_comment(self, key, comment):
  625. """
  626. Sets a comment that will appear in the configuration header
  627. :type key: string
  628. :type comment: string
  629. """
  630. coms = self.env.DEFINE_COMMENTS
  631. if not coms:
  632. coms = self.env.DEFINE_COMMENTS = {}
  633. coms[key] = comment or ''
  634. @conf
  635. def get_define_comment(self, key):
  636. """
  637. Returns the comment associated to a define
  638. :type key: string
  639. """
  640. coms = self.env.DEFINE_COMMENTS or {}
  641. return coms.get(key, '')
  642. @conf
  643. def define(self, key, val, quote=True, comment=''):
  644. """
  645. Stores a single define and its state into ``conf.env.DEFINES``. The value is cast to an integer (0/1).
  646. :param key: define name
  647. :type key: string
  648. :param val: value
  649. :type val: int or string
  650. :param quote: enclose strings in quotes (yes by default)
  651. :type quote: bool
  652. """
  653. assert isinstance(key, str)
  654. if not key:
  655. return
  656. if val is True:
  657. val = 1
  658. elif val in (False, None):
  659. val = 0
  660. if isinstance(val, int) or isinstance(val, float):
  661. s = '%s=%s'
  662. else:
  663. s = quote and '%s="%s"' or '%s=%s'
  664. app = s % (key, str(val))
  665. ban = key + '='
  666. lst = self.env.DEFINES
  667. for x in lst:
  668. if x.startswith(ban):
  669. lst[lst.index(x)] = app
  670. break
  671. else:
  672. self.env.append_value('DEFINES', app)
  673. self.env.append_unique(DEFKEYS, key)
  674. self.set_define_comment(key, comment)
  675. @conf
  676. def undefine(self, key, comment=''):
  677. """
  678. Removes a global define from ``conf.env.DEFINES``
  679. :param key: define name
  680. :type key: string
  681. """
  682. assert isinstance(key, str)
  683. if not key:
  684. return
  685. ban = key + '='
  686. lst = [x for x in self.env.DEFINES if not x.startswith(ban)]
  687. self.env.DEFINES = lst
  688. self.env.append_unique(DEFKEYS, key)
  689. self.set_define_comment(key, comment)
  690. @conf
  691. def define_cond(self, key, val, comment=''):
  692. """
  693. Conditionally defines a name::
  694. def configure(conf):
  695. conf.define_cond('A', True)
  696. # equivalent to:
  697. # if val: conf.define('A', 1)
  698. # else: conf.undefine('A')
  699. :param key: define name
  700. :type key: string
  701. :param val: value
  702. :type val: int or string
  703. """
  704. assert isinstance(key, str)
  705. if not key:
  706. return
  707. if val:
  708. self.define(key, 1, comment=comment)
  709. else:
  710. self.undefine(key, comment=comment)
  711. @conf
  712. def is_defined(self, key):
  713. """
  714. Indicates whether a particular define is globally set in ``conf.env.DEFINES``.
  715. :param key: define name
  716. :type key: string
  717. :return: True if the define is set
  718. :rtype: bool
  719. """
  720. assert key and isinstance(key, str)
  721. ban = key + '='
  722. for x in self.env.DEFINES:
  723. if x.startswith(ban):
  724. return True
  725. return False
  726. @conf
  727. def get_define(self, key):
  728. """
  729. Returns the value of an existing define, or None if not found
  730. :param key: define name
  731. :type key: string
  732. :rtype: string
  733. """
  734. assert key and isinstance(key, str)
  735. ban = key + '='
  736. for x in self.env.DEFINES:
  737. if x.startswith(ban):
  738. return x[len(ban):]
  739. return None
  740. @conf
  741. def have_define(self, key):
  742. """
  743. Returns a variable suitable for command-line or header use by removing invalid characters
  744. and prefixing it with ``HAVE_``
  745. :param key: define name
  746. :type key: string
  747. :return: the input key prefixed by *HAVE_* and substitute any invalid characters.
  748. :rtype: string
  749. """
  750. return (self.env.HAVE_PAT or 'HAVE_%s') % Utils.quote_define_name(key)
  751. @conf
  752. def write_config_header(self, configfile='', guard='', top=False, defines=True, headers=False, remove=True, define_prefix=''):
  753. """
  754. Writes a configuration header containing defines and includes::
  755. def configure(cnf):
  756. cnf.define('A', 1)
  757. cnf.write_config_header('config.h')
  758. This function only adds include guards (if necessary), consult
  759. :py:func:`waflib.Tools.c_config.get_config_header` for details on the body.
  760. :param configfile: path to the file to create (relative or absolute)
  761. :type configfile: string
  762. :param guard: include guard name to add, by default it is computed from the file name
  763. :type guard: string
  764. :param top: write the configuration header from the build directory (default is from the current path)
  765. :type top: bool
  766. :param defines: add the defines (yes by default)
  767. :type defines: bool
  768. :param headers: add #include in the file
  769. :type headers: bool
  770. :param remove: remove the defines after they are added (yes by default, works like in autoconf)
  771. :type remove: bool
  772. :type define_prefix: string
  773. :param define_prefix: prefix all the defines in the file with a particular prefix
  774. """
  775. if not configfile:
  776. configfile = WAF_CONFIG_H
  777. waf_guard = guard or 'W_%s_WAF' % Utils.quote_define_name(configfile)
  778. node = top and self.bldnode or self.path.get_bld()
  779. node = node.make_node(configfile)
  780. node.parent.mkdir()
  781. lst = ['/* WARNING! All changes made to this file will be lost! */\n']
  782. lst.append('#ifndef %s\n#define %s\n' % (waf_guard, waf_guard))
  783. lst.append(self.get_config_header(defines, headers, define_prefix=define_prefix))
  784. lst.append('\n#endif /* %s */\n' % waf_guard)
  785. node.write('\n'.join(lst))
  786. # config files must not be removed on "waf clean"
  787. self.env.append_unique(Build.CFG_FILES, [node.abspath()])
  788. if remove:
  789. for key in self.env[DEFKEYS]:
  790. self.undefine(key)
  791. self.env[DEFKEYS] = []
  792. @conf
  793. def get_config_header(self, defines=True, headers=False, define_prefix=''):
  794. """
  795. Creates the contents of a ``config.h`` file from the defines and includes
  796. set in conf.env.define_key / conf.env.include_key. No include guards are added.
  797. A prelude will be added from the variable env.WAF_CONFIG_H_PRELUDE if provided. This
  798. can be used to insert complex macros or include guards::
  799. def configure(conf):
  800. conf.env.WAF_CONFIG_H_PRELUDE = '#include <unistd.h>\\n'
  801. conf.write_config_header('config.h')
  802. :param defines: write the defines values
  803. :type defines: bool
  804. :param headers: write include entries for each element in self.env.INCKEYS
  805. :type headers: bool
  806. :type define_prefix: string
  807. :param define_prefix: prefix all the defines with a particular prefix
  808. :return: the contents of a ``config.h`` file
  809. :rtype: string
  810. """
  811. lst = []
  812. if self.env.WAF_CONFIG_H_PRELUDE:
  813. lst.append(self.env.WAF_CONFIG_H_PRELUDE)
  814. if headers:
  815. for x in self.env[INCKEYS]:
  816. lst.append('#include <%s>' % x)
  817. if defines:
  818. tbl = {}
  819. for k in self.env.DEFINES:
  820. a, _, b = k.partition('=')
  821. tbl[a] = b
  822. for k in self.env[DEFKEYS]:
  823. caption = self.get_define_comment(k)
  824. if caption:
  825. caption = ' /* %s */' % caption
  826. try:
  827. txt = '#define %s%s %s%s' % (define_prefix, k, tbl[k], caption)
  828. except KeyError:
  829. txt = '/* #undef %s%s */%s' % (define_prefix, k, caption)
  830. lst.append(txt)
  831. return "\n".join(lst)
  832. @conf
  833. def cc_add_flags(conf):
  834. """
  835. Adds CFLAGS / CPPFLAGS from os.environ to conf.env
  836. """
  837. conf.add_os_flags('CPPFLAGS', dup=False)
  838. conf.add_os_flags('CFLAGS', dup=False)
  839. @conf
  840. def cxx_add_flags(conf):
  841. """
  842. Adds CXXFLAGS / CPPFLAGS from os.environ to conf.env
  843. """
  844. conf.add_os_flags('CPPFLAGS', dup=False)
  845. conf.add_os_flags('CXXFLAGS', dup=False)
  846. @conf
  847. def link_add_flags(conf):
  848. """
  849. Adds LINKFLAGS / LDFLAGS from os.environ to conf.env
  850. """
  851. conf.add_os_flags('LINKFLAGS', dup=False)
  852. conf.add_os_flags('LDFLAGS', dup=False)
  853. @conf
  854. def cc_load_tools(conf):
  855. """
  856. Loads the Waf c extensions
  857. """
  858. if not conf.env.DEST_OS:
  859. conf.env.DEST_OS = Utils.unversioned_sys_platform()
  860. conf.load('c')
  861. @conf
  862. def cxx_load_tools(conf):
  863. """
  864. Loads the Waf c++ extensions
  865. """
  866. if not conf.env.DEST_OS:
  867. conf.env.DEST_OS = Utils.unversioned_sys_platform()
  868. conf.load('cxx')
  869. @conf
  870. def get_cc_version(conf, cc, gcc=False, icc=False, clang=False):
  871. """
  872. Runs the preprocessor to determine the gcc/icc/clang version
  873. The variables CC_VERSION, DEST_OS, DEST_BINFMT and DEST_CPU will be set in *conf.env*
  874. :raise: :py:class:`waflib.Errors.ConfigurationError`
  875. """
  876. cmd = cc + ['-dM', '-E', '-']
  877. env = conf.env.env or None
  878. try:
  879. out, err = conf.cmd_and_log(cmd, output=0, input='\n'.encode(), env=env)
  880. except Errors.WafError:
  881. conf.fatal('Could not determine the compiler version %r' % cmd)
  882. if gcc:
  883. if out.find('__INTEL_COMPILER') >= 0:
  884. conf.fatal('The intel compiler pretends to be gcc')
  885. if out.find('__GNUC__') < 0 and out.find('__clang__') < 0:
  886. conf.fatal('Could not determine the compiler type')
  887. if icc and out.find('__INTEL_COMPILER') < 0:
  888. conf.fatal('Not icc/icpc')
  889. if clang and out.find('__clang__') < 0:
  890. conf.fatal('Not clang/clang++')
  891. if not clang and out.find('__clang__') >= 0:
  892. conf.fatal('Could not find gcc/g++ (only Clang), if renamed try eg: CC=gcc48 CXX=g++48 waf configure')
  893. k = {}
  894. if icc or gcc or clang:
  895. out = out.splitlines()
  896. for line in out:
  897. lst = shlex.split(line)
  898. if len(lst)>2:
  899. key = lst[1]
  900. val = lst[2]
  901. k[key] = val
  902. def isD(var):
  903. return var in k
  904. # Some documentation is available at http://predef.sourceforge.net
  905. # The names given to DEST_OS must match what Utils.unversioned_sys_platform() returns.
  906. if not conf.env.DEST_OS:
  907. conf.env.DEST_OS = ''
  908. for i in MACRO_TO_DESTOS:
  909. if isD(i):
  910. conf.env.DEST_OS = MACRO_TO_DESTOS[i]
  911. break
  912. else:
  913. if isD('__APPLE__') and isD('__MACH__'):
  914. conf.env.DEST_OS = 'darwin'
  915. elif isD('__unix__'): # unix must be tested last as it's a generic fallback
  916. conf.env.DEST_OS = 'generic'
  917. if isD('__ELF__'):
  918. conf.env.DEST_BINFMT = 'elf'
  919. elif isD('__WINNT__') or isD('__CYGWIN__') or isD('_WIN32'):
  920. conf.env.DEST_BINFMT = 'pe'
  921. if not conf.env.IMPLIBDIR:
  922. conf.env.IMPLIBDIR = conf.env.LIBDIR # for .lib or .dll.a files
  923. conf.env.LIBDIR = conf.env.BINDIR
  924. elif isD('__APPLE__'):
  925. conf.env.DEST_BINFMT = 'mac-o'
  926. if not conf.env.DEST_BINFMT:
  927. # Infer the binary format from the os name.
  928. conf.env.DEST_BINFMT = Utils.destos_to_binfmt(conf.env.DEST_OS)
  929. for i in MACRO_TO_DEST_CPU:
  930. if isD(i):
  931. conf.env.DEST_CPU = MACRO_TO_DEST_CPU[i]
  932. break
  933. Logs.debug('ccroot: dest platform: ' + ' '.join([conf.env[x] or '?' for x in ('DEST_OS', 'DEST_BINFMT', 'DEST_CPU')]))
  934. if icc:
  935. ver = k['__INTEL_COMPILER']
  936. conf.env.CC_VERSION = (ver[:-2], ver[-2], ver[-1])
  937. else:
  938. if isD('__clang__') and isD('__clang_major__'):
  939. conf.env.CC_VERSION = (k['__clang_major__'], k['__clang_minor__'], k['__clang_patchlevel__'])
  940. else:
  941. # older clang versions and gcc
  942. conf.env.CC_VERSION = (k['__GNUC__'], k['__GNUC_MINOR__'], k.get('__GNUC_PATCHLEVEL__', '0'))
  943. return k
  944. @conf
  945. def get_xlc_version(conf, cc):
  946. """
  947. Returns the Aix compiler version
  948. :raise: :py:class:`waflib.Errors.ConfigurationError`
  949. """
  950. cmd = cc + ['-qversion']
  951. try:
  952. out, err = conf.cmd_and_log(cmd, output=0)
  953. except Errors.WafError:
  954. conf.fatal('Could not find xlc %r' % cmd)
  955. # the intention is to catch the 8.0 in "IBM XL C/C++ Enterprise Edition V8.0 for AIX..."
  956. for v in (r"IBM XL C/C\+\+.* V(?P<major>\d*)\.(?P<minor>\d*)",):
  957. version_re = re.compile(v, re.I).search
  958. match = version_re(out or err)
  959. if match:
  960. k = match.groupdict()
  961. conf.env.CC_VERSION = (k['major'], k['minor'])
  962. break
  963. else:
  964. conf.fatal('Could not determine the XLC version.')
  965. @conf
  966. def get_suncc_version(conf, cc):
  967. """
  968. Returns the Sun compiler version
  969. :raise: :py:class:`waflib.Errors.ConfigurationError`
  970. """
  971. cmd = cc + ['-V']
  972. try:
  973. out, err = conf.cmd_and_log(cmd, output=0)
  974. except Errors.WafError as e:
  975. # Older versions of the compiler exit with non-zero status when reporting their version
  976. if not (hasattr(e, 'returncode') and hasattr(e, 'stdout') and hasattr(e, 'stderr')):
  977. conf.fatal('Could not find suncc %r' % cmd)
  978. out = e.stdout
  979. err = e.stderr
  980. version = (out or err)
  981. version = version.splitlines()[0]
  982. # cc: Sun C 5.10 SunOS_i386 2009/06/03
  983. # cc: Studio 12.5 Sun C++ 5.14 SunOS_sparc Beta 2015/11/17
  984. # cc: WorkShop Compilers 5.0 98/12/15 C 5.0
  985. version_re = re.compile(r'cc: (studio.*?|\s+)?(sun\s+(c\+\+|c)|(WorkShop\s+Compilers))?\s+(?P<major>\d*)\.(?P<minor>\d*)', re.I).search
  986. match = version_re(version)
  987. if match:
  988. k = match.groupdict()
  989. conf.env.CC_VERSION = (k['major'], k['minor'])
  990. else:
  991. conf.fatal('Could not determine the suncc version.')
  992. # ============ the --as-needed flag should added during the configuration, not at runtime =========
  993. @conf
  994. def add_as_needed(self):
  995. """
  996. Adds ``--as-needed`` to the *LINKFLAGS*
  997. On some platforms, it is a default flag. In some cases (e.g., in NS-3) it is necessary to explicitly disable this feature with `-Wl,--no-as-needed` flag.
  998. """
  999. if self.env.DEST_BINFMT == 'elf' and 'gcc' in (self.env.CXX_NAME, self.env.CC_NAME):
  1000. self.env.append_unique('LINKFLAGS', '-Wl,--as-needed')
  1001. # ============ parallel configuration
  1002. class cfgtask(Task.Task):
  1003. """
  1004. A task that executes build configuration tests (calls conf.check)
  1005. Make sure to use locks if concurrent access to the same conf.env data is necessary.
  1006. """
  1007. def __init__(self, *k, **kw):
  1008. Task.Task.__init__(self, *k, **kw)
  1009. self.run_after = set()
  1010. def display(self):
  1011. return ''
  1012. def runnable_status(self):
  1013. for x in self.run_after:
  1014. if not x.hasrun:
  1015. return Task.ASK_LATER
  1016. return Task.RUN_ME
  1017. def uid(self):
  1018. return Utils.SIG_NIL
  1019. def signature(self):
  1020. return Utils.SIG_NIL
  1021. def run(self):
  1022. conf = self.conf
  1023. bld = Build.BuildContext(top_dir=conf.srcnode.abspath(), out_dir=conf.bldnode.abspath())
  1024. bld.env = conf.env
  1025. bld.init_dirs()
  1026. bld.in_msg = 1 # suppress top-level start_msg
  1027. bld.logger = self.logger
  1028. bld.multicheck_task = self
  1029. args = self.args
  1030. try:
  1031. if 'func' in args:
  1032. bld.test(build_fun=args['func'],
  1033. msg=args.get('msg', ''),
  1034. okmsg=args.get('okmsg', ''),
  1035. errmsg=args.get('errmsg', ''),
  1036. )
  1037. else:
  1038. args['multicheck_mandatory'] = args.get('mandatory', True)
  1039. args['mandatory'] = True
  1040. try:
  1041. bld.check(**args)
  1042. finally:
  1043. args['mandatory'] = args['multicheck_mandatory']
  1044. except Exception:
  1045. return 1
  1046. def process(self):
  1047. Task.Task.process(self)
  1048. if 'msg' in self.args:
  1049. with self.generator.bld.multicheck_lock:
  1050. self.conf.start_msg(self.args['msg'])
  1051. if self.hasrun == Task.NOT_RUN:
  1052. self.conf.end_msg('test cancelled', 'YELLOW')
  1053. elif self.hasrun != Task.SUCCESS:
  1054. self.conf.end_msg(self.args.get('errmsg', 'no'), 'YELLOW')
  1055. else:
  1056. self.conf.end_msg(self.args.get('okmsg', 'yes'), 'GREEN')
  1057. @conf
  1058. def multicheck(self, *k, **kw):
  1059. """
  1060. Runs configuration tests in parallel; results are printed sequentially at the end of the build
  1061. but each test must provide its own msg value to display a line::
  1062. def test_build(ctx):
  1063. ctx.in_msg = True # suppress console outputs
  1064. ctx.check_large_file(mandatory=False)
  1065. conf.multicheck(
  1066. {'header_name':'stdio.h', 'msg':'... stdio', 'uselib_store':'STDIO', 'global_define':False},
  1067. {'header_name':'xyztabcd.h', 'msg':'... optional xyztabcd.h', 'mandatory': False},
  1068. {'header_name':'stdlib.h', 'msg':'... stdlib', 'okmsg': 'aye', 'errmsg': 'nope'},
  1069. {'func': test_build, 'msg':'... testing an arbitrary build function', 'okmsg':'ok'},
  1070. msg = 'Checking for headers in parallel',
  1071. mandatory = True, # mandatory tests raise an error at the end
  1072. run_all_tests = True, # try running all tests
  1073. )
  1074. The configuration tests may modify the values in conf.env in any order, and the define
  1075. values can affect configuration tests being executed. It is hence recommended
  1076. to provide `uselib_store` values with `global_define=False` to prevent such issues.
  1077. """
  1078. self.start_msg(kw.get('msg', 'Executing %d configuration tests' % len(k)), **kw)
  1079. # Force a copy so that threads append to the same list at least
  1080. # no order is guaranteed, but the values should not disappear at least
  1081. for var in ('DEFINES', DEFKEYS):
  1082. self.env.append_value(var, [])
  1083. self.env.DEFINE_COMMENTS = self.env.DEFINE_COMMENTS or {}
  1084. # define a task object that will execute our tests
  1085. class par(object):
  1086. def __init__(self):
  1087. self.keep = False
  1088. self.task_sigs = {}
  1089. self.progress_bar = 0
  1090. def total(self):
  1091. return len(tasks)
  1092. def to_log(self, *k, **kw):
  1093. return
  1094. bld = par()
  1095. bld.keep = kw.get('run_all_tests', True)
  1096. bld.imp_sigs = {}
  1097. tasks = []
  1098. id_to_task = {}
  1099. for dct in k:
  1100. x = Task.classes['cfgtask'](bld=bld, env=None)
  1101. tasks.append(x)
  1102. x.args = dct
  1103. x.bld = bld
  1104. x.conf = self
  1105. x.args = dct
  1106. # bind a logger that will keep the info in memory
  1107. x.logger = Logs.make_mem_logger(str(id(x)), self.logger)
  1108. if 'id' in dct:
  1109. id_to_task[dct['id']] = x
  1110. # second pass to set dependencies with after_test/before_test
  1111. for x in tasks:
  1112. for key in Utils.to_list(x.args.get('before_tests', [])):
  1113. tsk = id_to_task[key]
  1114. if not tsk:
  1115. raise ValueError('No test named %r' % key)
  1116. tsk.run_after.add(x)
  1117. for key in Utils.to_list(x.args.get('after_tests', [])):
  1118. tsk = id_to_task[key]
  1119. if not tsk:
  1120. raise ValueError('No test named %r' % key)
  1121. x.run_after.add(tsk)
  1122. def it():
  1123. yield tasks
  1124. while 1:
  1125. yield []
  1126. bld.producer = p = Runner.Parallel(bld, Options.options.jobs)
  1127. bld.multicheck_lock = Utils.threading.Lock()
  1128. p.biter = it()
  1129. self.end_msg('started')
  1130. p.start()
  1131. # flush the logs in order into the config.log
  1132. for x in tasks:
  1133. x.logger.memhandler.flush()
  1134. self.start_msg('-> processing test results')
  1135. if p.error:
  1136. for x in p.error:
  1137. if getattr(x, 'err_msg', None):
  1138. self.to_log(x.err_msg)
  1139. self.end_msg('fail', color='RED')
  1140. raise Errors.WafError('There is an error in the library, read config.log for more information')
  1141. failure_count = 0
  1142. for x in tasks:
  1143. if x.hasrun not in (Task.SUCCESS, Task.NOT_RUN):
  1144. failure_count += 1
  1145. if failure_count:
  1146. self.end_msg(kw.get('errmsg', '%s test failed' % failure_count), color='YELLOW', **kw)
  1147. else:
  1148. self.end_msg('all ok', **kw)
  1149. for x in tasks:
  1150. if x.hasrun != Task.SUCCESS:
  1151. if x.args.get('mandatory', True):
  1152. self.fatal(kw.get('fatalmsg') or 'One of the tests has failed, read config.log for more information')
  1153. @conf
  1154. def check_gcc_o_space(self, mode='c'):
  1155. if int(self.env.CC_VERSION[0]) > 4:
  1156. # this is for old compilers
  1157. return
  1158. self.env.stash()
  1159. if mode == 'c':
  1160. self.env.CCLNK_TGT_F = ['-o', '']
  1161. elif mode == 'cxx':
  1162. self.env.CXXLNK_TGT_F = ['-o', '']
  1163. features = '%s %sshlib' % (mode, mode)
  1164. try:
  1165. self.check(msg='Checking if the -o link must be split from arguments', fragment=SNIP_EMPTY_PROGRAM, features=features)
  1166. except self.errors.ConfigurationError:
  1167. self.env.revert()
  1168. else:
  1169. self.env.commit()