[Numpy-svn] r4691 - branches/build_with_scons/numpy/core

numpy-svn at scipy.org numpy-svn at scipy.org
Sun Jan 6 09:09:08 EST 2008


Author: cdavid
Date: 2008-01-06 08:09:03 -0600 (Sun, 06 Jan 2008)
New Revision: 4691

Added:
   branches/build_with_scons/numpy/core/SConstruct
   branches/build_with_scons/numpy/core/scons_support.py
   branches/build_with_scons/numpy/core/setupscons.py
Log:
Adding scons scripts + support for numpy.core (do not work yet)

Added: branches/build_with_scons/numpy/core/SConstruct
===================================================================
--- branches/build_with_scons/numpy/core/SConstruct	2008-01-06 14:08:19 UTC (rev 4690)
+++ branches/build_with_scons/numpy/core/SConstruct	2008-01-06 14:09:03 UTC (rev 4691)
@@ -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)

Added: branches/build_with_scons/numpy/core/scons_support.py
===================================================================
--- branches/build_with_scons/numpy/core/scons_support.py	2008-01-06 14:08:19 UTC (rev 4690)
+++ branches/build_with_scons/numpy/core/scons_support.py	2008-01-06 14:09:03 UTC (rev 4691)
@@ -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
+

Added: branches/build_with_scons/numpy/core/setupscons.py
===================================================================
--- branches/build_with_scons/numpy/core/setupscons.py	2008-01-06 14:08:19 UTC (rev 4690)
+++ branches/build_with_scons/numpy/core/setupscons.py	2008-01-06 14:09:03 UTC (rev 4691)
@@ -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)




More information about the Numpy-svn mailing list