[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