diff options
-rw-r--r-- | numpy/build_utils/__init__.py | 172 | ||||
-rw-r--r-- | numpy/core/bscript | 66 |
2 files changed, 238 insertions, 0 deletions
diff --git a/numpy/build_utils/__init__.py b/numpy/build_utils/__init__.py index 0fa3f0ff4..d25458fc6 100644 --- a/numpy/build_utils/__init__.py +++ b/numpy/build_utils/__init__.py @@ -220,3 +220,175 @@ def check_type_size(conf, type_name, expected_sizes=None, **kw): 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 post_check(self, *k, **kw): + "set the variables after a test was run successfully" + + is_success = 0 + if kw['execute']: + if kw['success'] is not None: + is_success = kw['success'] + 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 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): + """ + 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]: + if self.is_defined(x): + val = self.get_define(x) + cmt = self.get_comment(x) + if cmt is not None: + lst.append(cmt) + lst.append('#define %s %s\n' % (x, val)) + else: + lst.append('/* #undef %s */\n' % x) + return tpl % {"content": "\n".join(lst)} diff --git a/numpy/core/bscript b/numpy/core/bscript index d85f634f9..b8baafe17 100644 --- a/numpy/core/bscript +++ b/numpy/core/bscript @@ -128,6 +128,71 @@ def signal_smp_checks(conf): else: NUMPYCONFIG_SYM.append(("NPY_NO_SMP", 0)) +def check_math_runtime(conf): + header_name = "Python.h math.h" + features = "c cprogram pyext" + + mlibs = [None, "m", "cpml"] + mathlib = os.environ.get('MATHLIB') + if mathlib: + mlibs.insert(0, mathlib) + + mlib = None + for lib in mlibs: + try: + if lib is None: + kw = {} + else: + kw = {"lib": lib} + st = conf.check_functions_at_once(["exp"], uselib_store="M", **kw) + mlib = lib or [] + break + except waflib.Errors.ConfigurationError: + pass + if mlib is None: + raise waflib.Errors.ConfigurationError("No math lib found !") + + # XXX: this is ugly: mathlib has nothing to do in a public header file + NUMPYCONFIG_SYM.append(('MATHLIB', ','.join(mlib))) + + conf.check_functions_at_once(MANDATORY_FUNCS, use="M") + + mfuncs = ('expl', 'expf', 'log1p', 'expm1', 'asinh', 'atanhf', 'atanhl', + 'rint', 'trunc') + conf.check_functions_at_once(mfuncs, use="M") + + header_name = "Python.h math.h" + features = "c pyext" + for f in OPTIONAL_STDFUNCS_MAYBE: + try: + conf.check_declaration("HAVE_%s" % numpy.build_utils.sanitize_string(f), + header_name=header_name, + features=features) + OPTIONAL_STDFUNCS.remove(f) + except waflib.Errors.ConfigurationError: + pass + + conf.check_functions_at_once(OPTIONAL_STDFUNCS, + features=features, mandatory=False, use="M") + conf.check_functions_at_once(C99_FUNCS_SINGLE, + features=features, mandatory=False, use="M") + conf.check_functions_at_once(C99_FUNCS_EXTENDED, + features=features, mandatory=False, use="M") + + for f in ["isnan", "isinf", "signbit", "isfinite"]: + try: + conf.check_declaration("HAVE_DECL_%s" % f.upper(), header_name=header_name, + features=features) + NUMPYCONFIG_SYM.append(('DEFINE_NPY_HAVE_DECL_%s' % f.upper(), + '#define NPY_HAVE_DECL_%s' % f.upper())) + except waflib.Errors.ConfigurationError: + try: + conf.check_declaration(f, header_name=header_name, features=features) + NUMPYCONFIG_SYM.append(('DEFINE_NPY_HAVE_DECL_%s' % f.upper(), + '#define NPY_HAVE_DECL_%s' % f.upper())) + except waflib.Errors.ConfigurationError: + NUMPYCONFIG_SYM.append(('DEFINE_NPY_HAVE_DECL_%s' % f.upper(), '')) + @pre_configure() def configure(context): conf = context.waf_context @@ -150,6 +215,7 @@ def configure(context): type_checks(conf) signal_smp_checks(conf) + check_math_runtime(conf) conf.env["CONFIG_HEADER_TEMPLATE"] = """\ %(content)s |