summaryrefslogtreecommitdiff
path: root/waflib/Tools/c_config.py
diff options
context:
space:
mode:
Diffstat (limited to 'waflib/Tools/c_config.py')
-rw-r--r--waflib/Tools/c_config.py688
1 files changed, 287 insertions, 401 deletions
diff --git a/waflib/Tools/c_config.py b/waflib/Tools/c_config.py
index d2b3c0d8..f114dffb 100644
--- a/waflib/Tools/c_config.py
+++ b/waflib/Tools/c_config.py
@@ -1,13 +1,11 @@
#!/usr/bin/env python
# encoding: utf-8
-# Thomas Nagy, 2005-2018 (ita)
+# Thomas Nagy, 2005-2010 (ita)
"""
C/C++/D configuration helpers
"""
-from __future__ import with_statement
-
import os, re, shlex
from waflib import Build, Utils, Task, Options, Logs, Errors, Runner
from waflib.TaskGen import after_method, feature
@@ -19,6 +17,32 @@ WAF_CONFIG_H = 'config.h'
DEFKEYS = 'define_key'
INCKEYS = 'include_key'
+cfg_ver = {
+ 'atleast-version': '>=',
+ 'exact-version': '==',
+ 'max-version': '<=',
+}
+
+SNIP_FUNCTION = '''
+int main(int argc, char **argv) {
+ void (*p)();
+ (void)argc; (void)argv;
+ p=(void(*)())(%s);
+ return !p;
+}
+'''
+"""Code template for checking for functions"""
+
+SNIP_TYPE = '''
+int main(int argc, char **argv) {
+ (void)argc; (void)argv;
+ if ((%(type_name)s *) 0) return 0;
+ if (sizeof (%(type_name)s)) return 0;
+ return 1;
+}
+'''
+"""Code template for checking for types"""
+
SNIP_EMPTY_PROGRAM = '''
int main(int argc, char **argv) {
(void)argc; (void)argv;
@@ -26,6 +50,15 @@ int main(int argc, char **argv) {
}
'''
+SNIP_FIELD = '''
+int main(int argc, char **argv) {
+ char *off;
+ (void)argc; (void)argv;
+ off = (char*) &((%(type_name)s*)0)->%(field_name)s;
+ return (size_t) off < sizeof(%(type_name)s);
+}
+'''
+
MACRO_TO_DESTOS = {
'__linux__' : 'linux',
'__GNU__' : 'gnu', # hurd
@@ -42,7 +75,7 @@ MACRO_TO_DESTOS = {
'_WIN64' : 'win32',
'_WIN32' : 'win32',
# Note about darwin: this is also tested with 'defined __APPLE__ && defined __MACH__' somewhere below in this file.
-'__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' : 'darwin',
+'__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' : 'darwin',
'__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' : 'darwin', # iphone
'__QNX__' : 'qnx',
'__native_client__' : 'nacl' # google native client platform
@@ -67,13 +100,12 @@ MACRO_TO_DEST_CPU = {
'__s390x__' : 's390x',
'__s390__' : 's390',
'__sh__' : 'sh',
-'__xtensa__' : 'xtensa',
}
@conf
def parse_flags(self, line, uselib_store, env=None, force_static=False, posix=None):
"""
- Parses flags from the input lines, and adds them to the relevant use variables::
+ Parse the flags from the input lines, and add them to the relevant use variables::
def configure(conf):
conf.parse_flags('-O3', 'FOO')
@@ -105,11 +137,9 @@ def parse_flags(self, line, uselib_store, env=None, force_static=False, posix=No
# append_unique is not always possible
# for example, apple flags may require both -arch i386 and -arch ppc
+ app = env.append_value
+ appu = env.append_unique
uselib = uselib_store
- def app(var, val):
- env.append_value('%s_%s' % (var, uselib), val)
- def appu(var, val):
- env.append_unique('%s_%s' % (var, uselib), val)
static = False
while lst:
x = lst.pop(0)
@@ -117,79 +147,69 @@ def parse_flags(self, line, uselib_store, env=None, force_static=False, posix=No
ot = x[2:]
if st == '-I' or st == '/I':
- if not ot:
- ot = lst.pop(0)
- appu('INCLUDES', ot)
+ if not ot: ot = lst.pop(0)
+ appu('INCLUDES_' + uselib, [ot])
elif st == '-i':
tmp = [x, lst.pop(0)]
app('CFLAGS', tmp)
app('CXXFLAGS', tmp)
elif st == '-D' or (env.CXX_NAME == 'msvc' and st == '/D'): # not perfect but..
- if not ot:
- ot = lst.pop(0)
- app('DEFINES', ot)
+ if not ot: ot = lst.pop(0)
+ app('DEFINES_' + uselib, [ot])
elif st == '-l':
- if not ot:
- ot = lst.pop(0)
- prefix = 'STLIB' if (force_static or static) else 'LIB'
- app(prefix, ot)
+ if not ot: ot = lst.pop(0)
+ prefix = (force_static or static) and 'STLIB_' or 'LIB_'
+ appu(prefix + uselib, [ot])
elif st == '-L':
- if not ot:
- ot = lst.pop(0)
- prefix = 'STLIBPATH' if (force_static or static) else 'LIBPATH'
- appu(prefix, ot)
+ if not ot: ot = lst.pop(0)
+ prefix = (force_static or static) and 'STLIBPATH_' or 'LIBPATH_'
+ appu(prefix + uselib, [ot])
elif x.startswith('/LIBPATH:'):
- prefix = 'STLIBPATH' if (force_static or static) else 'LIBPATH'
- appu(prefix, x.replace('/LIBPATH:', ''))
- elif x.startswith('-std='):
- prefix = 'CXXFLAGS' if '++' in x else 'CFLAGS'
- app(prefix, x)
- elif x.startswith('+') or x in ('-pthread', '-fPIC', '-fpic', '-fPIE', '-fpie'):
- app('CFLAGS', x)
- app('CXXFLAGS', x)
- app('LINKFLAGS', x)
+ prefix = (force_static or static) and 'STLIBPATH_' or 'LIBPATH_'
+ appu(prefix + uselib, [x.replace('/LIBPATH:', '')])
+ elif x == '-pthread' or x.startswith('+') or x.startswith('-std'):
+ app('CFLAGS_' + uselib, [x])
+ app('CXXFLAGS_' + uselib, [x])
+ app('LINKFLAGS_' + uselib, [x])
elif x == '-framework':
- appu('FRAMEWORK', lst.pop(0))
+ appu('FRAMEWORK_' + uselib, [lst.pop(0)])
elif x.startswith('-F'):
- appu('FRAMEWORKPATH', x[2:])
+ appu('FRAMEWORKPATH_' + uselib, [x[2:]])
elif x == '-Wl,-rpath' or x == '-Wl,-R':
- app('RPATH', lst.pop(0).lstrip('-Wl,'))
+ app('RPATH_' + uselib, lst.pop(0).lstrip('-Wl,'))
elif x.startswith('-Wl,-R,'):
- app('RPATH', x[7:])
+ app('RPATH_' + uselib, x[7:])
elif x.startswith('-Wl,-R'):
- app('RPATH', x[6:])
+ app('RPATH_' + uselib, x[6:])
elif x.startswith('-Wl,-rpath,'):
- app('RPATH', x[11:])
+ app('RPATH_' + uselib, x[11:])
elif x == '-Wl,-Bstatic' or x == '-Bstatic':
static = True
elif x == '-Wl,-Bdynamic' or x == '-Bdynamic':
static = False
- elif x.startswith('-Wl') or x in ('-rdynamic', '-pie'):
- app('LINKFLAGS', x)
- elif x.startswith(('-m', '-f', '-dynamic', '-O', '-g')):
- # Adding the -W option breaks python builds on Openindiana
- app('CFLAGS', x)
- app('CXXFLAGS', x)
+ elif x.startswith('-Wl'):
+ app('LINKFLAGS_' + uselib, [x])
+ elif x.startswith('-m') or x.startswith('-f') or x.startswith('-dynamic'):
+ app('CFLAGS_' + uselib, [x])
+ app('CXXFLAGS_' + uselib, [x])
elif x.startswith('-bundle'):
- app('LINKFLAGS', x)
- elif x.startswith(('-undefined', '-Xlinker')):
+ app('LINKFLAGS_' + uselib, [x])
+ elif x.startswith('-undefined') or x.startswith('-Xlinker'):
arg = lst.pop(0)
- app('LINKFLAGS', [x, arg])
- elif x.startswith(('-arch', '-isysroot')):
+ app('LINKFLAGS_' + uselib, [x, arg])
+ elif x.startswith('-arch') or x.startswith('-isysroot'):
tmp = [x, lst.pop(0)]
- app('CFLAGS', tmp)
- app('CXXFLAGS', tmp)
- app('LINKFLAGS', tmp)
- elif x.endswith(('.a', '.so', '.dylib', '.lib')):
- appu('LINKFLAGS', x) # not cool, #762
- else:
- self.to_log('Unhandled flag %r' % x)
+ app('CFLAGS_' + uselib, tmp)
+ app('CXXFLAGS_' + uselib, tmp)
+ app('LINKFLAGS_' + uselib, tmp)
+ elif x.endswith('.a') or x.endswith('.so') or x.endswith('.dylib') or x.endswith('.lib'):
+ appu('LINKFLAGS_' + uselib, [x]) # not cool, #762
@conf
def validate_cfg(self, kw):
"""
- Searches for the program *pkg-config* if missing, and validates the
- parameters to pass to :py:func:`waflib.Tools.c_config.exec_cfg`.
+ Search for the program *pkg-config* if missing, and validate the parameters to pass to
+ :py:func:`waflib.Tools.c_config.exec_cfg`.
:param path: the **-config program to use** (default is *pkg-config*)
:type path: list of string
@@ -205,42 +225,47 @@ def validate_cfg(self, kw):
self.find_program('pkg-config', var='PKGCONFIG')
kw['path'] = self.env.PKGCONFIG
- # verify that exactly one action is requested
- s = ('atleast_pkgconfig_version' in kw) + ('modversion' in kw) + ('package' in kw)
- if s != 1:
- raise ValueError('exactly one of atleast_pkgconfig_version, modversion and package must be set')
- if not 'msg' in kw:
- if 'atleast_pkgconfig_version' in kw:
+ # pkg-config version
+ if 'atleast_pkgconfig_version' in kw:
+ if not 'msg' in kw:
kw['msg'] = 'Checking for pkg-config version >= %r' % kw['atleast_pkgconfig_version']
- elif 'modversion' in kw:
- kw['msg'] = 'Checking for %r version' % kw['modversion']
- else:
- kw['msg'] = 'Checking for %r' %(kw['package'])
+ return
- # let the modversion check set the okmsg to the detected version
- if not 'okmsg' in kw and not 'modversion' in kw:
+ if not 'okmsg' in kw:
kw['okmsg'] = 'yes'
if not 'errmsg' in kw:
kw['errmsg'] = 'not found'
- # pkg-config version
- if 'atleast_pkgconfig_version' in kw:
- pass
- elif 'modversion' in kw:
- if not 'uselib_store' in kw:
- kw['uselib_store'] = kw['modversion']
- if not 'define_name' in kw:
- kw['define_name'] = '%s_VERSION' % Utils.quote_define_name(kw['uselib_store'])
- else:
- if not 'uselib_store' in kw:
- kw['uselib_store'] = Utils.to_list(kw['package'])[0].upper()
- if not 'define_name' in kw:
- kw['define_name'] = self.have_define(kw['uselib_store'])
+ if 'modversion' in kw:
+ if not 'msg' in kw:
+ kw['msg'] = 'Checking for %r version' % kw['modversion']
+ return
+
+ # checking for the version of a module, for the moment, one thing at a time
+ for x in cfg_ver.keys():
+ y = x.replace('-', '_')
+ if y in kw:
+ if not 'package' in kw:
+ raise ValueError('%s requires a package' % x)
+
+ if not 'msg' in kw:
+ kw['msg'] = 'Checking for %r %s %s' % (kw['package'], cfg_ver[x], kw[y])
+ return
+
+ if not 'define_name' in kw:
+ pkgname = kw.get('uselib_store', kw['package'].upper())
+ kw['define_name'] = self.have_define(pkgname)
+
+ if not 'uselib_store' in kw:
+ self.undefine(kw['define_name'])
+
+ if not 'msg' in kw:
+ kw['msg'] = 'Checking for %r' % (kw['package'] or kw['path'])
@conf
def exec_cfg(self, kw):
"""
- Executes ``pkg-config`` or other ``-config`` applications to collect configuration flags:
+ Execute the program *pkg-config*:
* if atleast_pkgconfig_version is given, check that pkg-config has the version n and return
* if modversion is given, then return the module version
@@ -264,39 +289,42 @@ def exec_cfg(self, kw):
path = Utils.to_list(kw['path'])
env = self.env.env or None
- if kw.get('pkg_config_path'):
- if not env:
- env = dict(self.environ)
- env['PKG_CONFIG_PATH'] = kw['pkg_config_path']
-
def define_it():
- define_name = kw['define_name']
- # by default, add HAVE_X to the config.h, else provide DEFINES_X for use=X
- if kw.get('global_define', 1):
- self.define(define_name, 1, False)
+ pkgname = kw.get('uselib_store', kw['package'].upper())
+ if kw.get('global_define'):
+ # compatibility, replace by pkgname in WAF 1.9?
+ self.define(self.have_define(kw['package']), 1, False)
else:
- self.env.append_unique('DEFINES_%s' % kw['uselib_store'], "%s=1" % define_name)
-
- if kw.get('add_have_to_env', 1):
- self.env[define_name] = 1
+ self.env.append_unique('DEFINES_%s' % pkgname, "%s=1" % self.have_define(pkgname))
+ self.env[self.have_define(pkgname)] = 1
# pkg-config version
if 'atleast_pkgconfig_version' in kw:
cmd = path + ['--atleast-pkgconfig-version=%s' % kw['atleast_pkgconfig_version']]
self.cmd_and_log(cmd, env=env)
+ if not 'okmsg' in kw:
+ kw['okmsg'] = 'yes'
return
- # single version for a module
+ # checking for the version of a module
+ for x in cfg_ver:
+ y = x.replace('-', '_')
+ if y in kw:
+ self.cmd_and_log(path + ['--%s=%s' % (x, kw[y]), kw['package']], env=env)
+ if not 'okmsg' in kw:
+ kw['okmsg'] = 'yes'
+ define_it()
+ break
+
+ # retrieving the version of a module
if 'modversion' in kw:
version = self.cmd_and_log(path + ['--modversion', kw['modversion']], env=env).strip()
- if not 'okmsg' in kw:
- kw['okmsg'] = version
- self.define(kw['define_name'], version)
+ self.define('%s_VERSION' % Utils.quote_define_name(kw.get('uselib_store', kw['modversion'])), version)
return version
lst = [] + path
- defi = kw.get('define_variable')
+ defi = kw.get('define_variable', None)
if not defi:
defi = self.env.PKG_CONFIG_DEFINES or {}
for key, val in defi.items():
@@ -314,32 +342,39 @@ def exec_cfg(self, kw):
# retrieving variables of a module
if 'variables' in kw:
- v_env = kw.get('env', self.env)
+ v = kw.get('env', self.env)
+ uselib = kw.get('uselib_store', kw['package'].upper())
vars = Utils.to_list(kw['variables'])
for v in vars:
val = self.cmd_and_log(lst + ['--variable=' + v], env=env).strip()
- var = '%s_%s' % (kw['uselib_store'], v)
- v_env[var] = val
+ var = '%s_%s' % (uselib, v)
+ v[var] = val
+ if not 'okmsg' in kw:
+ kw['okmsg'] = 'yes'
return
# so we assume the command-line will output flags to be parsed afterwards
ret = self.cmd_and_log(lst, env=env)
+ if not 'okmsg' in kw:
+ kw['okmsg'] = 'yes'
define_it()
- self.parse_flags(ret, kw['uselib_store'], kw.get('env', self.env), force_static=static, posix=kw.get('posix'))
+ self.parse_flags(ret, kw.get('uselib_store', kw['package'].upper()), kw.get('env', self.env), force_static=static, posix=kw.get('posix', None))
return ret
@conf
def check_cfg(self, *k, **kw):
"""
- Checks for configuration flags using a **-config**-like program (pkg-config, sdl-config, etc).
- This wraps internal calls to :py:func:`waflib.Tools.c_config.validate_cfg` and :py:func:`waflib.Tools.c_config.exec_cfg`
+ Check for configuration flags using a **-config**-like program (pkg-config, sdl-config, etc).
+ Encapsulate the calls to :py:func:`waflib.Tools.c_config.validate_cfg` and :py:func:`waflib.Tools.c_config.exec_cfg`
A few examples::
def configure(conf):
conf.load('compiler_c')
conf.check_cfg(package='glib-2.0', args='--libs --cflags')
+ conf.check_cfg(package='glib-2.0', uselib_store='GLIB', atleast_version='2.10.0',
+ args='--cflags --libs')
conf.check_cfg(package='pango')
conf.check_cfg(package='pango', uselib_store='MYPANGO', args=['--cflags', '--libs'])
conf.check_cfg(package='pango',
@@ -352,18 +387,24 @@ def check_cfg(self, *k, **kw):
conf.check_cfg(package='gtk+-2.0', variables=['includedir', 'prefix'], uselib_store='FOO')
print(conf.env.FOO_includedir)
"""
+ if k:
+ lst = k[0].split()
+ kw['package'] = lst[0]
+ kw['args'] = ' '.join(lst[1:])
+
self.validate_cfg(kw)
if 'msg' in kw:
self.start_msg(kw['msg'], **kw)
ret = None
try:
ret = self.exec_cfg(kw)
- except self.errors.WafError as e:
+ except self.errors.WafError:
if 'errmsg' in kw:
self.end_msg(kw['errmsg'], 'YELLOW', **kw)
if Logs.verbose > 1:
- self.to_log('Command failure: %s' % e)
- self.fatal('The configuration failed')
+ raise
+ else:
+ self.fatal('The configuration failed')
else:
if not ret:
ret = True
@@ -374,9 +415,6 @@ def check_cfg(self, *k, **kw):
return ret
def build_fun(bld):
- """
- Build function that is used for running configuration tests with ``conf.check()``
- """
if bld.kw['compile_filename']:
node = bld.srcnode.make_node(bld.kw['compile_filename'])
node.write(bld.kw['code'])
@@ -386,13 +424,13 @@ def build_fun(bld):
for k, v in bld.kw.items():
setattr(o, k, v)
- if not bld.kw.get('quiet'):
+ if not bld.kw.get('quiet', None):
bld.conf.to_log("==>\n%s\n<==" % bld.kw['code'])
@conf
def validate_c(self, kw):
"""
- Pre-checks the parameters that will be given to :py:func:`waflib.Configure.run_build`
+ pre-check the parameters that will be given to :py:func:`waflib.Configure.run_build`
:param compiler: c or cxx (tries to guess what is best)
:type compiler: string
@@ -417,9 +455,6 @@ def validate_c(self, kw):
:param auto_add_header_name: if header_name was set, add the headers in env.INCKEYS so the next tests will include these headers
:type auto_add_header_name: bool
"""
- for x in ('type_name', 'field_name', 'function_name'):
- if x in kw:
- Logs.warn('Invalid argument %r in test' % x)
if not 'build_fun' in kw:
kw['build_fun'] = build_fun
@@ -430,17 +465,17 @@ def validate_c(self, kw):
if not 'compiler' in kw and not 'features' in kw:
kw['compiler'] = 'c'
- if env.CXX_NAME and Task.classes.get('cxx'):
+ if env['CXX_NAME'] and Task.classes.get('cxx', None):
kw['compiler'] = 'cxx'
- if not self.env.CXX:
+ if not self.env['CXX']:
self.fatal('a c++ compiler is required')
else:
- if not self.env.CC:
+ if not self.env['CC']:
self.fatal('a c compiler is required')
if not 'compile_mode' in kw:
kw['compile_mode'] = 'c'
- if 'cxx' in Utils.to_list(kw.get('features', [])) or kw.get('compiler') == 'cxx':
+ if 'cxx' in Utils.to_list(kw.get('features',[])) or kw.get('compiler', '') == 'cxx':
kw['compile_mode'] = 'cxx'
if not 'type' in kw:
@@ -457,36 +492,71 @@ def validate_c(self, kw):
if not 'compile_filename' in kw:
kw['compile_filename'] = 'test.c' + ((kw['compile_mode'] == 'cxx') and 'pp' or '')
+
def to_header(dct):
if 'header_name' in dct:
dct = Utils.to_list(dct['header_name'])
return ''.join(['#include <%s>\n' % x for x in dct])
return ''
+ #OSX
if 'framework_name' in kw:
- # OSX, not sure this is used anywhere
fwkname = kw['framework_name']
if not 'uselib_store' in kw:
kw['uselib_store'] = fwkname.upper()
- if not kw.get('no_header'):
+
+ if not kw.get('no_header', False):
+ if not 'header_name' in kw:
+ kw['header_name'] = []
fwk = '%s/%s.h' % (fwkname, fwkname)
- if kw.get('remove_dot_h'):
+ if kw.get('remove_dot_h', None):
fwk = fwk[:-2]
- val = kw.get('header_name', [])
- kw['header_name'] = Utils.to_list(val) + [fwk]
+ kw['header_name'] = Utils.to_list(kw['header_name']) + [fwk]
+
kw['msg'] = 'Checking for framework %s' % fwkname
kw['framework'] = fwkname
+ #kw['frameworkpath'] = set it yourself
+
+ if 'function_name' in kw:
+ fu = kw['function_name']
+ if not 'msg' in kw:
+ kw['msg'] = 'Checking for function %s' % fu
+ kw['code'] = to_header(kw) + SNIP_FUNCTION % fu
+ if not 'uselib_store' in kw:
+ kw['uselib_store'] = fu.upper()
+ if not 'define_name' in kw:
+ kw['define_name'] = self.have_define(fu)
+
+ elif 'type_name' in kw:
+ tu = kw['type_name']
+ if not 'header_name' in kw:
+ kw['header_name'] = 'stdint.h'
+ if 'field_name' in kw:
+ field = kw['field_name']
+ kw['code'] = to_header(kw) + SNIP_FIELD % {'type_name' : tu, 'field_name' : field}
+ if not 'msg' in kw:
+ kw['msg'] = 'Checking for field %s in %s' % (field, tu)
+ if not 'define_name' in kw:
+ kw['define_name'] = self.have_define((tu + '_' + field).upper())
+ else:
+ kw['code'] = to_header(kw) + SNIP_TYPE % {'type_name' : tu}
+ if not 'msg' in kw:
+ kw['msg'] = 'Checking for type %s' % tu
+ if not 'define_name' in kw:
+ kw['define_name'] = self.have_define(tu.upper())
elif 'header_name' in kw:
if not 'msg' in kw:
kw['msg'] = 'Checking for header %s' % kw['header_name']
l = Utils.to_list(kw['header_name'])
- assert len(l), 'list of headers in header_name is empty'
+ assert len(l)>0, 'list of headers in header_name is empty'
kw['code'] = to_header(kw) + SNIP_EMPTY_PROGRAM
+
if not 'uselib_store' in kw:
kw['uselib_store'] = l[0].upper()
+
if not 'define_name' in kw:
kw['define_name'] = self.have_define(l[0])
@@ -522,7 +592,7 @@ def validate_c(self, kw):
kw['execute'] = False
if kw['execute']:
kw['features'].append('test_exec')
- kw['chmod'] = Utils.O755
+ kw['chmod'] = 493
if not 'errmsg' in kw:
kw['errmsg'] = 'not found'
@@ -538,12 +608,11 @@ def validate_c(self, kw):
kw['code'] = '\n'.join(['#include <%s>' % x for x in self.env[INCKEYS]]) + '\n' + kw['code']
# in case defines lead to very long command-lines
- if kw.get('merge_config_header') or env.merge_config_header:
+ if kw.get('merge_config_header', False) or env.merge_config_header:
kw['code'] = '%s\n\n%s' % (self.get_config_header(), kw['code'])
env.DEFINES = [] # modify the copy
- if not kw.get('success'):
- kw['success'] = None
+ if not kw.get('success'): kw['success'] = None
if 'define_name' in kw:
self.undefine(kw['define_name'])
@@ -552,76 +621,63 @@ def validate_c(self, kw):
@conf
def post_check(self, *k, **kw):
- """
- Sets the variables after a test executed in
- :py:func:`waflib.Tools.c_config.check` was run successfully
- """
+ "Set the variables after a test executed in :py:func:`waflib.Tools.c_config.check` was run successfully"
+
is_success = 0
if kw['execute']:
if kw['success'] is not None:
- if kw.get('define_ret'):
+ if kw.get('define_ret', False):
is_success = kw['success']
else:
is_success = (kw['success'] == 0)
else:
is_success = (kw['success'] == 0)
- if kw.get('define_name'):
- comment = kw.get('comment', '')
- define_name = kw['define_name']
- if kw['execute'] and kw.get('define_ret') and isinstance(is_success, str):
- if kw.get('global_define', 1):
- self.define(define_name, is_success, quote=kw.get('quote', 1), comment=comment)
+ if 'define_name' in kw:
+ # TODO simplify!
+ if 'header_name' in kw or 'function_name' in kw or 'type_name' in kw or 'fragment' in kw:
+ if kw['execute'] and kw.get('define_ret', None) and isinstance(is_success, str):
+ self.define(kw['define_name'], is_success, quote=kw.get('quote', 1))
else:
- if kw.get('quote', 1):
- succ = '"%s"' % is_success
- else:
- succ = int(is_success)
- val = '%s=%s' % (define_name, succ)
- var = 'DEFINES_%s' % kw['uselib_store']
- self.env.append_value(var, val)
+ self.define_cond(kw['define_name'], is_success)
else:
- if kw.get('global_define', 1):
- self.define_cond(define_name, is_success, comment=comment)
- else:
- var = 'DEFINES_%s' % kw['uselib_store']
- self.env.append_value(var, '%s=%s' % (define_name, int(is_success)))
-
- # define conf.env.HAVE_X to 1
- if kw.get('add_have_to_env', 1):
- if kw.get('uselib_store'):
- self.env[self.have_define(kw['uselib_store'])] = 1
- elif kw['execute'] and kw.get('define_ret'):
- self.env[define_name] = is_success
- else:
- self.env[define_name] = int(is_success)
+ self.define_cond(kw['define_name'], is_success)
+
+ # consistency with check_cfg
+ if kw.get('global_define', None):
+ self.env[kw['define_name']] = is_success
if 'header_name' in kw:
- if kw.get('auto_add_header_name'):
+ if kw.get('auto_add_header_name', False):
self.env.append_value(INCKEYS, Utils.to_list(kw['header_name']))
if is_success and 'uselib_store' in kw:
from waflib.Tools import ccroot
- # See get_uselib_vars in ccroot.py
- _vars = set()
+
+ # TODO see get_uselib_vars from ccroot.py
+ _vars = set([])
for x in kw['features']:
if x in ccroot.USELIB_VARS:
_vars |= ccroot.USELIB_VARS[x]
for k in _vars:
- x = k.lower()
- if x in kw:
- self.env.append_value(k + '_' + kw['uselib_store'], kw[x])
+ lk = k.lower()
+ if lk in kw:
+ val = kw[lk]
+ # remove trailing slash
+ if isinstance(val, str):
+ val = val.rstrip(os.path.sep)
+ self.env.append_unique(k + '_' + kw['uselib_store'], Utils.to_list(val))
return is_success
@conf
def check(self, *k, **kw):
"""
- Performs a configuration test by calling :py:func:`waflib.Configure.run_build`.
+ Perform a configuration test by calling :py:func:`waflib.Configure.run_build`.
For the complete list of parameters, see :py:func:`waflib.Tools.c_config.validate_c`.
- To force a specific compiler, pass ``compiler='c'`` or ``compiler='cxx'`` to the list of arguments
+ To force a specific compiler, pass "compiler='c'" or "compiler='cxx'" in the arguments
- Besides build targets, complete builds can be given through a build function. All files will
+ Besides build targets, complete builds can be given though a build function. All files will
be written to a temporary directory::
def build(bld):
@@ -655,7 +711,7 @@ def check(self, *k, **kw):
class test_exec(Task.Task):
"""
- A task that runs programs after they are built. See :py:func:`waflib.Tools.c_config.test_exec_fun`.
+ A task for executing a programs after they are built. See :py:func:`waflib.Tools.c_config.test_exec_fun`.
"""
color = 'PINK'
def run(self):
@@ -690,51 +746,20 @@ def test_exec_fun(self):
@conf
def check_cxx(self, *k, **kw):
- """
- Runs a test with a task generator of the form::
-
- conf.check(features='cxx cxxprogram', ...)
- """
+ # DO NOT USE
kw['compiler'] = 'cxx'
return self.check(*k, **kw)
@conf
def check_cc(self, *k, **kw):
- """
- Runs a test with a task generator of the form::
-
- conf.check(features='c cprogram', ...)
- """
+ # DO NOT USE
kw['compiler'] = 'c'
return self.check(*k, **kw)
@conf
-def set_define_comment(self, key, comment):
+def define(self, key, val, quote=True):
"""
- Sets a comment that will appear in the configuration header
-
- :type key: string
- :type comment: string
- """
- coms = self.env.DEFINE_COMMENTS
- if not coms:
- coms = self.env.DEFINE_COMMENTS = {}
- coms[key] = comment or ''
-
-@conf
-def get_define_comment(self, key):
- """
- Returns the comment associated to a define
-
- :type key: string
- """
- coms = self.env.DEFINE_COMMENTS or {}
- return coms.get(key, '')
-
-@conf
-def define(self, key, val, quote=True, comment=''):
- """
- Stores a single define and its state into ``conf.env.DEFINES``. The value is cast to an integer (0/1).
+ Store a single define and its state into conf.env.DEFINES. If the value is True, False or None it is cast to 1 or 0.
:param key: define name
:type key: string
@@ -743,9 +768,8 @@ def define(self, key, val, quote=True, comment=''):
:param quote: enclose strings in quotes (yes by default)
:type quote: bool
"""
- assert isinstance(key, str)
- if not key:
- return
+ assert key and isinstance(key, str)
+
if val is True:
val = 1
elif val in (False, None):
@@ -758,7 +782,7 @@ def define(self, key, val, quote=True, comment=''):
app = s % (key, str(val))
ban = key + '='
- lst = self.env.DEFINES
+ lst = self.env['DEFINES']
for x in lst:
if x.startswith(ban):
lst[lst.index(x)] = app
@@ -767,29 +791,26 @@ def define(self, key, val, quote=True, comment=''):
self.env.append_value('DEFINES', app)
self.env.append_unique(DEFKEYS, key)
- self.set_define_comment(key, comment)
@conf
-def undefine(self, key, comment=''):
+def undefine(self, key):
"""
- Removes a global define from ``conf.env.DEFINES``
+ Remove a define from conf.env.DEFINES
:param key: define name
:type key: string
"""
- assert isinstance(key, str)
- if not key:
- return
+ assert key and isinstance(key, str)
+
ban = key + '='
- lst = [x for x in self.env.DEFINES if not x.startswith(ban)]
- self.env.DEFINES = lst
+ lst = [x for x in self.env['DEFINES'] if not x.startswith(ban)]
+ self.env['DEFINES'] = lst
self.env.append_unique(DEFKEYS, key)
- self.set_define_comment(key, comment)
@conf
-def define_cond(self, key, val, comment=''):
+def define_cond(self, key, val):
"""
- Conditionally defines a name::
+ Conditionally define a name::
def configure(conf):
conf.define_cond('A', True)
@@ -802,19 +823,16 @@ def define_cond(self, key, val, comment=''):
:param val: value
:type val: int or string
"""
- assert isinstance(key, str)
- if not key:
- return
+ assert key and isinstance(key, str)
+
if val:
- self.define(key, 1, comment=comment)
+ self.define(key, 1)
else:
- self.undefine(key, comment=comment)
+ self.undefine(key)
@conf
def is_defined(self, key):
"""
- Indicates whether a particular define is globally set in ``conf.env.DEFINES``.
-
:param key: define name
:type key: string
:return: True if the define is set
@@ -823,7 +841,7 @@ def is_defined(self, key):
assert key and isinstance(key, str)
ban = key + '='
- for x in self.env.DEFINES:
+ for x in self.env['DEFINES']:
if x.startswith(ban):
return True
return False
@@ -831,16 +849,14 @@ def is_defined(self, key):
@conf
def get_define(self, key):
"""
- Returns the value of an existing define, or None if not found
-
:param key: define name
:type key: string
- :rtype: string
+ :return: the value of a previously stored define or None if it is not set
"""
assert key and isinstance(key, str)
ban = key + '='
- for x in self.env.DEFINES:
+ for x in self.env['DEFINES']:
if x.startswith(ban):
return x[len(ban):]
return None
@@ -848,9 +864,6 @@ def get_define(self, key):
@conf
def have_define(self, key):
"""
- Returns a variable suitable for command-line or header use by removing invalid characters
- and prefixing it with ``HAVE_``
-
:param key: define name
:type key: string
:return: the input key prefixed by *HAVE_* and substitute any invalid characters.
@@ -861,7 +874,7 @@ def have_define(self, key):
@conf
def write_config_header(self, configfile='', guard='', top=False, defines=True, headers=False, remove=True, define_prefix=''):
"""
- Writes a configuration header containing defines and includes::
+ Write a configuration header containing defines and includes::
def configure(cnf):
cnf.define('A', 1)
@@ -885,8 +898,7 @@ def write_config_header(self, configfile='', guard='', top=False, defines=True,
:type define_prefix: string
:param define_prefix: prefix all the defines in the file with a particular prefix
"""
- if not configfile:
- configfile = WAF_CONFIG_H
+ if not configfile: configfile = WAF_CONFIG_H
waf_guard = guard or 'W_%s_WAF' % Utils.quote_define_name(configfile)
node = top and self.bldnode or self.path.get_bld()
@@ -911,7 +923,7 @@ def write_config_header(self, configfile='', guard='', top=False, defines=True,
@conf
def get_config_header(self, defines=True, headers=False, define_prefix=''):
"""
- Creates the contents of a ``config.h`` file from the defines and includes
+ Create the contents of a ``config.h`` file from the defines and includes
set in conf.env.define_key / conf.env.include_key. No include guards are added.
A prelude will be added from the variable env.WAF_CONFIG_H_PRELUDE if provided. This
@@ -941,25 +953,22 @@ def get_config_header(self, defines=True, headers=False, define_prefix=''):
if defines:
tbl = {}
- for k in self.env.DEFINES:
+ for k in self.env['DEFINES']:
a, _, b = k.partition('=')
tbl[a] = b
for k in self.env[DEFKEYS]:
- caption = self.get_define_comment(k)
- if caption:
- caption = ' /* %s */' % caption
try:
- txt = '#define %s%s %s%s' % (define_prefix, k, tbl[k], caption)
+ txt = '#define %s%s %s' % (define_prefix, k, tbl[k])
except KeyError:
- txt = '/* #undef %s%s */%s' % (define_prefix, k, caption)
+ txt = '/* #undef %s%s */' % (define_prefix, k)
lst.append(txt)
return "\n".join(lst)
@conf
def cc_add_flags(conf):
"""
- Adds CFLAGS / CPPFLAGS from os.environ to conf.env
+ Add CFLAGS / CPPFLAGS from os.environ to conf.env
"""
conf.add_os_flags('CPPFLAGS', dup=False)
conf.add_os_flags('CFLAGS', dup=False)
@@ -967,7 +976,7 @@ def cc_add_flags(conf):
@conf
def cxx_add_flags(conf):
"""
- Adds CXXFLAGS / CPPFLAGS from os.environ to conf.env
+ Add CXXFLAGS / CPPFLAGS from os.environ to conf.env
"""
conf.add_os_flags('CPPFLAGS', dup=False)
conf.add_os_flags('CXXFLAGS', dup=False)
@@ -975,7 +984,7 @@ def cxx_add_flags(conf):
@conf
def link_add_flags(conf):
"""
- Adds LINKFLAGS / LDFLAGS from os.environ to conf.env
+ Add LINKFLAGS / LDFLAGS from os.environ to conf.env
"""
conf.add_os_flags('LINKFLAGS', dup=False)
conf.add_os_flags('LDFLAGS', dup=False)
@@ -983,7 +992,7 @@ def link_add_flags(conf):
@conf
def cc_load_tools(conf):
"""
- Loads the Waf c extensions
+ Load the c tool
"""
if not conf.env.DEST_OS:
conf.env.DEST_OS = Utils.unversioned_sys_platform()
@@ -992,7 +1001,7 @@ def cc_load_tools(conf):
@conf
def cxx_load_tools(conf):
"""
- Loads the Waf c++ extensions
+ Load the cxx tool
"""
if not conf.env.DEST_OS:
conf.env.DEST_OS = Utils.unversioned_sys_platform()
@@ -1001,17 +1010,15 @@ def cxx_load_tools(conf):
@conf
def get_cc_version(conf, cc, gcc=False, icc=False, clang=False):
"""
- Runs the preprocessor to determine the gcc/icc/clang version
+ Run the preprocessor to determine the compiler version
The variables CC_VERSION, DEST_OS, DEST_BINFMT and DEST_CPU will be set in *conf.env*
-
- :raise: :py:class:`waflib.Errors.ConfigurationError`
"""
cmd = cc + ['-dM', '-E', '-']
env = conf.env.env or None
try:
out, err = conf.cmd_and_log(cmd, output=0, input='\n'.encode(), env=env)
- except Errors.WafError:
+ except Exception:
conf.fatal('Could not determine the compiler version %r' % cmd)
if gcc:
@@ -1059,8 +1066,6 @@ def get_cc_version(conf, cc, gcc=False, icc=False, clang=False):
conf.env.DEST_BINFMT = 'elf'
elif isD('__WINNT__') or isD('__CYGWIN__') or isD('_WIN32'):
conf.env.DEST_BINFMT = 'pe'
- if not conf.env.IMPLIBDIR:
- conf.env.IMPLIBDIR = conf.env.LIBDIR # for .lib or .dll.a files
conf.env.LIBDIR = conf.env.BINDIR
elif isD('__APPLE__'):
conf.env.DEST_BINFMT = 'mac-o'
@@ -1077,22 +1082,19 @@ def get_cc_version(conf, cc, gcc=False, icc=False, clang=False):
Logs.debug('ccroot: dest platform: ' + ' '.join([conf.env[x] or '?' for x in ('DEST_OS', 'DEST_BINFMT', 'DEST_CPU')]))
if icc:
ver = k['__INTEL_COMPILER']
- conf.env.CC_VERSION = (ver[:-2], ver[-2], ver[-1])
+ conf.env['CC_VERSION'] = (ver[:-2], ver[-2], ver[-1])
else:
if isD('__clang__') and isD('__clang_major__'):
- conf.env.CC_VERSION = (k['__clang_major__'], k['__clang_minor__'], k['__clang_patchlevel__'])
+ conf.env['CC_VERSION'] = (k['__clang_major__'], k['__clang_minor__'], k['__clang_patchlevel__'])
else:
# older clang versions and gcc
- conf.env.CC_VERSION = (k['__GNUC__'], k['__GNUC_MINOR__'], k.get('__GNUC_PATCHLEVEL__', '0'))
+ conf.env['CC_VERSION'] = (k['__GNUC__'], k['__GNUC_MINOR__'], k.get('__GNUC_PATCHLEVEL__', '0'))
return k
@conf
def get_xlc_version(conf, cc):
- """
- Returns the Aix compiler version
+ """Get the compiler version"""
- :raise: :py:class:`waflib.Errors.ConfigurationError`
- """
cmd = cc + ['-qversion']
try:
out, err = conf.cmd_and_log(cmd, output=0)
@@ -1105,18 +1107,15 @@ def get_xlc_version(conf, cc):
match = version_re(out or err)
if match:
k = match.groupdict()
- conf.env.CC_VERSION = (k['major'], k['minor'])
+ conf.env['CC_VERSION'] = (k['major'], k['minor'])
break
else:
conf.fatal('Could not determine the XLC version.')
@conf
def get_suncc_version(conf, cc):
- """
- Returns the Sun compiler version
+ """Get the compiler version"""
- :raise: :py:class:`waflib.Errors.ConfigurationError`
- """
cmd = cc + ['-V']
try:
out, err = conf.cmd_and_log(cmd, output=0)
@@ -1130,14 +1129,11 @@ def get_suncc_version(conf, cc):
version = (out or err)
version = version.splitlines()[0]
- # cc: Sun C 5.10 SunOS_i386 2009/06/03
- # cc: Studio 12.5 Sun C++ 5.14 SunOS_sparc Beta 2015/11/17
- # cc: WorkShop Compilers 5.0 98/12/15 C 5.0
- 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
+ version_re = re.compile(r'cc:\s+sun\s+(c\+\+|c)\s+(?P<major>\d*)\.(?P<minor>\d*)', re.I).search
match = version_re(version)
if match:
k = match.groupdict()
- conf.env.CC_VERSION = (k['major'], k['minor'])
+ conf.env['CC_VERSION'] = (k['major'], k['minor'])
else:
conf.fatal('Could not determine the suncc version.')
@@ -1146,7 +1142,7 @@ def get_suncc_version(conf, cc):
@conf
def add_as_needed(self):
"""
- Adds ``--as-needed`` to the *LINKFLAGS*
+ Add ``--as-needed`` to the *LINKFLAGS*
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.
"""
if self.env.DEST_BINFMT == 'elf' and 'gcc' in (self.env.CXX_NAME, self.env.CC_NAME):
@@ -1154,31 +1150,22 @@ def add_as_needed(self):
# ============ parallel configuration
-class cfgtask(Task.Task):
+class cfgtask(Task.TaskBase):
"""
- A task that executes build configuration tests (calls conf.check)
+ A task that executes configuration tests
+ make sure that the checks write to conf.env in a thread-safe manner
- Make sure to use locks if concurrent access to the same conf.env data is necessary.
+ for the moment it only executes conf.check
"""
- def __init__(self, *k, **kw):
- Task.Task.__init__(self, *k, **kw)
- self.run_after = set()
-
def display(self):
return ''
def runnable_status(self):
- for x in self.run_after:
- if not x.hasrun:
- return Task.ASK_LATER
return Task.RUN_ME
def uid(self):
return Utils.SIG_NIL
- def signature(self):
- return Utils.SIG_NIL
-
def run(self):
conf = self.conf
bld = Build.BuildContext(top_dir=conf.srcnode.abspath(), out_dir=conf.bldnode.abspath())
@@ -1186,73 +1173,22 @@ class cfgtask(Task.Task):
bld.init_dirs()
bld.in_msg = 1 # suppress top-level start_msg
bld.logger = self.logger
- bld.multicheck_task = self
- args = self.args
try:
- if 'func' in args:
- bld.test(build_fun=args['func'],
- msg=args.get('msg', ''),
- okmsg=args.get('okmsg', ''),
- errmsg=args.get('errmsg', ''),
- )
- else:
- args['multicheck_mandatory'] = args.get('mandatory', True)
- args['mandatory'] = True
- try:
- bld.check(**args)
- finally:
- args['mandatory'] = args['multicheck_mandatory']
+ bld.check(**self.args)
except Exception:
return 1
- def process(self):
- Task.Task.process(self)
- if 'msg' in self.args:
- with self.generator.bld.multicheck_lock:
- self.conf.start_msg(self.args['msg'])
- if self.hasrun == Task.NOT_RUN:
- self.conf.end_msg('test cancelled', 'YELLOW')
- elif self.hasrun != Task.SUCCESS:
- self.conf.end_msg(self.args.get('errmsg', 'no'), 'YELLOW')
- else:
- self.conf.end_msg(self.args.get('okmsg', 'yes'), 'GREEN')
-
@conf
def multicheck(self, *k, **kw):
"""
- Runs configuration tests in parallel; results are printed sequentially at the end of the build
- but each test must provide its own msg value to display a line::
-
- def test_build(ctx):
- ctx.in_msg = True # suppress console outputs
- ctx.check_large_file(mandatory=False)
-
- conf.multicheck(
- {'header_name':'stdio.h', 'msg':'... stdio', 'uselib_store':'STDIO', 'global_define':False},
- {'header_name':'xyztabcd.h', 'msg':'... optional xyztabcd.h', 'mandatory': False},
- {'header_name':'stdlib.h', 'msg':'... stdlib', 'okmsg': 'aye', 'errmsg': 'nope'},
- {'func': test_build, 'msg':'... testing an arbitrary build function', 'okmsg':'ok'},
- msg = 'Checking for headers in parallel',
- mandatory = True, # mandatory tests raise an error at the end
- run_all_tests = True, # try running all tests
- )
-
- The configuration tests may modify the values in conf.env in any order, and the define
- values can affect configuration tests being executed. It is hence recommended
- to provide `uselib_store` values with `global_define=False` to prevent such issues.
+ Use tuples to perform parallel configuration tests
"""
self.start_msg(kw.get('msg', 'Executing %d configuration tests' % len(k)), **kw)
- # Force a copy so that threads append to the same list at least
- # no order is guaranteed, but the values should not disappear at least
- for var in ('DEFINES', DEFKEYS):
- self.env.append_value(var, [])
- self.env.DEFINE_COMMENTS = self.env.DEFINE_COMMENTS or {}
-
- # define a task object that will execute our tests
class par(object):
def __init__(self):
self.keep = False
+ self.returned_tasks = []
self.task_sigs = {}
self.progress_bar = 0
def total(self):
@@ -1261,13 +1197,9 @@ def multicheck(self, *k, **kw):
return
bld = par()
- bld.keep = kw.get('run_all_tests', True)
- bld.imp_sigs = {}
tasks = []
-
- id_to_task = {}
for dct in k:
- x = Task.classes['cfgtask'](bld=bld, env=None)
+ x = cfgtask(bld=bld)
tasks.append(x)
x.args = dct
x.bld = bld
@@ -1277,38 +1209,18 @@ def multicheck(self, *k, **kw):
# bind a logger that will keep the info in memory
x.logger = Logs.make_mem_logger(str(id(x)), self.logger)
- if 'id' in dct:
- id_to_task[dct['id']] = x
-
- # second pass to set dependencies with after_test/before_test
- for x in tasks:
- for key in Utils.to_list(x.args.get('before_tests', [])):
- tsk = id_to_task[key]
- if not tsk:
- raise ValueError('No test named %r' % key)
- tsk.run_after.add(x)
- for key in Utils.to_list(x.args.get('after_tests', [])):
- tsk = id_to_task[key]
- if not tsk:
- raise ValueError('No test named %r' % key)
- x.run_after.add(tsk)
-
def it():
yield tasks
while 1:
yield []
- bld.producer = p = Runner.Parallel(bld, Options.options.jobs)
- bld.multicheck_lock = Utils.threading.Lock()
+ p = Runner.Parallel(bld, Options.options.jobs)
p.biter = it()
-
- self.end_msg('started')
p.start()
# flush the logs in order into the config.log
for x in tasks:
x.logger.memhandler.flush()
- self.start_msg('-> processing test results')
if p.error:
for x in p.error:
if getattr(x, 'err_msg', None):
@@ -1316,36 +1228,10 @@ def multicheck(self, *k, **kw):
self.end_msg('fail', color='RED')
raise Errors.WafError('There is an error in the library, read config.log for more information')
- failure_count = 0
- for x in tasks:
- if x.hasrun not in (Task.SUCCESS, Task.NOT_RUN):
- failure_count += 1
-
- if failure_count:
- self.end_msg(kw.get('errmsg', '%s test failed' % failure_count), color='YELLOW', **kw)
- else:
- self.end_msg('all ok', **kw)
-
for x in tasks:
if x.hasrun != Task.SUCCESS:
- if x.args.get('mandatory', True):
- self.fatal(kw.get('fatalmsg') or 'One of the tests has failed, read config.log for more information')
+ self.end_msg(kw.get('errmsg', 'no'), color='YELLOW', **kw)
+ self.fatal(kw.get('fatalmsg', None) or 'One of the tests has failed, read config.log for more information')
-@conf
-def check_gcc_o_space(self, mode='c'):
- if int(self.env.CC_VERSION[0]) > 4:
- # this is for old compilers
- return
- self.env.stash()
- if mode == 'c':
- self.env.CCLNK_TGT_F = ['-o', '']
- elif mode == 'cxx':
- self.env.CXXLNK_TGT_F = ['-o', '']
- features = '%s %sshlib' % (mode, mode)
- try:
- self.check(msg='Checking if the -o link must be split from arguments', fragment=SNIP_EMPTY_PROGRAM, features=features)
- except self.errors.ConfigurationError:
- self.env.revert()
- else:
- self.env.commit()
+ self.end_msg('ok', **kw)