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',
76 def parse_flags(self
, line
, uselib_store
, env
=None, force_static
=False, posix
=None):
78 Parses flags from the input lines, and adds them to the relevant use variables::
81 conf.parse_flags('-O3', 'FOO')
82 # conf.env.CXXFLAGS_FOO = ['-O3']
83 # conf.env.CFLAGS_FOO = ['-O3']
87 :param uselib_store: where to add the flags
88 :type uselib_store: string
89 :param env: config set or conf.env by default
90 :type env: :py:class:`waflib.ConfigSet.ConfigSet`
91 :param force_static: force usage of static libraries
92 :type force_static: bool default False
93 :param posix: usage of POSIX mode for shlex lexical analiysis library
94 :type posix: bool default True
97 assert(isinstance(line
, str))
105 posix
= ('\\ ' in line
) or ('\\\\' in line
)
107 lex
= shlex
.shlex(line
, posix
=posix
)
108 lex
.whitespace_split
= True
112 so_re
= re
.compile(r
"\.so(?:\.[0-9]+)*$")
114 # append_unique is not always possible
115 # for example, apple flags may require both -arch i386 and -arch ppc
116 uselib
= uselib_store
118 env
.append_value('%s_%s' % (var
, uselib
), val
)
120 env
.append_unique('%s_%s' % (var
, uselib
), val
)
127 if st
== '-I' or st
== '/I':
132 tmp
= [x
, lst
.pop(0)]
135 elif st
== '-D' or (env
.CXX_NAME
== 'msvc' and st
== '/D'): # not perfect but..
142 prefix
= 'STLIB' if (force_static
or static
) else 'LIB'
147 prefix
= 'STLIBPATH' if (force_static
or static
) else 'LIBPATH'
149 elif x
.startswith('/LIBPATH:'):
150 prefix
= 'STLIBPATH' if (force_static
or static
) else 'LIBPATH'
151 appu(prefix
, x
.replace('/LIBPATH:', ''))
152 elif x
.startswith('-std='):
153 prefix
= 'CXXFLAGS' if '++' in x
else 'CFLAGS'
155 elif x
.startswith('+') or x
in ('-pthread', '-fPIC', '-fpic', '-fPIE', '-fpie', '-flto', '-fno-lto'):
159 elif x
== '-framework':
160 appu('FRAMEWORK', lst
.pop(0))
161 elif x
.startswith('-F'):
162 appu('FRAMEWORKPATH', x
[2:])
163 elif x
== '-Wl,-rpath' or x
== '-Wl,-R':
164 app('RPATH', lst
.pop(0).lstrip('-Wl,'))
165 elif x
.startswith('-Wl,-R,'):
167 elif x
.startswith('-Wl,-R'):
169 elif x
.startswith('-Wl,-rpath,'):
171 elif x
== '-Wl,-Bstatic' or x
== '-Bstatic':
173 elif x
== '-Wl,-Bdynamic' or x
== '-Bdynamic':
175 elif x
.startswith('-Wl') or x
in ('-rdynamic', '-pie'):
177 elif x
.startswith(('-m', '-f', '-dynamic', '-O', '-g')):
178 # Adding the -W option breaks python builds on Openindiana
181 elif x
.startswith('-bundle'):
183 elif x
.startswith(('-undefined', '-Xlinker')):
185 app('LINKFLAGS', [x
, arg
])
186 elif x
.startswith(('-arch', '-isysroot')):
187 tmp
= [x
, lst
.pop(0)]
190 app('LINKFLAGS', tmp
)
191 elif x
.endswith(('.a', '.dylib', '.lib')) or so_re
.search(x
):
192 appu('LINKFLAGS', x
) # not cool, #762
194 self
.to_log('Unhandled flag %r' % x
)
197 def validate_cfg(self
, kw
):
199 Searches for the program *pkg-config* if missing, and validates the
200 parameters to pass to :py:func:`waflib.Tools.c_config.exec_cfg`.
202 :param path: the **-config program to use** (default is *pkg-config*)
203 :type path: list of string
204 :param msg: message to display to describe the test executed
206 :param okmsg: message to display when the test is successful
208 :param errmsg: message to display in case of error
212 if not self
.env
.PKGCONFIG
:
213 self
.find_program('pkg-config', var
='PKGCONFIG')
214 kw
['path'] = self
.env
.PKGCONFIG
216 # verify that exactly one action is requested
217 s
= ('atleast_pkgconfig_version' in kw
) + ('modversion' in kw
) + ('package' in kw
)
219 raise ValueError('exactly one of atleast_pkgconfig_version, modversion and package must be set')
221 if 'atleast_pkgconfig_version' in kw
:
222 kw
['msg'] = 'Checking for pkg-config version >= %r' % kw
['atleast_pkgconfig_version']
223 elif 'modversion' in kw
:
224 kw
['msg'] = 'Checking for %r version' % kw
['modversion']
226 kw
['msg'] = 'Checking for %r' %(kw
['package'])
228 # let the modversion check set the okmsg to the detected version
229 if not 'okmsg' in kw
and not 'modversion' in kw
:
231 if not 'errmsg' in kw
:
232 kw
['errmsg'] = 'not found'
235 if 'atleast_pkgconfig_version' in kw
:
237 elif 'modversion' in kw
:
238 if not 'uselib_store' in kw
:
239 kw
['uselib_store'] = kw
['modversion']
240 if not 'define_name' in kw
:
241 kw
['define_name'] = '%s_VERSION' % Utils
.quote_define_name(kw
['uselib_store'])
243 if not 'uselib_store' in kw
:
244 kw
['uselib_store'] = Utils
.to_list(kw
['package'])[0].upper()
245 if not 'define_name' in kw
:
246 kw
['define_name'] = self
.have_define(kw
['uselib_store'])
249 def exec_cfg(self
, kw
):
251 Executes ``pkg-config`` or other ``-config`` applications to collect configuration flags:
253 * if atleast_pkgconfig_version is given, check that pkg-config has the version n and return
254 * if modversion is given, then return the module version
255 * else, execute the *-config* program with the *args* and *variables* given, and set the flags on the *conf.env.FLAGS_name* variable
257 :param path: the **-config program to use**
258 :type path: list of string
259 :param atleast_pkgconfig_version: minimum pkg-config version to use (disable other tests)
260 :type atleast_pkgconfig_version: string
261 :param package: package name, for example *gtk+-2.0*
262 :type package: string
263 :param uselib_store: if the test is successful, define HAVE\\_*name*. It is also used to define *conf.env.FLAGS_name* variables.
264 :type uselib_store: string
265 :param modversion: if provided, return the version of the given module and define *name*\\_VERSION
266 :type modversion: string
267 :param args: arguments to give to *package* when retrieving flags
268 :type args: list of string
269 :param variables: return the values of particular variables
270 :type variables: list of string
271 :param define_variable: additional variables to define (also in conf.env.PKG_CONFIG_DEFINES)
272 :type define_variable: dict(string: string)
273 :param pkg_config_path: paths where pkg-config should search for .pc config files (overrides env.PKG_CONFIG_PATH if exists)
274 :type pkg_config_path: string, list of directories separated by colon
275 :param force_static: force usage of static libraries
276 :type force_static: bool default False
277 :param posix: usage of POSIX mode for shlex lexical analiysis library
278 :type posix: bool default True
281 path
= Utils
.to_list(kw
['path'])
282 env
= self
.env
.env
or None
283 if kw
.get('pkg_config_path'):
285 env
= dict(self
.environ
)
286 env
['PKG_CONFIG_PATH'] = kw
['pkg_config_path']
289 define_name
= kw
['define_name']
290 # by default, add HAVE_X to the config.h, else provide DEFINES_X for use=X
291 if kw
.get('global_define', 1):
292 self
.define(define_name
, 1, False)
294 self
.env
.append_unique('DEFINES_%s' % kw
['uselib_store'], "%s=1" % define_name
)
296 if kw
.get('add_have_to_env', 1):
297 self
.env
[define_name
] = 1
300 if 'atleast_pkgconfig_version' in kw
:
301 cmd
= path
+ ['--atleast-pkgconfig-version=%s' % kw
['atleast_pkgconfig_version']]
302 self
.cmd_and_log(cmd
, env
=env
)
305 # single version for a module
306 if 'modversion' in kw
:
307 version
= self
.cmd_and_log(path
+ ['--modversion', kw
['modversion']], env
=env
).strip()
308 if not 'okmsg' in kw
:
309 kw
['okmsg'] = version
310 self
.define(kw
['define_name'], version
)
315 defi
= kw
.get('define_variable')
317 defi
= self
.env
.PKG_CONFIG_DEFINES
or {}
318 for key
, val
in defi
.items():
319 lst
.append('--define-variable=%s=%s' % (key
, val
))
321 static
= kw
.get('force_static', False)
323 args
= Utils
.to_list(kw
['args'])
324 if '--static' in args
or '--static-libs' in args
:
328 # tools like pkgconf expect the package argument after the -- ones -_-
329 lst
.extend(Utils
.to_list(kw
['package']))
331 # retrieving variables of a module
332 if 'variables' in kw
:
333 v_env
= kw
.get('env', self
.env
)
334 vars = Utils
.to_list(kw
['variables'])
336 val
= self
.cmd_and_log(lst
+ ['--variable=' + v
], env
=env
).strip()
337 var
= '%s_%s' % (kw
['uselib_store'], v
)
341 # so we assume the command-line will output flags to be parsed afterwards
342 ret
= self
.cmd_and_log(lst
, env
=env
)
345 self
.parse_flags(ret
, kw
['uselib_store'], kw
.get('env', self
.env
), force_static
=static
, posix
=kw
.get('posix'))
349 def check_cfg(self
, *k
, **kw
):
351 Checks for configuration flags using a **-config**-like program (pkg-config, sdl-config, etc).
352 This wraps internal calls to :py:func:`waflib.Tools.c_config.validate_cfg` and :py:func:`waflib.Tools.c_config.exec_cfg`
353 so check exec_cfg parameters descriptions for more details on kw passed
358 conf.load('compiler_c')
359 conf.check_cfg(package='glib-2.0', args='--libs --cflags')
360 conf.check_cfg(package='pango')
361 conf.check_cfg(package='pango', uselib_store='MYPANGO', args=['--cflags', '--libs'])
362 conf.check_cfg(package='pango',
363 args=['pango >= 0.1.0', 'pango < 9.9.9', '--cflags', '--libs'],
364 msg="Checking for 'pango 0.1.0'")
365 conf.check_cfg(path='sdl-config', args='--cflags --libs', package='', uselib_store='SDL')
366 conf.check_cfg(path='mpicc', args='--showme:compile --showme:link',
367 package='', uselib_store='OPEN_MPI', mandatory=False)
369 conf.check_cfg(package='gtk+-2.0', variables=['includedir', 'prefix'], uselib_store='FOO')
370 print(conf.env.FOO_includedir)
372 self
.validate_cfg(kw
)
374 self
.start_msg(kw
['msg'], **kw
)
377 ret
= self
.exec_cfg(kw
)
378 except self
.errors
.WafError
as e
:
380 self
.end_msg(kw
['errmsg'], 'YELLOW', **kw
)
382 self
.to_log('Command failure: %s' % e
)
383 self
.fatal('The configuration failed')
389 self
.end_msg(self
.ret_msg(kw
['okmsg'], kw
), **kw
)
395 Build function that is used for running configuration tests with ``conf.check()``
397 if bld
.kw
['compile_filename']:
398 node
= bld
.srcnode
.make_node(bld
.kw
['compile_filename'])
399 node
.write(bld
.kw
['code'])
401 o
= bld(features
=bld
.kw
['features'], source
=bld
.kw
['compile_filename'], target
='testprog')
403 for k
, v
in bld
.kw
.items():
406 if not bld
.kw
.get('quiet'):
407 bld
.conf
.to_log("==>\n%s\n<==" % bld
.kw
['code'])
410 def validate_c(self
, kw
):
412 Pre-checks the parameters that will be given to :py:func:`waflib.Configure.run_build`
414 :param compiler: c or cxx (tries to guess what is best)
415 :type compiler: string
416 :param type: cprogram, cshlib, cstlib - not required if *features are given directly*
417 :type type: binary to create
418 :param feature: desired features for the task generator that will execute the test, for example ``cxx cxxstlib``
419 :type feature: list of string
420 :param fragment: provide a piece of code for the test (default is to let the system create one)
421 :type fragment: string
422 :param uselib_store: define variables after the test is executed (IMPORTANT!)
423 :type uselib_store: string
424 :param use: parameters to use for building (just like the normal *use* keyword)
425 :type use: list of string
426 :param define_name: define to set when the check is over
427 :type define_name: string
428 :param execute: execute the resulting binary
430 :param define_ret: if execute is set to True, use the execution output in both the define and the return value
431 :type define_ret: bool
432 :param header_name: check for a particular header
433 :type header_name: string
434 :param auto_add_header_name: if header_name was set, add the headers in env.INCKEYS so the next tests will include these headers
435 :type auto_add_header_name: bool
437 for x
in ('type_name', 'field_name', 'function_name'):
439 Logs
.warn('Invalid argument %r in test' % x
)
441 if not 'build_fun' in kw
:
442 kw
['build_fun'] = build_fun
445 kw
['env'] = self
.env
.derive()
448 if not 'compiler' in kw
and not 'features' in kw
:
450 if env
.CXX_NAME
and Task
.classes
.get('cxx'):
451 kw
['compiler'] = 'cxx'
453 self
.fatal('a c++ compiler is required')
456 self
.fatal('a c compiler is required')
458 if not 'compile_mode' in kw
:
459 kw
['compile_mode'] = 'c'
460 if 'cxx' in Utils
.to_list(kw
.get('features', [])) or kw
.get('compiler') == 'cxx':
461 kw
['compile_mode'] = 'cxx'
464 kw
['type'] = 'cprogram'
466 if not 'features' in kw
:
467 if not 'header_name' in kw
or kw
.get('link_header_test', True):
468 kw
['features'] = [kw
['compile_mode'], kw
['type']] # "c ccprogram"
470 kw
['features'] = [kw
['compile_mode']]
472 kw
['features'] = Utils
.to_list(kw
['features'])
474 if not 'compile_filename' in kw
:
475 kw
['compile_filename'] = 'test.c' + ((kw
['compile_mode'] == 'cxx') and 'pp' or '')
478 if 'header_name' in dct
:
479 dct
= Utils
.to_list(dct
['header_name'])
480 return ''.join(['#include <%s>\n' % x
for x
in dct
])
483 if 'framework_name' in kw
:
484 # OSX, not sure this is used anywhere
485 fwkname
= kw
['framework_name']
486 if not 'uselib_store' in kw
:
487 kw
['uselib_store'] = fwkname
.upper()
488 if not kw
.get('no_header'):
489 fwk
= '%s/%s.h' % (fwkname
, fwkname
)
490 if kw
.get('remove_dot_h'):
492 val
= kw
.get('header_name', [])
493 kw
['header_name'] = Utils
.to_list(val
) + [fwk
]
494 kw
['msg'] = 'Checking for framework %s' % fwkname
495 kw
['framework'] = fwkname
497 elif 'header_name' in kw
:
499 kw
['msg'] = 'Checking for header %s' % kw
['header_name']
501 l
= Utils
.to_list(kw
['header_name'])
502 assert len(l
), 'list of headers in header_name is empty'
504 kw
['code'] = to_header(kw
) + SNIP_EMPTY_PROGRAM
505 if not 'uselib_store' in kw
:
506 kw
['uselib_store'] = l
[0].upper()
507 if not 'define_name' in kw
:
508 kw
['define_name'] = self
.have_define(l
[0])
512 kw
['msg'] = 'Checking for library %s' % kw
['lib']
513 if not 'uselib_store' in kw
:
514 kw
['uselib_store'] = kw
['lib'].upper()
518 kw
['msg'] = 'Checking for static library %s' % kw
['stlib']
519 if not 'uselib_store' in kw
:
520 kw
['uselib_store'] = kw
['stlib'].upper()
523 # an additional code fragment may be provided to replace the predefined code
525 kw
['code'] = kw
['fragment']
527 kw
['msg'] = 'Checking for code snippet'
528 if not 'errmsg' in kw
:
531 for (flagsname
,flagstype
) in (('cxxflags','compiler'), ('cflags','compiler'), ('linkflags','linker')):
534 kw
['msg'] = 'Checking for %s flags %s' % (flagstype
, kw
[flagsname
])
535 if not 'errmsg' in kw
:
538 if not 'execute' in kw
:
539 kw
['execute'] = False
541 kw
['features'].append('test_exec')
542 kw
['chmod'] = Utils
.O755
544 if not 'errmsg' in kw
:
545 kw
['errmsg'] = 'not found'
547 if not 'okmsg' in kw
:
551 kw
['code'] = SNIP_EMPTY_PROGRAM
553 # if there are headers to append automatically to the next tests
554 if self
.env
[INCKEYS
]:
555 kw
['code'] = '\n'.join(['#include <%s>' % x
for x
in self
.env
[INCKEYS
]]) + '\n' + kw
['code']
557 # in case defines lead to very long command-lines
558 if kw
.get('merge_config_header') or env
.merge_config_header
:
559 kw
['code'] = '%s\n\n%s' % (self
.get_config_header(), kw
['code'])
560 env
.DEFINES
= [] # modify the copy
562 if not kw
.get('success'):
565 if 'define_name' in kw
:
566 self
.undefine(kw
['define_name'])
568 self
.fatal('missing "msg" in conf.check(...)')
571 def post_check(self
, *k
, **kw
):
573 Sets the variables after a test executed in
574 :py:func:`waflib.Tools.c_config.check` was run successfully
578 if kw
['success'] is not None:
579 if kw
.get('define_ret'):
580 is_success
= kw
['success']
582 is_success
= (kw
['success'] == 0)
584 is_success
= (kw
['success'] == 0)
586 if kw
.get('define_name'):
587 comment
= kw
.get('comment', '')
588 define_name
= kw
['define_name']
589 if kw
['execute'] and kw
.get('define_ret') and isinstance(is_success
, str):
590 if kw
.get('global_define', 1):
591 self
.define(define_name
, is_success
, quote
=kw
.get('quote', 1), comment
=comment
)
593 if kw
.get('quote', 1):
594 succ
= '"%s"' % is_success
596 succ
= int(is_success
)
597 val
= '%s=%s' % (define_name
, succ
)
598 var
= 'DEFINES_%s' % kw
['uselib_store']
599 self
.env
.append_value(var
, val
)
601 if kw
.get('global_define', 1):
602 self
.define_cond(define_name
, is_success
, comment
=comment
)
604 var
= 'DEFINES_%s' % kw
['uselib_store']
605 self
.env
.append_value(var
, '%s=%s' % (define_name
, int(is_success
)))
607 # define conf.env.HAVE_X to 1
608 if kw
.get('add_have_to_env', 1):
609 if kw
.get('uselib_store'):
610 self
.env
[self
.have_define(kw
['uselib_store'])] = 1
611 elif kw
['execute'] and kw
.get('define_ret'):
612 self
.env
[define_name
] = is_success
614 self
.env
[define_name
] = int(is_success
)
616 if 'header_name' in kw
:
617 if kw
.get('auto_add_header_name'):
618 self
.env
.append_value(INCKEYS
, Utils
.to_list(kw
['header_name']))
620 if is_success
and 'uselib_store' in kw
:
621 from waflib
.Tools
import ccroot
622 # See get_uselib_vars in ccroot.py
624 for x
in kw
['features']:
625 if x
in ccroot
.USELIB_VARS
:
626 _vars |
= ccroot
.USELIB_VARS
[x
]
631 self
.env
.append_value(k
+ '_' + kw
['uselib_store'], kw
[x
])
635 def check(self
, *k
, **kw
):
637 Performs a configuration test by calling :py:func:`waflib.Configure.run_build`.
638 For the complete list of parameters, see :py:func:`waflib.Tools.c_config.validate_c`.
639 To force a specific compiler, pass ``compiler='c'`` or ``compiler='cxx'`` to the list of arguments
641 Besides build targets, complete builds can be given through a build function. All files will
642 be written to a temporary directory::
645 lib_node = bld.srcnode.make_node('libdir/liblc1.c')
646 lib_node.parent.mkdir()
647 lib_node.write('#include <stdio.h>\\nint lib_func(void) { FILE *f = fopen("foo", "r");}\\n', 'w')
648 bld(features='c cshlib', source=[lib_node], linkflags=conf.env.EXTRA_LDFLAGS, target='liblc')
649 conf.check(build_fun=build, msg=msg)
652 self
.start_msg(kw
['msg'], **kw
)
655 ret
= self
.run_build(*k
, **kw
)
656 except self
.errors
.ConfigurationError
:
657 self
.end_msg(kw
['errmsg'], 'YELLOW', **kw
)
661 self
.fatal('The configuration failed')
665 ret
= self
.post_check(*k
, **kw
)
667 self
.end_msg(kw
['errmsg'], 'YELLOW', **kw
)
668 self
.fatal('The configuration failed %r' % ret
)
670 self
.end_msg(self
.ret_msg(kw
['okmsg'], kw
), **kw
)
673 class test_exec(Task
.Task
):
675 A task that runs programs after they are built. See :py:func:`waflib.Tools.c_config.test_exec_fun`.
679 cmd
= [self
.inputs
[0].abspath()] + getattr(self
.generator
, 'test_args', [])
680 if getattr(self
.generator
, 'rpath', None):
681 if getattr(self
.generator
, 'define_ret', False):
682 self
.generator
.bld
.retval
= self
.generator
.bld
.cmd_and_log(cmd
)
684 self
.generator
.bld
.retval
= self
.generator
.bld
.exec_command(cmd
)
686 env
= self
.env
.env
or {}
687 env
.update(dict(os
.environ
))
688 for var
in ('LD_LIBRARY_PATH', 'DYLD_LIBRARY_PATH', 'PATH'):
689 env
[var
] = self
.inputs
[0].parent
.abspath() + os
.path
.pathsep
+ env
.get(var
, '')
690 if getattr(self
.generator
, 'define_ret', False):
691 self
.generator
.bld
.retval
= self
.generator
.bld
.cmd_and_log(cmd
, env
=env
)
693 self
.generator
.bld
.retval
= self
.generator
.bld
.exec_command(cmd
, env
=env
)
695 @feature('test_exec')
696 @after_method('apply_link')
697 def test_exec_fun(self
):
699 The feature **test_exec** is used to create a task that will to execute the binary
700 created (link task output) during the build. The exit status will be set
701 on the build context, so only one program may have the feature *test_exec*.
702 This is used by configuration tests::
705 conf.check(execute=True)
707 self
.create_task('test_exec', self
.link_task
.outputs
[0])
710 def check_cxx(self
, *k
, **kw
):
712 Runs a test with a task generator of the form::
714 conf.check(features='cxx cxxprogram', ...)
716 kw
['compiler'] = 'cxx'
717 return self
.check(*k
, **kw
)
720 def check_cc(self
, *k
, **kw
):
722 Runs a test with a task generator of the form::
724 conf.check(features='c cprogram', ...)
727 return self
.check(*k
, **kw
)
730 def set_define_comment(self
, key
, comment
):
732 Sets a comment that will appear in the configuration header
735 :type comment: string
737 coms
= self
.env
.DEFINE_COMMENTS
739 coms
= self
.env
.DEFINE_COMMENTS
= {}
740 coms
[key
] = comment
or ''
743 def get_define_comment(self
, key
):
745 Returns the comment associated to a define
749 coms
= self
.env
.DEFINE_COMMENTS
or {}
750 return coms
.get(key
, '')
753 def define(self
, key
, val
, quote
=True, comment
=''):
755 Stores a single define and its state into ``conf.env.DEFINES``. The value is cast to an integer (0/1).
757 :param key: define name
760 :type val: int or string
761 :param quote: enclose strings in quotes (yes by default)
764 assert isinstance(key
, str)
769 elif val
in (False, None):
772 if isinstance(val
, int) or isinstance(val
, float):
775 s
= quote
and '%s="%s"' or '%s=%s'
776 app
= s
% (key
, str(val
))
779 lst
= self
.env
.DEFINES
781 if x
.startswith(ban
):
782 lst
[lst
.index(x
)] = app
785 self
.env
.append_value('DEFINES', app
)
787 self
.env
.append_unique(DEFKEYS
, key
)
788 self
.set_define_comment(key
, comment
)
791 def undefine(self
, key
, comment
=''):
793 Removes a global define from ``conf.env.DEFINES``
795 :param key: define name
798 assert isinstance(key
, str)
802 lst
= [x
for x
in self
.env
.DEFINES
if not x
.startswith(ban
)]
803 self
.env
.DEFINES
= lst
804 self
.env
.append_unique(DEFKEYS
, key
)
805 self
.set_define_comment(key
, comment
)
808 def define_cond(self
, key
, val
, comment
=''):
810 Conditionally defines a name::
813 conf.define_cond('A', True)
815 # if val: conf.define('A', 1)
816 # else: conf.undefine('A')
818 :param key: define name
821 :type val: int or string
823 assert isinstance(key
, str)
827 self
.define(key
, 1, comment
=comment
)
829 self
.undefine(key
, comment
=comment
)
832 def is_defined(self
, key
):
834 Indicates whether a particular define is globally set in ``conf.env.DEFINES``.
836 :param key: define name
838 :return: True if the define is set
841 assert key
and isinstance(key
, str)
844 for x
in self
.env
.DEFINES
:
845 if x
.startswith(ban
):
850 def get_define(self
, key
):
852 Returns the value of an existing define, or None if not found
854 :param key: define name
858 assert key
and isinstance(key
, str)
861 for x
in self
.env
.DEFINES
:
862 if x
.startswith(ban
):
867 def have_define(self
, key
):
869 Returns a variable suitable for command-line or header use by removing invalid characters
870 and prefixing it with ``HAVE_``
872 :param key: define name
874 :return: the input key prefixed by *HAVE_* and substitute any invalid characters.
877 return (self
.env
.HAVE_PAT
or 'HAVE_%s') % Utils
.quote_define_name(key
)
880 def write_config_header(self
, configfile
='', guard
='', top
=False, defines
=True, headers
=False, remove
=True, define_prefix
=''):
882 Writes a configuration header containing defines and includes::
886 cnf.write_config_header('config.h')
888 This function only adds include guards (if necessary), consult
889 :py:func:`waflib.Tools.c_config.get_config_header` for details on the body.
891 :param configfile: path to the file to create (relative or absolute)
892 :type configfile: string
893 :param guard: include guard name to add, by default it is computed from the file name
895 :param top: write the configuration header from the build directory (default is from the current path)
897 :param defines: add the defines (yes by default)
899 :param headers: add #include in the file
901 :param remove: remove the defines after they are added (yes by default, works like in autoconf)
903 :type define_prefix: string
904 :param define_prefix: prefix all the defines in the file with a particular prefix
907 configfile
= WAF_CONFIG_H
908 waf_guard
= guard
or 'W_%s_WAF' % Utils
.quote_define_name(configfile
)
910 node
= top
and self
.bldnode
or self
.path
.get_bld()
911 node
= node
.make_node(configfile
)
914 lst
= ['/* WARNING! All changes made to this file will be lost! */\n']
915 lst
.append('#ifndef %s\n#define %s\n' % (waf_guard
, waf_guard
))
916 lst
.append(self
.get_config_header(defines
, headers
, define_prefix
=define_prefix
))
917 lst
.append('\n#endif /* %s */\n' % waf_guard
)
919 node
.write('\n'.join(lst
))
921 # config files must not be removed on "waf clean"
922 self
.env
.append_unique(Build
.CFG_FILES
, [node
.abspath()])
925 for key
in self
.env
[DEFKEYS
]:
927 self
.env
[DEFKEYS
] = []
930 def get_config_header(self
, defines
=True, headers
=False, define_prefix
=''):
932 Creates the contents of a ``config.h`` file from the defines and includes
933 set in conf.env.define_key / conf.env.include_key. No include guards are added.
935 A prelude will be added from the variable env.WAF_CONFIG_H_PRELUDE if provided. This
936 can be used to insert complex macros or include guards::
939 conf.env.WAF_CONFIG_H_PRELUDE = '#include <unistd.h>\\n'
940 conf.write_config_header('config.h')
942 :param defines: write the defines values
944 :param headers: write include entries for each element in self.env.INCKEYS
946 :type define_prefix: string
947 :param define_prefix: prefix all the defines with a particular prefix
948 :return: the contents of a ``config.h`` file
953 if self
.env
.WAF_CONFIG_H_PRELUDE
:
954 lst
.append(self
.env
.WAF_CONFIG_H_PRELUDE
)
957 for x
in self
.env
[INCKEYS
]:
958 lst
.append('#include <%s>' % x
)
962 for k
in self
.env
.DEFINES
:
963 a
, _
, b
= k
.partition('=')
966 for k
in self
.env
[DEFKEYS
]:
967 caption
= self
.get_define_comment(k
)
969 caption
= ' /* %s */' % caption
971 txt
= '#define %s%s %s%s' % (define_prefix
, k
, tbl
[k
], caption
)
973 txt
= '/* #undef %s%s */%s' % (define_prefix
, k
, caption
)
975 return "\n".join(lst
)
978 def cc_add_flags(conf
):
980 Adds CFLAGS / CPPFLAGS from os.environ to conf.env
982 conf
.add_os_flags('CPPFLAGS', dup
=False)
983 conf
.add_os_flags('CFLAGS', dup
=False)
986 def cxx_add_flags(conf
):
988 Adds CXXFLAGS / CPPFLAGS from os.environ to conf.env
990 conf
.add_os_flags('CPPFLAGS', dup
=False)
991 conf
.add_os_flags('CXXFLAGS', dup
=False)
994 def link_add_flags(conf
):
996 Adds LINKFLAGS / LDFLAGS from os.environ to conf.env
998 conf
.add_os_flags('LINKFLAGS', dup
=False)
999 conf
.add_os_flags('LDFLAGS', dup
=False)
1002 def cc_load_tools(conf
):
1004 Loads the Waf c extensions
1006 if not conf
.env
.DEST_OS
:
1007 conf
.env
.DEST_OS
= Utils
.unversioned_sys_platform()
1011 def cxx_load_tools(conf
):
1013 Loads the Waf c++ extensions
1015 if not conf
.env
.DEST_OS
:
1016 conf
.env
.DEST_OS
= Utils
.unversioned_sys_platform()
1020 def get_cc_version(conf
, cc
, gcc
=False, icc
=False, clang
=False):
1022 Runs the preprocessor to determine the gcc/icc/clang version
1024 The variables CC_VERSION, DEST_OS, DEST_BINFMT and DEST_CPU will be set in *conf.env*
1026 :raise: :py:class:`waflib.Errors.ConfigurationError`
1028 cmd
= cc
+ ['-dM', '-E', '-']
1029 env
= conf
.env
.env
or None
1031 out
, err
= conf
.cmd_and_log(cmd
, output
=0, input='\n'.encode(), env
=env
)
1032 except Errors
.WafError
:
1033 conf
.fatal('Could not determine the compiler version %r' % cmd
)
1036 if out
.find('__INTEL_COMPILER') >= 0:
1037 conf
.fatal('The intel compiler pretends to be gcc')
1038 if out
.find('__GNUC__') < 0 and out
.find('__clang__') < 0:
1039 conf
.fatal('Could not determine the compiler type')
1041 if icc
and out
.find('__INTEL_COMPILER') < 0:
1042 conf
.fatal('Not icc/icpc')
1044 if clang
and out
.find('__clang__') < 0:
1045 conf
.fatal('Not clang/clang++')
1046 if not clang
and out
.find('__clang__') >= 0:
1047 conf
.fatal('Could not find gcc/g++ (only Clang), if renamed try eg: CC=gcc48 CXX=g++48 waf configure')
1050 if icc
or gcc
or clang
:
1051 out
= out
.splitlines()
1053 lst
= shlex
.split(line
)
1062 # Some documentation is available at http://predef.sourceforge.net
1063 # The names given to DEST_OS must match what Utils.unversioned_sys_platform() returns.
1064 if not conf
.env
.DEST_OS
:
1065 conf
.env
.DEST_OS
= ''
1066 for i
in MACRO_TO_DESTOS
:
1068 conf
.env
.DEST_OS
= MACRO_TO_DESTOS
[i
]
1071 if isD('__APPLE__') and isD('__MACH__'):
1072 conf
.env
.DEST_OS
= 'darwin'
1073 elif isD('__unix__'): # unix must be tested last as it's a generic fallback
1074 conf
.env
.DEST_OS
= 'generic'
1077 conf
.env
.DEST_BINFMT
= 'elf'
1078 elif isD('__WINNT__') or isD('__CYGWIN__') or isD('_WIN32'):
1079 conf
.env
.DEST_BINFMT
= 'pe'
1080 if not conf
.env
.IMPLIBDIR
:
1081 conf
.env
.IMPLIBDIR
= conf
.env
.LIBDIR
# for .lib or .dll.a files
1082 conf
.env
.LIBDIR
= conf
.env
.BINDIR
1083 elif isD('__APPLE__'):
1084 conf
.env
.DEST_BINFMT
= 'mac-o'
1086 if not conf
.env
.DEST_BINFMT
:
1087 # Infer the binary format from the os name.
1088 conf
.env
.DEST_BINFMT
= Utils
.destos_to_binfmt(conf
.env
.DEST_OS
)
1090 for i
in MACRO_TO_DEST_CPU
:
1092 conf
.env
.DEST_CPU
= MACRO_TO_DEST_CPU
[i
]
1095 Logs
.debug('ccroot: dest platform: ' + ' '.join([conf
.env
[x
] or '?' for x
in ('DEST_OS', 'DEST_BINFMT', 'DEST_CPU')]))
1097 ver
= k
['__INTEL_COMPILER']
1098 conf
.env
.CC_VERSION
= (ver
[:-2], ver
[-2], ver
[-1])
1100 if isD('__clang__') and isD('__clang_major__'):
1101 conf
.env
.CC_VERSION
= (k
['__clang_major__'], k
['__clang_minor__'], k
['__clang_patchlevel__'])
1103 # older clang versions and gcc
1104 conf
.env
.CC_VERSION
= (k
['__GNUC__'], k
['__GNUC_MINOR__'], k
.get('__GNUC_PATCHLEVEL__', '0'))
1108 def get_xlc_version(conf
, cc
):
1110 Returns the Aix compiler version
1112 :raise: :py:class:`waflib.Errors.ConfigurationError`
1114 cmd
= cc
+ ['-qversion']
1116 out
, err
= conf
.cmd_and_log(cmd
, output
=0)
1117 except Errors
.WafError
:
1118 conf
.fatal('Could not find xlc %r' % cmd
)
1120 # the intention is to catch the 8.0 in "IBM XL C/C++ Enterprise Edition V8.0 for AIX..."
1121 for v
in (r
"IBM XL C/C\+\+.* V(?P<major>\d*)\.(?P<minor>\d*)",):
1122 version_re
= re
.compile(v
, re
.I
).search
1123 match
= version_re(out
or err
)
1125 k
= match
.groupdict()
1126 conf
.env
.CC_VERSION
= (k
['major'], k
['minor'])
1129 conf
.fatal('Could not determine the XLC version.')
1132 def get_suncc_version(conf
, cc
):
1134 Returns the Sun compiler version
1136 :raise: :py:class:`waflib.Errors.ConfigurationError`
1140 out
, err
= conf
.cmd_and_log(cmd
, output
=0)
1141 except Errors
.WafError
as e
:
1142 # Older versions of the compiler exit with non-zero status when reporting their version
1143 if not (hasattr(e
, 'returncode') and hasattr(e
, 'stdout') and hasattr(e
, 'stderr')):
1144 conf
.fatal('Could not find suncc %r' % cmd
)
1148 version
= (out
or err
)
1149 version
= version
.splitlines()[0]
1151 # cc: Sun C 5.10 SunOS_i386 2009/06/03
1152 # cc: Studio 12.5 Sun C++ 5.14 SunOS_sparc Beta 2015/11/17
1153 # cc: WorkShop Compilers 5.0 98/12/15 C 5.0
1154 version_re
= re
.compile(r
'cc: (studio.*?|\s+)?(sun\s+(c\+\+|c)|(WorkShop\s+Compilers))?\s+(?P<major>\d*)\.(?P<minor>\d*)', re
.I
).search
1155 match
= version_re(version
)
1157 k
= match
.groupdict()
1158 conf
.env
.CC_VERSION
= (k
['major'], k
['minor'])
1160 conf
.fatal('Could not determine the suncc version.')
1162 # ============ the --as-needed flag should added during the configuration, not at runtime =========
1165 def add_as_needed(self
):
1167 Adds ``--as-needed`` to the *LINKFLAGS*
1168 On some platforms, it is a default flag. In some cases (e.g., in NS-3) it is necessary to explicitly disable this feature with `-Wl,--no-as-needed` flag.
1170 if self
.env
.DEST_BINFMT
== 'elf' and 'gcc' in (self
.env
.CXX_NAME
, self
.env
.CC_NAME
):
1171 self
.env
.append_unique('LINKFLAGS', '-Wl,--as-needed')
1173 # ============ parallel configuration
1175 class cfgtask(Task
.Task
):
1177 A task that executes build configuration tests (calls conf.check)
1179 Make sure to use locks if concurrent access to the same conf.env data is necessary.
1181 def __init__(self
, *k
, **kw
):
1182 Task
.Task
.__init
__(self
, *k
, **kw
)
1183 self
.run_after
= set()
1188 def runnable_status(self
):
1189 for x
in self
.run_after
:
1191 return Task
.ASK_LATER
1195 return Utils
.SIG_NIL
1197 def signature(self
):
1198 return Utils
.SIG_NIL
1202 bld
= Build
.BuildContext(top_dir
=conf
.srcnode
.abspath(), out_dir
=conf
.bldnode
.abspath())
1205 bld
.in_msg
= 1 # suppress top-level start_msg
1206 bld
.logger
= self
.logger
1207 bld
.multicheck_task
= self
1211 bld
.test(build_fun
=args
['func'],
1212 msg
=args
.get('msg', ''),
1213 okmsg
=args
.get('okmsg', ''),
1214 errmsg
=args
.get('errmsg', ''),
1217 args
['multicheck_mandatory'] = args
.get('mandatory', True)
1218 args
['mandatory'] = True
1222 args
['mandatory'] = args
['multicheck_mandatory']
1227 Task
.Task
.process(self
)
1228 if 'msg' in self
.args
:
1229 with self
.generator
.bld
.multicheck_lock
:
1230 self
.conf
.start_msg(self
.args
['msg'])
1231 if self
.hasrun
== Task
.NOT_RUN
:
1232 self
.conf
.end_msg('test cancelled', 'YELLOW')
1233 elif self
.hasrun
!= Task
.SUCCESS
:
1234 self
.conf
.end_msg(self
.args
.get('errmsg', 'no'), 'YELLOW')
1236 self
.conf
.end_msg(self
.args
.get('okmsg', 'yes'), 'GREEN')
1239 def multicheck(self
, *k
, **kw
):
1241 Runs configuration tests in parallel; results are printed sequentially at the end of the build
1242 but each test must provide its own msg value to display a line::
1244 def test_build(ctx):
1245 ctx.in_msg = True # suppress console outputs
1246 ctx.check_large_file(mandatory=False)
1249 {'header_name':'stdio.h', 'msg':'... stdio', 'uselib_store':'STDIO', 'global_define':False},
1250 {'header_name':'xyztabcd.h', 'msg':'... optional xyztabcd.h', 'mandatory': False},
1251 {'header_name':'stdlib.h', 'msg':'... stdlib', 'okmsg': 'aye', 'errmsg': 'nope'},
1252 {'func': test_build, 'msg':'... testing an arbitrary build function', 'okmsg':'ok'},
1253 msg = 'Checking for headers in parallel',
1254 mandatory = True, # mandatory tests raise an error at the end
1255 run_all_tests = True, # try running all tests
1258 The configuration tests may modify the values in conf.env in any order, and the define
1259 values can affect configuration tests being executed. It is hence recommended
1260 to provide `uselib_store` values with `global_define=False` to prevent such issues.
1262 self
.start_msg(kw
.get('msg', 'Executing %d configuration tests' % len(k
)), **kw
)
1264 # Force a copy so that threads append to the same list at least
1265 # no order is guaranteed, but the values should not disappear at least
1266 for var
in ('DEFINES', DEFKEYS
):
1267 self
.env
.append_value(var
, [])
1268 self
.env
.DEFINE_COMMENTS
= self
.env
.DEFINE_COMMENTS
or {}
1270 # define a task object that will execute our tests
1275 self
.progress_bar
= 0
1278 def to_log(self
, *k
, **kw
):
1282 bld
.keep
= kw
.get('run_all_tests', True)
1287 for counter
, dct
in enumerate(k
):
1288 x
= Task
.classes
['cfgtask'](bld
=bld
, env
=None)
1291 x
.args
['multicheck_counter'] = counter
1296 # bind a logger that will keep the info in memory
1297 x
.logger
= Logs
.make_mem_logger(str(id(x
)), self
.logger
)
1300 id_to_task
[dct
['id']] = x
1302 # second pass to set dependencies with after_test/before_test
1304 for key
in Utils
.to_list(x
.args
.get('before_tests', [])):
1305 tsk
= id_to_task
[key
]
1307 raise ValueError('No test named %r' % key
)
1308 tsk
.run_after
.add(x
)
1309 for key
in Utils
.to_list(x
.args
.get('after_tests', [])):
1310 tsk
= id_to_task
[key
]
1312 raise ValueError('No test named %r' % key
)
1313 x
.run_after
.add(tsk
)
1319 bld
.producer
= p
= Runner
.Parallel(bld
, Options
.options
.jobs
)
1320 bld
.multicheck_lock
= Utils
.threading
.Lock()
1323 self
.end_msg('started')
1326 # flush the logs in order into the config.log
1328 x
.logger
.memhandler
.flush()
1330 self
.start_msg('-> processing test results')
1333 if getattr(x
, 'err_msg', None):
1334 self
.to_log(x
.err_msg
)
1335 self
.end_msg('fail', color
='RED')
1336 raise Errors
.WafError('There is an error in the library, read config.log for more information')
1340 if x
.hasrun
not in (Task
.SUCCESS
, Task
.NOT_RUN
):
1344 self
.end_msg(kw
.get('errmsg', '%s test failed' % failure_count
), color
='YELLOW', **kw
)
1346 self
.end_msg('all ok', **kw
)
1349 if x
.hasrun
!= Task
.SUCCESS
:
1350 if x
.args
.get('mandatory', True):
1351 self
.fatal(kw
.get('fatalmsg') or 'One of the tests has failed, read config.log for more information')
1354 def check_gcc_o_space(self
, mode
='c'):
1355 if int(self
.env
.CC_VERSION
[0]) > 4:
1356 # this is for old compilers
1360 self
.env
.CCLNK_TGT_F
= ['-o', '']
1362 self
.env
.CXXLNK_TGT_F
= ['-o', '']
1363 features
= '%s %sshlib' % (mode
, mode
)
1365 self
.check(msg
='Checking if the -o link must be split from arguments', fragment
=SNIP_EMPTY_PROGRAM
, features
=features
)
1366 except self
.errors
.ConfigurationError
: