3 # Thomas Nagy, 2005-2018 (ita)
6 C/C++/D configuration helpers
9 from __future__
import with_statement
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;
30 '__linux__' : 'linux',
31 '__GNU__' : 'gnu', # hurd
32 '__FreeBSD__' : 'freebsd',
33 '__NetBSD__' : 'netbsd',
34 '__OpenBSD__' : 'openbsd',
39 '__CYGWIN__' : 'cygwin',
40 '__MSYS__' : 'cygwin',
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
48 '__native_client__' : 'nacl' # google native client platform
52 '__x86_64__' : 'x86_64',
53 '__amd64__' : 'x86_64',
57 '__sparc__' : 'sparc',
58 '__alpha__' : 'alpha',
59 '__aarch64__' : 'aarch64',
60 '__thumb__' : 'thumb',
63 '__powerpc__' : 'powerpc',
64 '__ppc__' : 'powerpc',
65 '__convex__' : 'convex',
67 '__s390x__' : 's390x',
70 '__xtensa__' : 'xtensa',
74 def parse_flags(self
, line
, uselib_store
, env
=None, force_static
=False, posix
=None):
76 Parses flags from the input lines, and adds them to the relevant use variables::
79 conf.parse_flags('-O3', 'FOO')
80 # conf.env.CXXFLAGS_FOO = ['-O3']
81 # conf.env.CFLAGS_FOO = ['-O3']
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`
91 assert(isinstance(line
, str))
99 posix
= ('\\ ' in line
) or ('\\\\' in line
)
101 lex
= shlex
.shlex(line
, posix
=posix
)
102 lex
.whitespace_split
= True
106 # append_unique is not always possible
107 # for example, apple flags may require both -arch i386 and -arch ppc
108 uselib
= uselib_store
110 env
.append_value('%s_%s' % (var
, uselib
), val
)
112 env
.append_unique('%s_%s' % (var
, uselib
), val
)
119 if st
== '-I' or st
== '/I':
124 tmp
= [x
, lst
.pop(0)]
127 elif st
== '-D' or (env
.CXX_NAME
== 'msvc' and st
== '/D'): # not perfect but..
134 prefix
= 'STLIB' if (force_static
or static
) else 'LIB'
139 prefix
= 'STLIBPATH' if (force_static
or static
) else 'LIBPATH'
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'
147 elif x
.startswith('+') or x
in ('-pthread', '-fPIC', '-fpic', '-fPIE', '-fpie'):
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,'):
159 elif x
.startswith('-Wl,-R'):
161 elif x
.startswith('-Wl,-rpath,'):
163 elif x
== '-Wl,-Bstatic' or x
== '-Bstatic':
165 elif x
== '-Wl,-Bdynamic' or x
== '-Bdynamic':
167 elif x
.startswith('-Wl') or x
in ('-rdynamic', '-pie'):
169 elif x
.startswith(('-m', '-f', '-dynamic', '-O', '-g')):
170 # Adding the -W option breaks python builds on Openindiana
173 elif x
.startswith('-bundle'):
175 elif x
.startswith(('-undefined', '-Xlinker')):
177 app('LINKFLAGS', [x
, arg
])
178 elif x
.startswith(('-arch', '-isysroot')):
179 tmp
= [x
, lst
.pop(0)]
182 app('LINKFLAGS', tmp
)
183 elif x
.endswith(('.a', '.so', '.dylib', '.lib')):
184 appu('LINKFLAGS', x
) # not cool, #762
186 self
.to_log('Unhandled flag %r' % x
)
189 def validate_cfg(self
, kw
):
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`.
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
198 :param okmsg: message to display when the test is successful
200 :param errmsg: message to display in case of error
204 if not self
.env
.PKGCONFIG
:
205 self
.find_program('pkg-config', var
='PKGCONFIG')
206 kw
['path'] = self
.env
.PKGCONFIG
208 # verify that exactly one action is requested
209 s
= ('atleast_pkgconfig_version' in kw
) + ('modversion' in kw
) + ('package' in kw
)
211 raise ValueError('exactly one of atleast_pkgconfig_version, modversion and package must be set')
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']
218 kw
['msg'] = 'Checking for %r' %(kw
['package'])
220 # let the modversion check set the okmsg to the detected version
221 if not 'okmsg' in kw
and not 'modversion' in kw
:
223 if not 'errmsg' in kw
:
224 kw
['errmsg'] = 'not found'
227 if 'atleast_pkgconfig_version' in kw
:
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'])
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'])
241 def exec_cfg(self
, kw
):
243 Executes ``pkg-config`` or other ``-config`` applications to collect configuration flags:
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
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)
265 path
= Utils
.to_list(kw
['path'])
266 env
= self
.env
.env
or None
267 if kw
.get('pkg_config_path'):
269 env
= dict(self
.environ
)
270 env
['PKG_CONFIG_PATH'] = kw
['pkg_config_path']
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)
278 self
.env
.append_unique('DEFINES_%s' % kw
['uselib_store'], "%s=1" % define_name
)
280 if kw
.get('add_have_to_env', 1):
281 self
.env
[define_name
] = 1
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
)
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
)
299 defi
= kw
.get('define_variable')
301 defi
= self
.env
.PKG_CONFIG_DEFINES
or {}
302 for key
, val
in defi
.items():
303 lst
.append('--define-variable=%s=%s' % (key
, val
))
305 static
= kw
.get('force_static', False)
307 args
= Utils
.to_list(kw
['args'])
308 if '--static' in args
or '--static-libs' in args
:
312 # tools like pkgconf expect the package argument after the -- ones -_-
313 lst
.extend(Utils
.to_list(kw
['package']))
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'])
320 val
= self
.cmd_and_log(lst
+ ['--variable=' + v
], env
=env
).strip()
321 var
= '%s_%s' % (kw
['uselib_store'], v
)
325 # so we assume the command-line will output flags to be parsed afterwards
326 ret
= self
.cmd_and_log(lst
, env
=env
)
329 self
.parse_flags(ret
, kw
['uselib_store'], kw
.get('env', self
.env
), force_static
=static
, posix
=kw
.get('posix'))
333 def check_cfg(self
, *k
, **kw
):
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`
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)
352 conf.check_cfg(package='gtk+-2.0', variables=['includedir', 'prefix'], uselib_store='FOO')
353 print(conf.env.FOO_includedir)
355 self
.validate_cfg(kw
)
357 self
.start_msg(kw
['msg'], **kw
)
360 ret
= self
.exec_cfg(kw
)
361 except self
.errors
.WafError
as e
:
363 self
.end_msg(kw
['errmsg'], 'YELLOW', **kw
)
365 self
.to_log('Command failure: %s' % e
)
366 self
.fatal('The configuration failed')
372 self
.end_msg(self
.ret_msg(kw
['okmsg'], kw
), **kw
)
378 Build function that is used for running configuration tests with ``conf.check()``
380 if bld
.kw
['compile_filename']:
381 node
= bld
.srcnode
.make_node(bld
.kw
['compile_filename'])
382 node
.write(bld
.kw
['code'])
384 o
= bld(features
=bld
.kw
['features'], source
=bld
.kw
['compile_filename'], target
='testprog')
386 for k
, v
in bld
.kw
.items():
389 if not bld
.kw
.get('quiet'):
390 bld
.conf
.to_log("==>\n%s\n<==" % bld
.kw
['code'])
393 def validate_c(self
, kw
):
395 Pre-checks the parameters that will be given to :py:func:`waflib.Configure.run_build`
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
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
420 for x
in ('type_name', 'field_name', 'function_name'):
422 Logs
.warn('Invalid argument %r in test' % x
)
424 if not 'build_fun' in kw
:
425 kw
['build_fun'] = build_fun
428 kw
['env'] = self
.env
.derive()
431 if not 'compiler' in kw
and not 'features' in kw
:
433 if env
.CXX_NAME
and Task
.classes
.get('cxx'):
434 kw
['compiler'] = 'cxx'
436 self
.fatal('a c++ compiler is required')
439 self
.fatal('a c compiler is required')
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'
447 kw
['type'] = 'cprogram'
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"
453 kw
['features'] = [kw
['compile_mode']]
455 kw
['features'] = Utils
.to_list(kw
['features'])
457 if not 'compile_filename' in kw
:
458 kw
['compile_filename'] = 'test.c' + ((kw
['compile_mode'] == 'cxx') and 'pp' or '')
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
])
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'):
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
480 elif 'header_name' in kw
:
482 kw
['msg'] = 'Checking for header %s' % kw
['header_name']
484 l
= Utils
.to_list(kw
['header_name'])
485 assert len(l
), 'list of headers in header_name is empty'
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])
495 kw
['msg'] = 'Checking for library %s' % kw
['lib']
496 if not 'uselib_store' in kw
:
497 kw
['uselib_store'] = kw
['lib'].upper()
501 kw
['msg'] = 'Checking for static library %s' % kw
['stlib']
502 if not 'uselib_store' in kw
:
503 kw
['uselib_store'] = kw
['stlib'].upper()
506 # an additional code fragment may be provided to replace the predefined code
508 kw
['code'] = kw
['fragment']
510 kw
['msg'] = 'Checking for code snippet'
511 if not 'errmsg' in kw
:
514 for (flagsname
,flagstype
) in (('cxxflags','compiler'), ('cflags','compiler'), ('linkflags','linker')):
517 kw
['msg'] = 'Checking for %s flags %s' % (flagstype
, kw
[flagsname
])
518 if not 'errmsg' in kw
:
521 if not 'execute' in kw
:
522 kw
['execute'] = False
524 kw
['features'].append('test_exec')
525 kw
['chmod'] = Utils
.O755
527 if not 'errmsg' in kw
:
528 kw
['errmsg'] = 'not found'
530 if not 'okmsg' in kw
:
534 kw
['code'] = SNIP_EMPTY_PROGRAM
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']
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
545 if not kw
.get('success'):
548 if 'define_name' in kw
:
549 self
.undefine(kw
['define_name'])
551 self
.fatal('missing "msg" in conf.check(...)')
554 def post_check(self
, *k
, **kw
):
556 Sets the variables after a test executed in
557 :py:func:`waflib.Tools.c_config.check` was run successfully
561 if kw
['success'] is not None:
562 if kw
.get('define_ret'):
563 is_success
= kw
['success']
565 is_success
= (kw
['success'] == 0)
567 is_success
= (kw
['success'] == 0)
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
)
576 if kw
.get('quote', 1):
577 succ
= '"%s"' % is_success
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
)
584 if kw
.get('global_define', 1):
585 self
.define_cond(define_name
, is_success
, comment
=comment
)
587 var
= 'DEFINES_%s' % kw
['uselib_store']
588 self
.env
.append_value(var
, '%s=%s' % (define_name
, int(is_success
)))
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
597 self
.env
[define_name
] = int(is_success
)
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']))
603 if is_success
and 'uselib_store' in kw
:
604 from waflib
.Tools
import ccroot
605 # See get_uselib_vars in ccroot.py
607 for x
in kw
['features']:
608 if x
in ccroot
.USELIB_VARS
:
609 _vars |
= ccroot
.USELIB_VARS
[x
]
614 self
.env
.append_value(k
+ '_' + kw
['uselib_store'], kw
[x
])
618 def check(self
, *k
, **kw
):
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
624 Besides build targets, complete builds can be given through a build function. All files will
625 be written to a temporary directory::
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)
635 self
.start_msg(kw
['msg'], **kw
)
638 ret
= self
.run_build(*k
, **kw
)
639 except self
.errors
.ConfigurationError
:
640 self
.end_msg(kw
['errmsg'], 'YELLOW', **kw
)
644 self
.fatal('The configuration failed')
648 ret
= self
.post_check(*k
, **kw
)
650 self
.end_msg(kw
['errmsg'], 'YELLOW', **kw
)
651 self
.fatal('The configuration failed %r' % ret
)
653 self
.end_msg(self
.ret_msg(kw
['okmsg'], kw
), **kw
)
656 class test_exec(Task
.Task
):
658 A task that runs programs after they are built. See :py:func:`waflib.Tools.c_config.test_exec_fun`.
662 if getattr(self
.generator
, 'rpath', None):
663 if getattr(self
.generator
, 'define_ret', False):
664 self
.generator
.bld
.retval
= self
.generator
.bld
.cmd_and_log([self
.inputs
[0].abspath()])
666 self
.generator
.bld
.retval
= self
.generator
.bld
.exec_command([self
.inputs
[0].abspath()])
668 env
= self
.env
.env
or {}
669 env
.update(dict(os
.environ
))
670 for var
in ('LD_LIBRARY_PATH', 'DYLD_LIBRARY_PATH', 'PATH'):
671 env
[var
] = self
.inputs
[0].parent
.abspath() + os
.path
.pathsep
+ env
.get(var
, '')
672 if getattr(self
.generator
, 'define_ret', False):
673 self
.generator
.bld
.retval
= self
.generator
.bld
.cmd_and_log([self
.inputs
[0].abspath()], env
=env
)
675 self
.generator
.bld
.retval
= self
.generator
.bld
.exec_command([self
.inputs
[0].abspath()], env
=env
)
677 @feature('test_exec')
678 @after_method('apply_link')
679 def test_exec_fun(self
):
681 The feature **test_exec** is used to create a task that will to execute the binary
682 created (link task output) during the build. The exit status will be set
683 on the build context, so only one program may have the feature *test_exec*.
684 This is used by configuration tests::
687 conf.check(execute=True)
689 self
.create_task('test_exec', self
.link_task
.outputs
[0])
692 def check_cxx(self
, *k
, **kw
):
694 Runs a test with a task generator of the form::
696 conf.check(features='cxx cxxprogram', ...)
698 kw
['compiler'] = 'cxx'
699 return self
.check(*k
, **kw
)
702 def check_cc(self
, *k
, **kw
):
704 Runs a test with a task generator of the form::
706 conf.check(features='c cprogram', ...)
709 return self
.check(*k
, **kw
)
712 def set_define_comment(self
, key
, comment
):
714 Sets a comment that will appear in the configuration header
717 :type comment: string
719 coms
= self
.env
.DEFINE_COMMENTS
721 coms
= self
.env
.DEFINE_COMMENTS
= {}
722 coms
[key
] = comment
or ''
725 def get_define_comment(self
, key
):
727 Returns the comment associated to a define
731 coms
= self
.env
.DEFINE_COMMENTS
or {}
732 return coms
.get(key
, '')
735 def define(self
, key
, val
, quote
=True, comment
=''):
737 Stores a single define and its state into ``conf.env.DEFINES``. The value is cast to an integer (0/1).
739 :param key: define name
742 :type val: int or string
743 :param quote: enclose strings in quotes (yes by default)
746 assert isinstance(key
, str)
751 elif val
in (False, None):
754 if isinstance(val
, int) or isinstance(val
, float):
757 s
= quote
and '%s="%s"' or '%s=%s'
758 app
= s
% (key
, str(val
))
761 lst
= self
.env
.DEFINES
763 if x
.startswith(ban
):
764 lst
[lst
.index(x
)] = app
767 self
.env
.append_value('DEFINES', app
)
769 self
.env
.append_unique(DEFKEYS
, key
)
770 self
.set_define_comment(key
, comment
)
773 def undefine(self
, key
, comment
=''):
775 Removes a global define from ``conf.env.DEFINES``
777 :param key: define name
780 assert isinstance(key
, str)
784 lst
= [x
for x
in self
.env
.DEFINES
if not x
.startswith(ban
)]
785 self
.env
.DEFINES
= lst
786 self
.env
.append_unique(DEFKEYS
, key
)
787 self
.set_define_comment(key
, comment
)
790 def define_cond(self
, key
, val
, comment
=''):
792 Conditionally defines a name::
795 conf.define_cond('A', True)
797 # if val: conf.define('A', 1)
798 # else: conf.undefine('A')
800 :param key: define name
803 :type val: int or string
805 assert isinstance(key
, str)
809 self
.define(key
, 1, comment
=comment
)
811 self
.undefine(key
, comment
=comment
)
814 def is_defined(self
, key
):
816 Indicates whether a particular define is globally set in ``conf.env.DEFINES``.
818 :param key: define name
820 :return: True if the define is set
823 assert key
and isinstance(key
, str)
826 for x
in self
.env
.DEFINES
:
827 if x
.startswith(ban
):
832 def get_define(self
, key
):
834 Returns the value of an existing define, or None if not found
836 :param key: define name
840 assert key
and isinstance(key
, str)
843 for x
in self
.env
.DEFINES
:
844 if x
.startswith(ban
):
849 def have_define(self
, key
):
851 Returns a variable suitable for command-line or header use by removing invalid characters
852 and prefixing it with ``HAVE_``
854 :param key: define name
856 :return: the input key prefixed by *HAVE_* and substitute any invalid characters.
859 return (self
.env
.HAVE_PAT
or 'HAVE_%s') % Utils
.quote_define_name(key
)
862 def write_config_header(self
, configfile
='', guard
='', top
=False, defines
=True, headers
=False, remove
=True, define_prefix
=''):
864 Writes a configuration header containing defines and includes::
868 cnf.write_config_header('config.h')
870 This function only adds include guards (if necessary), consult
871 :py:func:`waflib.Tools.c_config.get_config_header` for details on the body.
873 :param configfile: path to the file to create (relative or absolute)
874 :type configfile: string
875 :param guard: include guard name to add, by default it is computed from the file name
877 :param top: write the configuration header from the build directory (default is from the current path)
879 :param defines: add the defines (yes by default)
881 :param headers: add #include in the file
883 :param remove: remove the defines after they are added (yes by default, works like in autoconf)
885 :type define_prefix: string
886 :param define_prefix: prefix all the defines in the file with a particular prefix
889 configfile
= WAF_CONFIG_H
890 waf_guard
= guard
or 'W_%s_WAF' % Utils
.quote_define_name(configfile
)
892 node
= top
and self
.bldnode
or self
.path
.get_bld()
893 node
= node
.make_node(configfile
)
896 lst
= ['/* WARNING! All changes made to this file will be lost! */\n']
897 lst
.append('#ifndef %s\n#define %s\n' % (waf_guard
, waf_guard
))
898 lst
.append(self
.get_config_header(defines
, headers
, define_prefix
=define_prefix
))
899 lst
.append('\n#endif /* %s */\n' % waf_guard
)
901 node
.write('\n'.join(lst
))
903 # config files must not be removed on "waf clean"
904 self
.env
.append_unique(Build
.CFG_FILES
, [node
.abspath()])
907 for key
in self
.env
[DEFKEYS
]:
909 self
.env
[DEFKEYS
] = []
912 def get_config_header(self
, defines
=True, headers
=False, define_prefix
=''):
914 Creates the contents of a ``config.h`` file from the defines and includes
915 set in conf.env.define_key / conf.env.include_key. No include guards are added.
917 A prelude will be added from the variable env.WAF_CONFIG_H_PRELUDE if provided. This
918 can be used to insert complex macros or include guards::
921 conf.env.WAF_CONFIG_H_PRELUDE = '#include <unistd.h>\\n'
922 conf.write_config_header('config.h')
924 :param defines: write the defines values
926 :param headers: write include entries for each element in self.env.INCKEYS
928 :type define_prefix: string
929 :param define_prefix: prefix all the defines with a particular prefix
930 :return: the contents of a ``config.h`` file
935 if self
.env
.WAF_CONFIG_H_PRELUDE
:
936 lst
.append(self
.env
.WAF_CONFIG_H_PRELUDE
)
939 for x
in self
.env
[INCKEYS
]:
940 lst
.append('#include <%s>' % x
)
944 for k
in self
.env
.DEFINES
:
945 a
, _
, b
= k
.partition('=')
948 for k
in self
.env
[DEFKEYS
]:
949 caption
= self
.get_define_comment(k
)
951 caption
= ' /* %s */' % caption
953 txt
= '#define %s%s %s%s' % (define_prefix
, k
, tbl
[k
], caption
)
955 txt
= '/* #undef %s%s */%s' % (define_prefix
, k
, caption
)
957 return "\n".join(lst
)
960 def cc_add_flags(conf
):
962 Adds CFLAGS / CPPFLAGS from os.environ to conf.env
964 conf
.add_os_flags('CPPFLAGS', dup
=False)
965 conf
.add_os_flags('CFLAGS', dup
=False)
968 def cxx_add_flags(conf
):
970 Adds CXXFLAGS / CPPFLAGS from os.environ to conf.env
972 conf
.add_os_flags('CPPFLAGS', dup
=False)
973 conf
.add_os_flags('CXXFLAGS', dup
=False)
976 def link_add_flags(conf
):
978 Adds LINKFLAGS / LDFLAGS from os.environ to conf.env
980 conf
.add_os_flags('LINKFLAGS', dup
=False)
981 conf
.add_os_flags('LDFLAGS', dup
=False)
984 def cc_load_tools(conf
):
986 Loads the Waf c extensions
988 if not conf
.env
.DEST_OS
:
989 conf
.env
.DEST_OS
= Utils
.unversioned_sys_platform()
993 def cxx_load_tools(conf
):
995 Loads the Waf c++ extensions
997 if not conf
.env
.DEST_OS
:
998 conf
.env
.DEST_OS
= Utils
.unversioned_sys_platform()
1002 def get_cc_version(conf
, cc
, gcc
=False, icc
=False, clang
=False):
1004 Runs the preprocessor to determine the gcc/icc/clang version
1006 The variables CC_VERSION, DEST_OS, DEST_BINFMT and DEST_CPU will be set in *conf.env*
1008 :raise: :py:class:`waflib.Errors.ConfigurationError`
1010 cmd
= cc
+ ['-dM', '-E', '-']
1011 env
= conf
.env
.env
or None
1013 out
, err
= conf
.cmd_and_log(cmd
, output
=0, input='\n'.encode(), env
=env
)
1014 except Errors
.WafError
:
1015 conf
.fatal('Could not determine the compiler version %r' % cmd
)
1018 if out
.find('__INTEL_COMPILER') >= 0:
1019 conf
.fatal('The intel compiler pretends to be gcc')
1020 if out
.find('__GNUC__') < 0 and out
.find('__clang__') < 0:
1021 conf
.fatal('Could not determine the compiler type')
1023 if icc
and out
.find('__INTEL_COMPILER') < 0:
1024 conf
.fatal('Not icc/icpc')
1026 if clang
and out
.find('__clang__') < 0:
1027 conf
.fatal('Not clang/clang++')
1028 if not clang
and out
.find('__clang__') >= 0:
1029 conf
.fatal('Could not find gcc/g++ (only Clang), if renamed try eg: CC=gcc48 CXX=g++48 waf configure')
1032 if icc
or gcc
or clang
:
1033 out
= out
.splitlines()
1035 lst
= shlex
.split(line
)
1044 # Some documentation is available at http://predef.sourceforge.net
1045 # The names given to DEST_OS must match what Utils.unversioned_sys_platform() returns.
1046 if not conf
.env
.DEST_OS
:
1047 conf
.env
.DEST_OS
= ''
1048 for i
in MACRO_TO_DESTOS
:
1050 conf
.env
.DEST_OS
= MACRO_TO_DESTOS
[i
]
1053 if isD('__APPLE__') and isD('__MACH__'):
1054 conf
.env
.DEST_OS
= 'darwin'
1055 elif isD('__unix__'): # unix must be tested last as it's a generic fallback
1056 conf
.env
.DEST_OS
= 'generic'
1059 conf
.env
.DEST_BINFMT
= 'elf'
1060 elif isD('__WINNT__') or isD('__CYGWIN__') or isD('_WIN32'):
1061 conf
.env
.DEST_BINFMT
= 'pe'
1062 if not conf
.env
.IMPLIBDIR
:
1063 conf
.env
.IMPLIBDIR
= conf
.env
.LIBDIR
# for .lib or .dll.a files
1064 conf
.env
.LIBDIR
= conf
.env
.BINDIR
1065 elif isD('__APPLE__'):
1066 conf
.env
.DEST_BINFMT
= 'mac-o'
1068 if not conf
.env
.DEST_BINFMT
:
1069 # Infer the binary format from the os name.
1070 conf
.env
.DEST_BINFMT
= Utils
.destos_to_binfmt(conf
.env
.DEST_OS
)
1072 for i
in MACRO_TO_DEST_CPU
:
1074 conf
.env
.DEST_CPU
= MACRO_TO_DEST_CPU
[i
]
1077 Logs
.debug('ccroot: dest platform: ' + ' '.join([conf
.env
[x
] or '?' for x
in ('DEST_OS', 'DEST_BINFMT', 'DEST_CPU')]))
1079 ver
= k
['__INTEL_COMPILER']
1080 conf
.env
.CC_VERSION
= (ver
[:-2], ver
[-2], ver
[-1])
1082 if isD('__clang__') and isD('__clang_major__'):
1083 conf
.env
.CC_VERSION
= (k
['__clang_major__'], k
['__clang_minor__'], k
['__clang_patchlevel__'])
1085 # older clang versions and gcc
1086 conf
.env
.CC_VERSION
= (k
['__GNUC__'], k
['__GNUC_MINOR__'], k
.get('__GNUC_PATCHLEVEL__', '0'))
1090 def get_xlc_version(conf
, cc
):
1092 Returns the Aix compiler version
1094 :raise: :py:class:`waflib.Errors.ConfigurationError`
1096 cmd
= cc
+ ['-qversion']
1098 out
, err
= conf
.cmd_and_log(cmd
, output
=0)
1099 except Errors
.WafError
:
1100 conf
.fatal('Could not find xlc %r' % cmd
)
1102 # the intention is to catch the 8.0 in "IBM XL C/C++ Enterprise Edition V8.0 for AIX..."
1103 for v
in (r
"IBM XL C/C\+\+.* V(?P<major>\d*)\.(?P<minor>\d*)",):
1104 version_re
= re
.compile(v
, re
.I
).search
1105 match
= version_re(out
or err
)
1107 k
= match
.groupdict()
1108 conf
.env
.CC_VERSION
= (k
['major'], k
['minor'])
1111 conf
.fatal('Could not determine the XLC version.')
1114 def get_suncc_version(conf
, cc
):
1116 Returns the Sun compiler version
1118 :raise: :py:class:`waflib.Errors.ConfigurationError`
1122 out
, err
= conf
.cmd_and_log(cmd
, output
=0)
1123 except Errors
.WafError
as e
:
1124 # Older versions of the compiler exit with non-zero status when reporting their version
1125 if not (hasattr(e
, 'returncode') and hasattr(e
, 'stdout') and hasattr(e
, 'stderr')):
1126 conf
.fatal('Could not find suncc %r' % cmd
)
1130 version
= (out
or err
)
1131 version
= version
.splitlines()[0]
1133 # cc: Sun C 5.10 SunOS_i386 2009/06/03
1134 # cc: Studio 12.5 Sun C++ 5.14 SunOS_sparc Beta 2015/11/17
1135 # cc: WorkShop Compilers 5.0 98/12/15 C 5.0
1136 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
1137 match
= version_re(version
)
1139 k
= match
.groupdict()
1140 conf
.env
.CC_VERSION
= (k
['major'], k
['minor'])
1142 conf
.fatal('Could not determine the suncc version.')
1144 # ============ the --as-needed flag should added during the configuration, not at runtime =========
1147 def add_as_needed(self
):
1149 Adds ``--as-needed`` to the *LINKFLAGS*
1150 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 if self
.env
.DEST_BINFMT
== 'elf' and 'gcc' in (self
.env
.CXX_NAME
, self
.env
.CC_NAME
):
1153 self
.env
.append_unique('LINKFLAGS', '-Wl,--as-needed')
1155 # ============ parallel configuration
1157 class cfgtask(Task
.Task
):
1159 A task that executes build configuration tests (calls conf.check)
1161 Make sure to use locks if concurrent access to the same conf.env data is necessary.
1163 def __init__(self
, *k
, **kw
):
1164 Task
.Task
.__init
__(self
, *k
, **kw
)
1165 self
.run_after
= set()
1170 def runnable_status(self
):
1171 for x
in self
.run_after
:
1173 return Task
.ASK_LATER
1177 return Utils
.SIG_NIL
1179 def signature(self
):
1180 return Utils
.SIG_NIL
1184 bld
= Build
.BuildContext(top_dir
=conf
.srcnode
.abspath(), out_dir
=conf
.bldnode
.abspath())
1187 bld
.in_msg
= 1 # suppress top-level start_msg
1188 bld
.logger
= self
.logger
1189 bld
.multicheck_task
= self
1193 bld
.test(build_fun
=args
['func'],
1194 msg
=args
.get('msg', ''),
1195 okmsg
=args
.get('okmsg', ''),
1196 errmsg
=args
.get('errmsg', ''),
1199 args
['multicheck_mandatory'] = args
.get('mandatory', True)
1200 args
['mandatory'] = True
1204 args
['mandatory'] = args
['multicheck_mandatory']
1209 Task
.Task
.process(self
)
1210 if 'msg' in self
.args
:
1211 with self
.generator
.bld
.multicheck_lock
:
1212 self
.conf
.start_msg(self
.args
['msg'])
1213 if self
.hasrun
== Task
.NOT_RUN
:
1214 self
.conf
.end_msg('test cancelled', 'YELLOW')
1215 elif self
.hasrun
!= Task
.SUCCESS
:
1216 self
.conf
.end_msg(self
.args
.get('errmsg', 'no'), 'YELLOW')
1218 self
.conf
.end_msg(self
.args
.get('okmsg', 'yes'), 'GREEN')
1221 def multicheck(self
, *k
, **kw
):
1223 Runs configuration tests in parallel; results are printed sequentially at the end of the build
1224 but each test must provide its own msg value to display a line::
1226 def test_build(ctx):
1227 ctx.in_msg = True # suppress console outputs
1228 ctx.check_large_file(mandatory=False)
1231 {'header_name':'stdio.h', 'msg':'... stdio', 'uselib_store':'STDIO', 'global_define':False},
1232 {'header_name':'xyztabcd.h', 'msg':'... optional xyztabcd.h', 'mandatory': False},
1233 {'header_name':'stdlib.h', 'msg':'... stdlib', 'okmsg': 'aye', 'errmsg': 'nope'},
1234 {'func': test_build, 'msg':'... testing an arbitrary build function', 'okmsg':'ok'},
1235 msg = 'Checking for headers in parallel',
1236 mandatory = True, # mandatory tests raise an error at the end
1237 run_all_tests = True, # try running all tests
1240 The configuration tests may modify the values in conf.env in any order, and the define
1241 values can affect configuration tests being executed. It is hence recommended
1242 to provide `uselib_store` values with `global_define=False` to prevent such issues.
1244 self
.start_msg(kw
.get('msg', 'Executing %d configuration tests' % len(k
)), **kw
)
1246 # Force a copy so that threads append to the same list at least
1247 # no order is guaranteed, but the values should not disappear at least
1248 for var
in ('DEFINES', DEFKEYS
):
1249 self
.env
.append_value(var
, [])
1250 self
.env
.DEFINE_COMMENTS
= self
.env
.DEFINE_COMMENTS
or {}
1252 # define a task object that will execute our tests
1257 self
.progress_bar
= 0
1260 def to_log(self
, *k
, **kw
):
1264 bld
.keep
= kw
.get('run_all_tests', True)
1270 x
= Task
.classes
['cfgtask'](bld
=bld
, env
=None)
1277 # bind a logger that will keep the info in memory
1278 x
.logger
= Logs
.make_mem_logger(str(id(x
)), self
.logger
)
1281 id_to_task
[dct
['id']] = x
1283 # second pass to set dependencies with after_test/before_test
1285 for key
in Utils
.to_list(x
.args
.get('before_tests', [])):
1286 tsk
= id_to_task
[key
]
1288 raise ValueError('No test named %r' % key
)
1289 tsk
.run_after
.add(x
)
1290 for key
in Utils
.to_list(x
.args
.get('after_tests', [])):
1291 tsk
= id_to_task
[key
]
1293 raise ValueError('No test named %r' % key
)
1294 x
.run_after
.add(tsk
)
1300 bld
.producer
= p
= Runner
.Parallel(bld
, Options
.options
.jobs
)
1301 bld
.multicheck_lock
= Utils
.threading
.Lock()
1304 self
.end_msg('started')
1307 # flush the logs in order into the config.log
1309 x
.logger
.memhandler
.flush()
1311 self
.start_msg('-> processing test results')
1314 if getattr(x
, 'err_msg', None):
1315 self
.to_log(x
.err_msg
)
1316 self
.end_msg('fail', color
='RED')
1317 raise Errors
.WafError('There is an error in the library, read config.log for more information')
1321 if x
.hasrun
not in (Task
.SUCCESS
, Task
.NOT_RUN
):
1325 self
.end_msg(kw
.get('errmsg', '%s test failed' % failure_count
), color
='YELLOW', **kw
)
1327 self
.end_msg('all ok', **kw
)
1330 if x
.hasrun
!= Task
.SUCCESS
:
1331 if x
.args
.get('mandatory', True):
1332 self
.fatal(kw
.get('fatalmsg') or 'One of the tests has failed, read config.log for more information')
1335 def check_gcc_o_space(self
, mode
='c'):
1336 if int(self
.env
.CC_VERSION
[0]) > 4:
1337 # this is for old compilers
1341 self
.env
.CCLNK_TGT_F
= ['-o', '']
1343 self
.env
.CXXLNK_TGT_F
= ['-o', '']
1344 features
= '%s %sshlib' % (mode
, mode
)
1346 self
.check(msg
='Checking if the -o link must be split from arguments', fragment
=SNIP_EMPTY_PROGRAM
, features
=features
)
1347 except self
.errors
.ConfigurationError
: