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