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