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