diff options
author | David Cournapeau <cournape@gmail.com> | 2008-01-06 14:09:03 +0000 |
---|---|---|
committer | David Cournapeau <cournape@gmail.com> | 2008-01-06 14:09:03 +0000 |
commit | 6123f389746f0ff187aa4e05fa0c2c5d3e12dc58 (patch) | |
tree | 9da32e6a54135a640fa5b72a7c965d7cf9397bfa /numpy | |
parent | d57e886e51cccb06807c4e6fdaee280326b91f3c (diff) | |
download | numpy-6123f389746f0ff187aa4e05fa0c2c5d3e12dc58.tar.gz |
Adding scons scripts + support for numpy.core (do not work yet)
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/SConstruct | 272 | ||||
-rw-r--r-- | numpy/core/scons_support.py | 189 | ||||
-rw-r--r-- | numpy/core/setupscons.py | 103 |
3 files changed, 564 insertions, 0 deletions
diff --git a/numpy/core/SConstruct b/numpy/core/SConstruct new file mode 100644 index 000000000..bffdf0d5d --- /dev/null +++ b/numpy/core/SConstruct @@ -0,0 +1,272 @@ +# Last Change: Sun Jan 06 07:00 PM 2008 J +# vim:syntax=python +import os +import sys +from os.path import join as pjoin, basename as pbasename, dirname as pdirname +from copy import deepcopy + +from numscons import get_python_inc, get_pythonlib_dir +from numscons import GetNumpyEnvironment +from numscons import CheckCBLAS +from numscons.configuration import write_info + +from scons_support import CheckBrokenMathlib, define_no_smp, \ + generate_config_header, generate_config_header_emitter + +env = GetNumpyEnvironment(ARGUMENTS) +env.Append(CPPPATH = [get_python_inc()]) +if os.name == 'nt': + # NT needs the pythonlib to run any code importing Python.h, including + # simple code using only typedef and so on, so we need it for configuration + # checks + env.AppendUnique(LIBPATH = [get_pythonlib_dir()]) + +#======================= +# Starting Configuration +#======================= +# XXX: separate env for configuration +config = env.NumpyConfigure(custom_tests = {'CheckBrokenMathlib' : CheckBrokenMathlib, + 'CheckCBLAS' : CheckCBLAS}) + +# Convention: list of tuples (definition, value). value: +# - 0: #undef definition +# - 1: #define definition +# - string: #define definition value +config_sym = [] + +#--------------- +# Checking Types +#--------------- +def check_type(type, include = None): + st = config.CheckTypeSize(type, includes = include) + type = type.replace(' ', '_') + if st: + config_sym.append(('SIZEOF_%s' % type.upper(), '%d' % st)) + else: + config_sym.append(('SIZEOF_%s' % type.upper(), 0)) + +check_type('short') +check_type('int') +check_type('long') +check_type('float') +check_type('double') +check_type('long double') +check_type('Py_intptr_t', include = "#include <Python.h>\n") +check_type('PY_LONG_LONG', include = "#include <Python.h>\n") + +# TODO: check python extension can be built (in root or here ?) + +#----------------------- +# Checking configuration +#----------------------- + +#---------------------- +# Checking signal stuff +#---------------------- +# TODO + +#------------------------------------------ +# Checking the mathlib and its capabilities +#------------------------------------------ +# Function to check: +mfuncs = [('expl', 'HAVE_LONGDOUBLE_FUNCS'), + ('expf', 'HAVE_FLOAT_FUNCS'), + ('log1p', 'HAVE_LOG1P'), + ('expm1', 'HAVE_EXPM1'), + ('asinh', 'HAVE_INVERSE_HYPERBOLIC'), + ('atanhf', 'HAVE_INVERSE_HYPERBOLIC_FLOAT'), + ('atanhl', 'HAVE_INVERSE_HYPERBOLIC_LONGDOUBLE'), + ('isnan', 'HAVE_ISNAN'), + ('isinf', 'HAVE_ISINF'), + ('rint', 'HAVE_RINT'), + ] + +# TODO: checklib vs checkfunc ? +mlibs = [[], ['m'], ['cpml']] +mathlib = os.environ.get('MATHLIB') +if mathlib: + mlibs.insert(0, mathlib) +for mlib in mlibs: + st = config.CheckBrokenMathlib(mlib) + if st: + break + +if not st: + import SCons + raise SCons.Errors.UserError("No usable mathlib was found: chose another "\ + "one using the MATHLIB env variable, eg "\ + "'MATHLIB=m python setup.py build'") +# XXX: this is ugly: mathlib has nothing to do in a public header file +config_sym.append(('MATHLIB', ','.join(mlib))) + +def check_lib(f, autoadd = 0): + """Check that f is available in mlib, and add the symbol appropriately. + + f is expected to be a tuble (symbol, cpp define).""" + st = config.CheckLibWithHeader(mlib, 'math.h', language = 'C', call = '%s;' % f[0], autoadd = autoadd) + if st: + config_sym.append((f[1], 1)) + else: + config_sym.append((f[1], 0)) + +check_lib(mfuncs[0], autoadd = 1) +for f in mfuncs[1:]: + check_lib(f) + +#------------------------------------------------------- +# Define the function PyOS_ascii_strod if not available +#------------------------------------------------------- +# XXX: would be better to check for PyOS_ascii_strod instead of version +if sys.version[:3] < '2.4': + if config.CheckFunc('strtod'): + config_sym.append(('PyOS_ascii_strtod', 'strtod')) + +if define_no_smp(): + config_sym.append(('NPY_NOSMP', '1')) +else: + config_sym.append(('NPY_NOSMP', '0')) + +# XXX: this is ugly +if sys.platform=='win32' or os.name=='nt': + from distutils.msvccompiler import get_build_architecture + a = get_build_architecture() + print 'BUILD_ARCHITECTURE: %r, os.name=%r, sys.platform=%r' % (a, os.name, sys.platform) + if a == 'AMD64': + moredefs.append(('DISTUTILS_USE_SDK', 1)) + +#-------------- +# Checking Blas +#-------------- +if config.CheckCBLAS(): + build_blasdot = 1 +else: + build_blasdot = 0 + +config.Finish() +write_info(env) + +#========== +# Build +#========== + +#--------------------------------------- +# Generate the public configuration file +#--------------------------------------- +config_dict = {} +# XXX: this is ugly, make the API for config.h and numpyconfig.h similar +for key, value in config_sym: + config_dict['@%s@' % key] = str(value) +env['SUBST_DICT'] = config_dict + +include_dir = 'include/numpy' +env.SubstInFile(pjoin(env['build_dir'], 'numpyconfig.h'), + pjoin(env['src_dir'], include_dir, 'numpyconfig.h.in')) + +env['CONFIG_H_GEN'] = config_sym + +#--------------------------- +# Builder for generated code +#--------------------------- +from scons_support import do_generate_array_api, do_generate_ufunc_api, \ + generate_api_emitter,\ + generate_from_template, generate_from_template_emitter, \ + generate_umath, generate_umath_emitter + +array_api_gen_bld = Builder(action = do_generate_array_api, + emitter = generate_api_emitter) + +ufunc_api_gen_bld = Builder(action = do_generate_ufunc_api, + emitter = generate_api_emitter) + +template_bld = Builder(action = generate_from_template, + emitter = generate_from_template_emitter) + +umath_bld = Builder(action = generate_umath, + emitter = generate_umath_emitter) + +config_h_bld = Builder(action = generate_config_header, + emitter = generate_config_header_emitter) + +env.Append(BUILDERS = {'GenerateMultiarrayApi' : array_api_gen_bld, + 'GenerateUfuncApi' : ufunc_api_gen_bld, + 'GenerateFromTemplate' : template_bld, + 'GenerateUmath' : umath_bld, + 'GenerateConfigHeader' : config_h_bld}) + +#------------------------ +# Generate generated code +#------------------------ +# XXX: the use of env['build_dir'] and env['src_dir'] are really ugly. Will +# have to think about how removing them (using hierarchical scons and dir +# option ?) +from os.path import join as pjoin + +config_header = env.GenerateConfigHeader(pjoin(env['build_dir'], 'config.h'), []) + +scalartypes_src = env.GenerateFromTemplate( + pjoin(env['build_dir'], 'src', 'scalartypes'), + pjoin(env['src_dir'], 'src', 'scalartypes.inc.src')) + +arraytypes_src = env.GenerateFromTemplate( + pjoin(env['build_dir'], 'src', 'arraytypes'), + pjoin(env['src_dir'], 'src', 'arraytypes.inc.src')) + +sortmodule_src = env.GenerateFromTemplate( + pjoin(env['build_dir'], 'src', '_sortmodule'), + pjoin(env['src_dir'], 'src', '_sortmodule.c.src')) + +umathmodule_src = env.GenerateFromTemplate( + pjoin(env['build_dir'], 'src', 'umathmodule'), + pjoin(env['src_dir'], 'src', 'umathmodule.c.src')) + +scalarmathmodule_src = env.GenerateFromTemplate( + pjoin(env['build_dir'], 'src', 'scalarmathmodule'), + pjoin(env['src_dir'], 'src', 'scalarmathmodule.c.src')) + +umath = env.GenerateUmath( + pjoin(env['build_dir'], '__umath_generated'), + pjoin(env['src_dir'], 'code_generators', 'generate_umath.py')) + +multiarray_api = env.GenerateMultiarrayApi( + pjoin(env['build_dir'], 'multiarray_api'), + [ pjoin(env['src_dir'], 'code_generators', + 'array_api_order.txt'), + pjoin(env['src_dir'], 'code_generators', + 'multiarray_api_order.txt')]) + +ufunc_api = env.GenerateUfuncApi( + pjoin(env['build_dir'], 'ufunc_api'), + pjoin(env['src_dir'], 'code_generators', 'ufunc_api_order.txt')) + +env.Append(CPPPATH = [pjoin(env['src_dir'], 'include'), env['build_dir']]) + +#----------------- +# Build multiarray +#----------------- +multiarray_src = [pjoin('src', 'multiarraymodule.c')] +multiarray = env.NumpyPythonExtension('multiarray', source = multiarray_src) + +#------------------ +# Build sort module +#------------------ +sort = env.NumpyPythonExtension('_sort', source = sortmodule_src) + +#------------------- +# Build umath module +#------------------- +umathmodule = env.NumpyPythonExtension('umath', source = umathmodule_src) + +#------------------------ +# Build scalarmath module +#------------------------ +scalarmathmodule = env.NumpyPythonExtension('scalarmath', + source = scalarmathmodule_src) + +#---------------------- +# Build _dotblas module +#---------------------- +if build_blasdot: + dotblas_src = [pjoin('blasdot', i) for i in ['_dotblas.c']] + blasenv = env.Copy() + blasenv.Append(CPPPATH = pjoin(env['src_dir'], 'blasdot')) + dotblas = blasenv.NumpyPythonExtension('_dotblas', source = dotblas_src) diff --git a/numpy/core/scons_support.py b/numpy/core/scons_support.py new file mode 100644 index 000000000..3d2c4eaea --- /dev/null +++ b/numpy/core/scons_support.py @@ -0,0 +1,189 @@ +#! Last Change: Sun Jan 06 09:00 PM 2008 J + +__docstring__ = """Code to support special facilities to scons which are only +useful for numpy.core, hence not put into numpy.distutils.scons""" + +import sys +import os + +from os.path import join as pjoin, dirname as pdirname, basename as pbasename +from copy import deepcopy + +from code_generators.generate_array_api import \ + do_generate_api as nowrap_do_generate_array_api +from code_generators.generate_ufunc_api import \ + do_generate_api as nowrap_do_generate_ufunc_api + +from numscons.numdist import process_c_str as process_str +from numscons.core.utils import rsplit, isstring + +import SCons.Node + +def split_ext(string): + sp = rsplit(string, '.', 1) + if len(sp) == 1: + return (sp[0], '') + else: + return sp +#------------------------------------ +# Ufunc and multiarray API generators +#------------------------------------ +def do_generate_array_api(target, source, env): + nowrap_do_generate_array_api([str(i) for i in target], + [str(i) for i in source]) + return 0 + +def do_generate_ufunc_api(target, source, env): + nowrap_do_generate_ufunc_api([str(i) for i in target], + [str(i) for i in source]) + return 0 + +def generate_api_emitter(target, source, env): + """Returns the list of targets generated by the code generator for array + api and ufunc api.""" + base, ext = split_ext(str(target[0])) + dir = pdirname(base) + ba = pbasename(base) + h = pjoin(dir, '__' + ba + '.h') + c = pjoin(dir, '__' + ba + '.c') + txt = base + '.txt' + #print h, c, txt + t = [h, c, txt] + return (t, source) + +#------------------------- +# From template generators +#------------------------- +# XXX: this is general and can be used outside numpy.core. +def do_generate_from_template(targetfile, sourcefile, env): + t = open(targetfile, 'w') + s = open(sourcefile, 'r') + allstr = s.read() + s.close() + writestr = process_str(allstr) + t.write(writestr) + t.close() + return 0 + +def generate_from_template(target, source, env): + for t, s in zip(target, source): + do_generate_from_template(str(t), str(s), env) + +def generate_from_template_emitter(target, source, env): + base, ext = split_ext(pbasename(str(source[0]))) + t = pjoin(pdirname(str(target[0])), base) + return ([t], source) + +#---------------- +# umath generator +#---------------- +def do_generate_umath(targetfile, sourcefile, env): + t = open(targetfile, 'w') + from code_generators import generate_umath + code = generate_umath.make_code(generate_umath.defdict, generate_umath.__file__) + t.write(code) + t.close() + +def generate_umath(target, source, env): + for t, s in zip(target, source): + do_generate_umath(str(t), str(s), env) + +def generate_umath_emitter(target, source, env): + t = str(target[0]) + '.c' + return ([t], source) + +#------------------- +# Generate config.h +#------------------- +def generate_config_header(target, source, env): + t = open(str(target[0]), 'w') + if not env.has_key('CONFIG_H_GEN'): + # XXX + assert 0 == 1 + sym = env['CONFIG_H_GEN'] + def write_symbol(define, value): + if value == 1: + return "#define %s\n\n" % define + elif value == 0: + return "/* #undef %s */\n\n" % define + elif isstring(value): + return "#define %s %s\n\n" % (define, value) + else: + return "#define %s %s\n\n" % (define, ','.join(value)) + t.writelines([write_symbol(i[0], i[1]) for i in sym]) + t.write('\n') + t.close() + + print 'File: %s' % target[0] + target_f = open(str(target[0])) + print target_f.read() + target_f.close() + print 'EOF' + return 0 + +def generate_config_header_emitter(target, source, env): + """Add dependency from config list CONFIG_H_GEN to target. Returns + original target, source tuple unchanged. """ + from SCons.Script import Depends + d = deepcopy(env['CONFIG_H_GEN']) # copy it + Depends(target, SCons.Node.Python.Value(d)) + return target, source + +#----------------------------------------- +# Other functions related to configuration +#----------------------------------------- +def CheckBrokenMathlib(context, mathlib): + src = """ +/* check whether libm is broken */ +#include <math.h> +int main(int argc, char *argv[]) +{ + return exp(-720.) > 1.0; /* typically an IEEE denormal */ +} +""" + + try: + oldLIBS = deepcopy(context.env['LIBS']) + except: + oldLIBS = [] + + try: + context.Message("Checking if math lib %s is usable for numpy ... " % mathlib) + context.env.AppendUnique(LIBS = mathlib) + st = context.TryRun(src, '.c') + finally: + context.env['LIBS'] = oldLIBS + + if st[0]: + context.Result(' Yes !') + else: + context.Result(' No !') + return st[0] + +def define_no_smp(): + """Returns True if we should define NPY_NOSMP, False otherwise.""" + #-------------------------------- + # Checking SMP and thread options + #-------------------------------- + # Python 2.3 causes a segfault when + # trying to re-acquire the thread-state + # which is done in error-handling + # ufunc code. NPY_ALLOW_C_API and friends + # cause the segfault. So, we disable threading + # for now. + if sys.version[:5] < '2.4.2': + nosmp = 1 + else: + # Perhaps a fancier check is in order here. + # so that threads are only enabled if there + # are actually multiple CPUS? -- but + # threaded code can be nice even on a single + # CPU so that long-calculating code doesn't + # block. + try: + nosmp = os.environ['NPY_NOSMP'] + nosmp = 1 + except KeyError: + nosmp = 0 + return nosmp == 1 + diff --git a/numpy/core/setupscons.py b/numpy/core/setupscons.py new file mode 100644 index 000000000..5b79d2501 --- /dev/null +++ b/numpy/core/setupscons.py @@ -0,0 +1,103 @@ +import os +import sys +import glob +from os.path import join, basename +from numpy.distutils import log + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration,dot_join + from numpy.distutils.system_info import get_info, default_lib_dirs + + config = Configuration('core',parent_package,top_path) + local_dir = config.local_path + + header_dir = 'include/numpy' # this is relative to config.path_in_package + + config.add_subpackage('code_generators') + + # List of files to register to numpy.distutils + dot_blas_src = [join('blasdot', '_dotblas.c'), + join('blasdot', 'cblas.h')] + api_definition = [join('code_generators', 'array_api_order.txt'), + join('code_generators', 'multiarray_api_order.txt'), + join('code_generators', 'ufunc_api_order.txt')] + core_src = [join('src', basename(i)) for i in glob.glob(join(local_dir, + 'src', + '*.c'))] + core_src += [join('src', basename(i)) for i in glob.glob(join(local_dir, + 'src', + '*.src'))] + + source_files = dot_blas_src + api_definition + core_src + \ + [join(header_dir, 'numpyconfig.h.in')] + + # Add generated files to distutils... + def add_config_header(): + scons_build_dir = config.get_scons_build_dir() + # XXX: I really have to think about how to communicate path info + # between scons and distutils, and set the options at one single + # location. + target = join(scons_build_dir, local_dir, 'config.h') + incl_dir = os.path.dirname(target) + if incl_dir not in config.numpy_include_dirs: + config.numpy_include_dirs.append(incl_dir) + + def add_numpyconfig_header(): + scons_build_dir = config.get_scons_build_dir() + # XXX: I really have to think about how to communicate path info + # between scons and distutils, and set the options at one single + # location. + target = join(scons_build_dir, local_dir, 'numpyconfig.h') + incl_dir = os.path.dirname(target) + if incl_dir not in config.numpy_include_dirs: + config.numpy_include_dirs.append(incl_dir) + config.add_data_files((header_dir, target)) + + def add_array_api(): + scons_build_dir = config.get_scons_build_dir() + # XXX: I really have to think about how to communicate path info + # between scons and distutils, and set the options at one single + # location. + h_file = join(scons_build_dir, local_dir, '__multiarray_api.h') + t_file = join(scons_build_dir, local_dir, 'multiarray_api.txt') + config.add_data_files((header_dir, h_file), + (header_dir, t_file)) + + def add_ufunc_api(): + scons_build_dir = config.get_scons_build_dir() + # XXX: I really have to think about how to communicate path info + # between scons and distutils, and set the options at one single + # location. + h_file = join(scons_build_dir, local_dir, '__ufunc_api.h') + t_file = join(scons_build_dir, local_dir, 'ufunc_api.txt') + config.add_data_files((header_dir, h_file), + (header_dir, t_file)) + + def add_generated_files(): + add_config_header() + add_numpyconfig_header() + add_array_api() + add_ufunc_api() + config.add_configres() + + config.add_sconscript('SConstruct', + post_hook = add_generated_files, + source_files = source_files) + + config.add_data_files('include/numpy/*.h') + config.add_include_dirs('src') + + config.numpy_include_dirs.extend(config.paths('include')) + + # Don't install fenv unless we need them. + if sys.platform == 'cygwin': + config.add_data_dir('include/numpy/fenv') + + config.add_data_dir('tests') + config.make_svn_version_py() + + return config + +if __name__=='__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) |