Repository URL to install this package:
|
Version:
1.10.0 ▾
|
from __future__ import division, absolute_import, print_function
import os
import re
import waflib.Configure
import waflib.Tools.c_config
from waflib import Logs, Utils
from .common \
import \
LONG_DOUBLE_REPRESENTATION_SRC, pyod, \
long_double_representation
DEFKEYS = waflib.Tools.c_config.DEFKEYS
DEFINE_COMMENTS = "define_commentz"
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 ''
# Make the given string safe to be used as a CPP macro
def sanitize_string(s):
key_up = s.upper()
return re.sub('[^A-Z0-9_]', '_', key_up)
def validate_arguments(self, kw):
if not 'env' in kw:
kw['env'] = self.env.derive()
if not "compile_mode" in kw:
kw["compile_mode"] = "c"
if not 'compile_filename' in kw:
kw['compile_filename'] = 'test.c' + \
((kw['compile_mode'] == 'cxx') and 'pp' or '')
if not 'features' in kw:
kw['features'] = [kw['compile_mode']]
if not 'execute' in kw:
kw['execute'] = False
if not 'okmsg' in kw:
kw['okmsg'] = 'yes'
if not 'errmsg' in kw:
kw['errmsg'] = 'no !'
if 'define_name' in kw:
comment = kw.get('define_comment', None)
self.undefine_with_comment(kw['define_name'], comment)
def try_compile(self, kw):
self.start_msg(kw["msg"])
ret = None
try:
ret = self.run_c_code(**kw)
except self.errors.ConfigurationError as e:
self.end_msg(kw['errmsg'], 'YELLOW')
if Logs.verbose > 1:
raise
else:
self.fatal('The configuration failed')
else:
kw['success'] = ret
self.end_msg(self.ret_msg(kw['okmsg'], kw))
@waflib.Configure.conf
def check_header(self, header_name, **kw):
code = """
%s
int main()
{
}
""" % to_header({"header_name": header_name})
kw["code"] = code
kw["define_comment"] = "/* Define to 1 if you have the <%s> header file. */" % header_name
kw["define_name"] = "HAVE_%s" % sanitize_string(header_name)
if not "features" in kw:
kw["features"] = ["c"]
kw["msg"] = "Checking for header %r" % header_name
validate_arguments(self, kw)
try_compile(self, kw)
ret = kw["success"]
if ret == 0:
kw["define_value"] = 1
else:
kw["define_value"] = 0
self.post_check(**kw)
if not kw.get('execute', False):
return ret == 0
return ret
@waflib.Configure.conf
def check_declaration(self, symbol, **kw):
code = r"""
int main()
{
#ifndef %s
(void) %s;
#endif
;
return 0;
}
""" % (symbol, symbol)
kw["code"] = to_header(kw) + code
kw["msg"] = "Checking for macro %r" % symbol
kw["errmsg"] = "not found"
kw["okmsg"] = "yes"
validate_arguments(self, kw)
try_compile(self, kw)
ret = kw["success"]
kw["define_name"] = "HAVE_DECL_%s" % sanitize_string(symbol)
kw["define_comment"] = "/* Set to 1 if %s is defined. */" % symbol
self.post_check(**kw)
if not kw.get('execute', False):
return ret == 0
return ret
@waflib.Configure.conf
def check_type(self, type_name, **kw):
code = r"""
int main() {
if ((%(type_name)s *) 0)
return 0;
if (sizeof (%(type_name)s))
return 0;
}
""" % {"type_name": type_name}
kw["code"] = to_header(kw) + code
kw["msg"] = "Checking for type %r" % type_name
kw["errmsg"] = "not found"
kw["okmsg"] = "yes"
validate_arguments(self, kw)
try_compile(self, kw)
ret = kw["success"]
if ret == 0:
kw["define_value"] = 1
else:
kw["define_value"] = 0
kw["define_name"] = "HAVE_%s" % sanitize_string(type_name)
kw["define_comment"] = "/* Define to 1 if the system has the type `%s'. */" % type_name
self.post_check(**kw)
if not kw.get('execute', False):
return ret == 0
return ret
def do_binary_search(conf, type_name, kw):
code = """\
typedef %(type)s waf_check_sizeof_type;
int main ()
{
static int test_array [1 - 2 * !(((long) (sizeof (waf_check_sizeof_type))) >= 0)];
test_array [0] = 0
;
return 0;
}
""" % {"type": type_name}
kw["code"] = to_header(kw) + code
try:
conf.run_c_code(**kw)
except conf.errors.ConfigurationError as e:
conf.end_msg("failed !")
if waflib.Logs.verbose > 1:
raise
else:
conf.fatal("The configuration failed !")
body = r"""
typedef %(type)s waf_check_sizeof_type;
int main ()
{
static int test_array [1 - 2 * !(((long) (sizeof (waf_check_sizeof_type))) <= %(size)s)];
test_array [0] = 0
;
return 0;
}
"""
# The principle is simple: we first find low and high bounds
# of size for the type, where low/high are looked up on a log
# scale. Then, we do a binary search to find the exact size
# between low and high
low = 0
mid = 0
while True:
try:
kw["code"] = to_header(kw) + body % {"type": type_name, "size": mid}
validate_arguments(conf, kw)
conf.run_c_code(**kw)
break
except conf.errors.ConfigurationError:
#log.info("failure to test for bound %d" % mid)
low = mid + 1
mid = 2 * mid + 1
high = mid
ret = None
# Binary search:
while low != high:
mid = (high - low) / 2 + low
try:
kw["code"] = to_header(kw) + body % {"type": type_name, "size": mid}
validate_arguments(conf, kw)
ret = conf.run_c_code(**kw)
high = mid
except conf.errors.ConfigurationError:
low = mid + 1
return low
@waflib.Configure.conf
def check_type_size(conf, type_name, expected_sizes=None, **kw):
kw["define_name"] = "SIZEOF_%s" % sanitize_string(type_name)
kw["define_comment"] = "/* The size of `%s', as computed by sizeof. */" % type_name
kw["msg"] = "Checking sizeof(%s)" % type_name
validate_arguments(conf, kw)
conf.start_msg(kw["msg"])
if expected_sizes is not None:
try:
val = int(expected_sizes)
except TypeError:
values = expected_sizes
else:
values = [val]
size = None
for value in values:
code = """\
typedef %(type)s waf_check_sizeof_type;
int main ()
{
static int test_array [1 - 2 * !(((long) (sizeof (waf_check_sizeof_type))) == %(size)d)];
test_array [0] = 0
;
return 0;
}
""" % {"type": type_name, "size": value}
kw["code"] = to_header(kw) + code
try:
conf.run_c_code(**kw)
size = value
break
except conf.errors.ConfigurationError:
pass
if size is None:
size = do_binary_search(conf, type_name, kw)
else:
size = do_binary_search(conf, type_name, kw)
kw["define_value"] = size
kw["success"] = 0
conf.end_msg(size)
conf.post_check(**kw)
return size
@waflib.Configure.conf
def check_functions_at_once(self, funcs, **kw):
header = []
header = ['#ifdef __cplusplus']
header.append('extern "C" {')
header.append('#endif')
for f in funcs:
header.append("\tchar %s();" % f)
# Handle MSVC intrinsics: force MS compiler to make a function
# call. Useful to test for some functions when built with
# optimization on, to avoid build error because the intrinsic
# and our 'fake' test declaration do not match.
header.append("#ifdef _MSC_VER")
header.append("#pragma function(%s)" % f)
header.append("#endif")
header.append('#ifdef __cplusplus')
header.append('};')
header.append('#endif')
funcs_decl = "\n".join(header)
tmp = []
for f in funcs:
tmp.append("\t%s();" % f)
tmp = "\n".join(tmp)
code = r"""
%(include)s
%(funcs_decl)s
int main (void)
{
%(tmp)s
return 0;
}
""" % {"tmp": tmp, "include": to_header(kw), "funcs_decl": funcs_decl}
kw["code"] = code
if not "features" in kw:
kw["features"] = ["c", "cprogram"]
msg = ", ".join(funcs)
if len(msg) > 30:
_funcs = list(funcs)
msg = []
while len(", ".join(msg)) < 30 and _funcs:
msg.append(_funcs.pop(0))
msg = ", ".join(msg) + ",..."
if "lib" in kw:
kw["msg"] = "Checking for functions %s in library %r" % (msg, kw["lib"])
else:
kw["msg"] = "Checking for functions %s" % msg
validate_arguments(self, kw)
try_compile(self, kw)
ret = kw["success"]
# We set the config.h define here because we need to define several of them
# in one shot
if ret == 0:
for f in funcs:
self.define_with_comment("HAVE_%s" % sanitize_string(f), 1,
"/* Define to 1 if you have the `%s' function. */" % f)
self.post_check(**kw)
if not kw.get('execute', False):
return ret == 0
return ret
@waflib.Configure.conf
def check_inline(conf, **kw):
validate_arguments(conf, kw)
code = """
#ifndef __cplusplus
static %(inline)s int static_func (void)
{
return 0;
}
%(inline)s int nostatic_func (void)
{
return 0;
}
#endif"""
conf.start_msg("Checking for inline support")
inline = None
for k in ['inline', '__inline__', '__inline']:
try:
kw["code"] = code % {"inline": k}
ret = conf.run_c_code(**kw)
inline = k
break
except conf.errors.ConfigurationError:
pass
if inline is None:
conf.end_msg("failed", 'YELLOW')
if Logs.verbose > 1:
raise
else:
conf.fatal('The configuration failed')
else:
kw['success'] = ret
conf.end_msg(inline)
return inline
@waflib.Configure.conf
def check_ldouble_representation(conf, **kw):
msg = {
'INTEL_EXTENDED_12_BYTES_LE': "Intel extended, little endian",
'INTEL_EXTENDED_16_BYTES_LE': "Intel extended, little endian",
'IEEE_QUAD_BE': "IEEE Quad precision, big endian",
'IEEE_QUAD_LE': "IEEE Quad precision, little endian",
'IEEE_DOUBLE_LE': "IEEE Double precision, little endian",
'IEEE_DOUBLE_BE': "IEEE Double precision, big endian"
}
code = LONG_DOUBLE_REPRESENTATION_SRC % {'type': 'long double'}
validate_arguments(conf, kw)
conf.start_msg("Checking for long double representation... ")
try:
kw["code"] = code
ret = conf.run_c_code(**kw)
except conf.errors.ConfigurationError as e:
conf.end_msg(kw['errmsg'], 'YELLOW')
if Logs.verbose > 1:
raise
else:
conf.fatal('The configuration failed')
else:
task_gen = conf.test_bld.groups[0][0]
obj_filename = task_gen.tasks[0].outputs[0].abspath()
tp = long_double_representation(pyod(obj_filename))
kw['success'] = ret
conf.end_msg(msg[tp])
kw["define_name"] = "HAVE_LDOUBLE_%s" % tp
kw["define_comment"] = "/* Define for arch-specific long double representation */"
ret = kw["success"]
conf.post_check(**kw)
if not kw.get('execute', False):
return ret == 0
return ret
@waflib.Configure.conf
def post_check(self, *k, **kw):
"set the variables after a test was run successfully"
is_success = False
if kw['execute']:
if kw['success'] is not None:
if kw.get('define_ret', False):
is_success = kw['success']
else:
is_success = (kw['success'] == 0)
else:
is_success = (kw['success'] == 0)
def define_or_stuff():
nm = kw['define_name']
cmt = kw.get('define_comment', None)
value = kw.get("define_value", is_success)
if kw['execute'] and kw.get('define_ret', None) and isinstance(is_success, str):
self.define_with_comment(kw['define_name'], value, cmt, quote=kw.get('quote', 1))
else:
self.define_cond(kw['define_name'], value, cmt)
if 'define_name' in kw:
define_or_stuff()
if is_success and 'uselib_store' in kw:
from waflib.Tools import ccroot
# 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:
lk = k.lower()
if k == 'INCLUDES': lk = 'includes'
if k == 'DEFKEYS': lk = 'defines'
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'], val)
return is_success
@waflib.Configure.conf
def define_with_comment(conf, define, value, comment=None, quote=True):
if comment is None:
return conf.define(define, value, quote)
assert define and isinstance(define, str)
comment_tbl = conf.env[DEFINE_COMMENTS] or {}
comment_tbl[define] = comment
conf.env[DEFINE_COMMENTS] = comment_tbl
return conf.define(define, value, quote)
@waflib.Configure.conf
def undefine_with_comment(conf, define, comment=None):
if comment is None:
return conf.undefine(define)
comment_tbl = conf.env[DEFINE_COMMENTS] or {}
comment_tbl[define] = comment
conf.env[DEFINE_COMMENTS] = comment_tbl
conf.undefine(define)
@waflib.Configure.conf
def get_comment(self, key):
assert key and isinstance(key, str)
if key in self.env[DEFINE_COMMENTS]:
return self.env[DEFINE_COMMENTS][key]
return None
@waflib.Configure.conf
def define_cond(self, name, value, comment):
"""Conditionally define a name.
Formally equivalent to: if value: define(name, 1) else: undefine(name)"""
if value:
self.define_with_comment(name, value, comment)
else:
self.undefine(name)
@waflib.Configure.conf
def get_config_header(self, defines=True, headers=False, define_prefix=None):
"""
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.
:param defines: write the defines values
:type defines: bool
:param headers: write the headers
:type headers: bool
:return: the contents of a ``config.h`` file
:rtype: string
"""
tpl = self.env["CONFIG_HEADER_TEMPLATE"] or "%(content)s"
lst = []
if headers:
for x in self.env[INCKEYS]:
lst.append('#include <%s>' % x)
if defines:
for x in self.env[DEFKEYS]:
cmt = self.get_comment(x)
if cmt is not None:
lst.append(cmt)
if self.is_defined(x):
val = self.get_define(x)
lst.append('#define %s %s\n' % (x, val))
else:
lst.append('/* #undef %s */\n' % x)
return tpl % {"content": "\n".join(lst)}