diff options
author | Jarrod Millman <millman@berkeley.edu> | 2008-02-08 10:12:16 +0000 |
---|---|---|
committer | Jarrod Millman <millman@berkeley.edu> | 2008-02-08 10:12:16 +0000 |
commit | 0b7800b455b3aaf50cb83a224f283e72f1dea951 (patch) | |
tree | aab6281c88fd6bed7c74df03562c197d934edd83 | |
parent | 964727a2c475a7e48e262efc52b51345f51f2522 (diff) | |
parent | fb3f711f1a1eafb2895a84a80f88814d7fb9a465 (diff) | |
download | numpy-0b7800b455b3aaf50cb83a224f283e72f1dea951.tar.gz |
merging David Cournapeau's build_with_scons branch, which adds scons support to numpy.distutils and modifies the configuration of numpy/core
35 files changed, 1852 insertions, 81 deletions
diff --git a/numpy/core/SConstruct b/numpy/core/SConstruct new file mode 100644 index 000000000..209d642c7 --- /dev/null +++ b/numpy/core/SConstruct @@ -0,0 +1,292 @@ +# Last Change: Wed Jan 23 08: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 import write_info + +from scons_support import CheckBrokenMathlib, define_no_smp, \ + check_mlib, check_mlibs, is_npy_no_signal + +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 +#======================= +config = env.NumpyConfigure(custom_tests = {'CheckBrokenMathlib' : CheckBrokenMathlib, + 'CheckCBLAS' : CheckCBLAS}, config_h = pjoin(env['build_dir'], 'config.h')) + +# numpyconfig_sym will keep the values of some configuration variables, the one +# needed for the public numpy API. + +# Convention: list of tuples (definition, value). value: +# - 0: #undef definition +# - 1: #define definition +# - string: #define definition value +numpyconfig_sym = [] + +#--------------- +# Checking Types +#--------------- +def check_type(type, include = None): + st = config.CheckTypeSize(type, includes = include) + type = type.replace(' ', '_') + if st: + numpyconfig_sym.append(('SIZEOF_%s' % type.upper(), '%d' % st)) + else: + numpyconfig_sym.append(('SIZEOF_%s' % type.upper(), 0)) + +for type in ('short', 'int', 'long', 'float', 'double', 'long double'): + check_type(type) + +for type in ('Py_intptr_t',): + check_type(type, include = "#include <Python.h>\n") + +# We check declaration AND type because that's how distutils does it. +if config.CheckDeclaration('PY_LONG_LONG', includes = '#include <Python.h>\n'): + st = config.CheckTypeSize('PY_LONG_LONG', includes = '#include <Python.h>\n') + assert not st == 0 + numpyconfig_sym.append(('DEFINE_NPY_SIZEOF_LONGLONG', '#define NPY_SIZEOF_LONGLONG %d' % st)) + numpyconfig_sym.append(('DEFINE_NPY_SIZEOF_PY_LONG_LONG', '#define NPY_SIZEOF_PY_LONG_LONG %d' % st)) +else: + numpyconfig_sym.append(('DEFINE_NPY_SIZEOF_LONGLONG', '')) + numpyconfig_sym.append(('DEFINE_NPY_SIZEOF_PY_LONG_LONG', '')) + +if not config.CheckDeclaration('CHAR_BIT', includes= '#include <Python.h>\n'): + raise RuntimeError("Config wo CHAR_BIT is not supported with scons: please contact the maintainer (cdavid)") + +#---------------------- +# Checking signal stuff +#---------------------- +if is_npy_no_signal(): + numpyconfig_sym.append(('DEFINE_NPY_NO_SIGNAL', '#define NPY_NO_SIGNAL\n')) + config.Define('__NPY_PRIVATE_NO_SIGNAL', comment = "define to 1 to disable SMP support ") +else: + numpyconfig_sym.append(('DEFINE_NPY_NO_SIGNAL', '')) + +#--------------------- +# Checking SMP option +#--------------------- +if define_no_smp(): + nosmp = 1 +else: + nosmp = 0 +numpyconfig_sym.append(('NPY_NO_SMP', nosmp)) + +#---------------------- +# Checking the mathlib +#---------------------- +mlibs = [[], ['m'], ['cpml']] +mathlib = os.environ.get('MATHLIB') +if mathlib: + mlibs.insert(0, mathlib) + +mlib = check_mlibs(config, mlibs) + +# XXX: this is ugly: mathlib has nothing to do in a public header file +numpyconfig_sym.append(('MATHLIB', ','.join(mlib))) + +#---------------------------------- +# Checking the math funcs available +#---------------------------------- +# Function to check: +mfuncs = ('expl', 'expf', 'log1p', 'expm1', 'asinh', 'atanhf', 'atanhl', + 'isnan', 'isinf', 'rint') + +# Set value to 1 for each defined function (in math lib) +mfuncs_defined = dict([(f, 0) for f in mfuncs]) + +# TODO: checklib vs checkfunc ? +def check_func(f): + """Check that f is available in mlib, and add the symbol appropriately. """ + st = config.CheckDeclaration(f, language = 'C', includes = "#include <math.h>") + if st: + st = config.CheckFunc(f, language = 'C') + if st: + mfuncs_defined[f] = 1 + else: + mfuncs_defined[f] = 0 + +for f in mfuncs: + check_func(f) + +if mfuncs_defined['expl'] == 1: + config.Define('HAVE_LONGDOUBLE_FUNCS', + comment = 'Define to 1 if long double funcs are available') +if mfuncs_defined['expf'] == 1: + config.Define('HAVE_FLOAT_FUNCS', + comment = 'Define to 1 if long double funcs are available') +if mfuncs_defined['asinh'] == 1: + config.Define('HAVE_INVERSE_HYPERBOLIC', + comment = 'Define to 1 if inverse hyperbolic funcs are available') +if mfuncs_defined['atanhf'] == 1: + config.Define('HAVE_INVERSE_HYPERBOLIC_FLOAT', + comment = 'Define to 1 if inverse hyperbolic float funcs are available') +if mfuncs_defined['atanhl'] == 1: + config.Define('HAVE_INVERSE_HYPERBOLIC_LONGDOUBLE', + comment = 'Define to 1 if inverse hyperbolic long double funcs are available') + +#------------------------------------------------------- +# Define the function PyOS_ascii_strod if not available +#------------------------------------------------------- +if not config.CheckDeclaration('PyOS_ascii_strtod', + includes = "#include <Python.h>"): + if config.CheckFunc('strtod'): + config.Define('PyOS_ascii_strtod', 'strtod', + "Define to a function to use as a replacement for "\ + "PyOS_ascii_strtod if not available in python header") + +#------------------------------------ +# DISTUTILS Hack on AMD64 on windows +#------------------------------------ +# 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': + distutils_use_sdk = 1 + config.Define('DISTUTILS_USE_SDK', distutils_use_sdk, + "define to 1 to disable SMP support ") + +#-------------- +# 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 numpyconfig_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'] = numpyconfig_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) + +env.Append(BUILDERS = {'GenerateMultiarrayApi' : array_api_gen_bld, + 'GenerateUfuncApi' : ufunc_api_gen_bld, + 'GenerateFromTemplate' : template_bld, + 'GenerateUmath' : umath_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 + +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/code_generators/__init__.py b/numpy/core/code_generators/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/numpy/core/code_generators/__init__.py diff --git a/numpy/core/code_generators/generate_array_api.py b/numpy/core/code_generators/generate_array_api.py index c6f73c33f..94ab37fa3 100644 --- a/numpy/core/code_generators/generate_array_api.py +++ b/numpy/core/code_generators/generate_array_api.py @@ -1,9 +1,6 @@ import os import genapi -OBJECT_API_ORDER = 'array_api_order.txt' -MULTIARRAY_API_ORDER = 'multiarray_api_order.txt' - types = ['Generic','Number','Integer','SignedInteger','UnsignedInteger', 'Inexact', 'Floating', 'ComplexFloating', 'Flexible', 'Character', @@ -122,22 +119,30 @@ void *PyArray_API[] = { """ def generate_api(output_dir, force=False): - header_file = os.path.join(output_dir, '__multiarray_api.h') - c_file = os.path.join(output_dir,'__multiarray_api.c') - doc_file = os.path.join(output_dir, 'multiarray_api.txt') - - targets = (header_file, c_file, doc_file) - if (not force - and not genapi.should_rebuild(targets, - [OBJECT_API_ORDER, - MULTIARRAY_API_ORDER, - __file__])): + basename = 'multiarray_api' + + h_file = os.path.join(output_dir, '__%s.h' % basename) + c_file = os.path.join(output_dir, '__%s.c' % basename) + d_file = os.path.join(output_dir, '%s.txt' % basename) + targets = (h_file, c_file, d_file) + sources = ['array_api_order.txt', 'multiarray_api_order.txt'] + + if (not force and not genapi.should_rebuild(targets, sources + [__file__])): return targets + else: + do_generate_api(targets, sources) + + return targets + +def do_generate_api(targets, sources): + header_file = targets[0] + c_file = targets[1] + doc_file = targets[2] objectapi_list = genapi.get_api_functions('OBJECT_API', - OBJECT_API_ORDER) + sources[0]) multiapi_list = genapi.get_api_functions('MULTIARRAY_API', - MULTIARRAY_API_ORDER) + sources[1]) # API fixes for __arrayobject_api.h fixed = 10 diff --git a/numpy/core/code_generators/generate_ufunc_api.py b/numpy/core/code_generators/generate_ufunc_api.py index 96bb47cae..fa858b207 100644 --- a/numpy/core/code_generators/generate_ufunc_api.py +++ b/numpy/core/code_generators/generate_ufunc_api.py @@ -1,8 +1,6 @@ import os import genapi -UFUNC_API_ORDER = 'ufunc_api_order.txt' - h_template = r""" #ifdef _UMATHMODULE @@ -72,17 +70,28 @@ void *PyUFunc_API[] = { """ def generate_api(output_dir, force=False): - header_file = os.path.join(output_dir, '__ufunc_api.h') - c_file = os.path.join(output_dir, '__ufunc_api.c') - doc_file = os.path.join(output_dir, 'ufunc_api.txt') - - targets = (header_file, c_file, doc_file) - if (not force - and not genapi.should_rebuild(targets, - [UFUNC_API_ORDER, __file__])): + basename = 'ufunc_api' + + h_file = os.path.join(output_dir, '__%s.h' % basename) + c_file = os.path.join(output_dir, '__%s.c' % basename) + d_file = os.path.join(output_dir, '%s.txt' % basename) + targets = (h_file, c_file, d_file) + + sources = ['ufunc_api_order.txt'] + + if (not force and not genapi.should_rebuild(targets, sources + [__file__])): return targets + else: + do_generate_api(targets, sources) + + return targets + +def do_generate_api(targets, sources): + header_file = targets[0] + c_file = targets[1] + doc_file = targets[2] - ufunc_api_list = genapi.get_api_functions('UFUNC_API', UFUNC_API_ORDER) + ufunc_api_list = genapi.get_api_functions('UFUNC_API', sources[0]) # API fixes for __arrayobject_api.h diff --git a/numpy/core/include/numpy/ndarrayobject.h b/numpy/core/include/numpy/ndarrayobject.h index 62986a9eb..3b1376cd3 100644 --- a/numpy/core/include/numpy/ndarrayobject.h +++ b/numpy/core/include/numpy/ndarrayobject.h @@ -13,7 +13,14 @@ extern "C" CONFUSE_EMACS everything when you're typing */ #endif /* This is auto-generated by the installer */ -#include "config.h" +#include "numpyconfig.h" + +/* Only use thread if configured in config and python supports it */ +#if defined WITH_THREAD && !NPY_NO_SMP + #define NPY_ALLOW_THREADS 1 +#else + #define NPY_ALLOW_THREADS 0 +#endif /* There are several places in the code where an array of dimensions is * allocated statically. This is the size of that static allocation. @@ -80,7 +87,8 @@ typedef unsigned char npy_bool; #define NPY_FALSE 0 #define NPY_TRUE 1 -#if SIZEOF_LONG_DOUBLE==SIZEOF_DOUBLE + +#if NPY_SIZEOF_LONGDOUBLE == NPY_SIZEOF_DOUBLE typedef double npy_longdouble; #define NPY_LONGDOUBLE_FMT "g" #else @@ -279,22 +287,15 @@ typedef enum { #define NPY_MAX_ULONG ULONG_MAX -#define NPY_SIZEOF_LONG SIZEOF_LONG -#define NPY_SIZEOF_INT SIZEOF_INT -#define NPY_SIZEOF_SHORT SIZEOF_SHORT -#define NPY_SIZEOF_FLOAT SIZEOF_FLOAT -#define NPY_SIZEOF_DOUBLE SIZEOF_DOUBLE -#define NPY_SIZEOF_LONGDOUBLE SIZEOF_LONG_DOUBLE -#define NPY_SIZEOF_LONGLONG SIZEOF_LONG_LONG #define NPY_BITSOF_BOOL (sizeof(npy_bool)*CHAR_BIT) #define NPY_BITSOF_CHAR CHAR_BIT -#define NPY_BITSOF_SHORT (SIZEOF_SHORT*CHAR_BIT) -#define NPY_BITSOF_INT (SIZEOF_INT*CHAR_BIT) -#define NPY_BITSOF_LONG (SIZEOF_LONG*CHAR_BIT) -#define NPY_BITSOF_LONGLONG (NPY_SIZEOF_LONGLONG*CHAR_BIT) -#define NPY_BITSOF_FLOAT (SIZEOF_FLOAT*CHAR_BIT) -#define NPY_BITSOF_DOUBLE (SIZEOF_DOUBLE*CHAR_BIT) -#define NPY_BITSOF_LONGDOUBLE (NPY_SIZEOF_LONGDOUBLE*CHAR_BIT) +#define NPY_BITSOF_SHORT (NPY_SIZEOF_SHORT * CHAR_BIT) +#define NPY_BITSOF_INT (NPY_SIZEOF_INT * CHAR_BIT) +#define NPY_BITSOF_LONG (NPY_SIZEOF_LONG * CHAR_BIT) +#define NPY_BITSOF_LONGLONG (NPY_SIZEOF_LONGLONG * CHAR_BIT) +#define NPY_BITSOF_FLOAT (NPY_SIZEOF_FLOAT * CHAR_BIT) +#define NPY_BITSOF_DOUBLE (NPY_SIZEOF_DOUBLE * CHAR_BIT) +#define NPY_BITSOF_LONGDOUBLE (NPY_SIZEOF_LONGDOUBLE * CHAR_BIT) #if NPY_BITSOF_LONG == 8 #define NPY_INT8 NPY_LONG @@ -918,8 +919,8 @@ typedef enum { * platform. Py_intptr_t, Py_uintptr_t are defined in pyport.h. */ typedef Py_intptr_t npy_intp; typedef Py_uintptr_t npy_uintp; -#define NPY_SIZEOF_INTP SIZEOF_PY_INTPTR_T -#define NPY_SIZEOF_UINTP SIZEOF_PY_INTPTR_T +#define NPY_SIZEOF_INTP NPY_SIZEOF_PY_INTPTR_T +#define NPY_SIZEOF_UINTP NPY_SIZEOF_PY_INTPTR_T #ifdef constchar #undef constchar @@ -940,7 +941,7 @@ typedef Py_uintptr_t npy_uintp; #define constchar char #endif -#if SIZEOF_PY_INTPTR_T == SIZEOF_INT +#if NPY_SIZEOF_PY_INTPTR_T == NPY_SIZEOF_INT #define NPY_INTP NPY_INT #define NPY_UINTP NPY_UINT #define PyIntpArrType_Type PyIntArrType_Type @@ -949,7 +950,7 @@ typedef Py_uintptr_t npy_uintp; #define NPY_MIN_INTP NPY_MIN_INT #define NPY_MAX_UINTP NPY_MAX_UINT #define NPY_INTP_FMT "d" -#elif SIZEOF_PY_INTPTR_T == SIZEOF_LONG +#elif NPY_SIZEOF_PY_INTPTR_T == NPY_SIZEOF_LONG #define NPY_INTP NPY_LONG #define NPY_UINTP NPY_ULONG #define PyIntpArrType_Type PyLongArrType_Type @@ -958,7 +959,7 @@ typedef Py_uintptr_t npy_uintp; #define NPY_MIN_INTP MIN_LONG #define NPY_MAX_UINTP NPY_MAX_ULONG #define NPY_INTP_FMT "ld" -#elif defined(PY_LONG_LONG) && (SIZEOF_PY_INTPTR_T == SIZEOF_LONG_LONG) +#elif defined(PY_LONG_LONG) && (NPY_SIZEOF_PY_INTPTR_T == NPY_SIZEOF_LONGLONG) #define NPY_INTP NPY_LONGLONG #define NPY_UINTP NPY_ULONGLONG #define PyIntpArrType_Type PyLongLongArrType_Type @@ -1894,7 +1895,7 @@ typedef struct { #define PyArray_REFCOUNT(obj) (((PyObject *)(obj))->ob_refcnt) #define NPY_REFCOUNT PyArray_REFCOUNT -#define NPY_MAX_ELSIZE (2*SIZEOF_LONGDOUBLE) +#define NPY_MAX_ELSIZE (2 * NPY_SIZEOF_LONGDOUBLE) #define PyArray_ContiguousFromAny(op, type, min_depth, max_depth) \ PyArray_FromAny(op, PyArray_DescrFromType(type), min_depth, \ diff --git a/numpy/core/include/numpy/numpyconfig.h.in b/numpy/core/include/numpy/numpyconfig.h.in new file mode 100644 index 000000000..929dc720d --- /dev/null +++ b/numpy/core/include/numpy/numpyconfig.h.in @@ -0,0 +1,16 @@ +#define NPY_SIZEOF_SHORT @SIZEOF_SHORT@ +#define NPY_SIZEOF_INT @SIZEOF_INT@ +#define NPY_SIZEOF_LONG @SIZEOF_LONG@ +#define NPY_SIZEOF_FLOAT @SIZEOF_FLOAT@ +#define NPY_SIZEOF_DOUBLE @SIZEOF_DOUBLE@ +#define NPY_SIZEOF_LONGDOUBLE @SIZEOF_LONG_DOUBLE@ +#define NPY_SIZEOF_PY_INTPTR_T @SIZEOF_PY_INTPTR_T@ + +@DEFINE_NPY_NO_SIGNAL@ +#define NPY_NO_SMP @NPY_NO_SMP@ + +/* XXX: this has really nothing to do in a config file... */ +#define NPY_MATHLIB @MATHLIB@ + +@DEFINE_NPY_SIZEOF_LONGLONG@ +@DEFINE_NPY_SIZEOF_PY_LONG_LONG@ diff --git a/numpy/core/scons_support.py b/numpy/core/scons_support.py new file mode 100644 index 000000000..2c08d648f --- /dev/null +++ b/numpy/core/scons_support.py @@ -0,0 +1,183 @@ +#! Last Change: Tue Jan 08 10:00 PM 2008 J + +"""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 +import SCons + +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) + +#----------------------------------------- +# 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 check_mlib(config, mlib): + """Return 1 if mlib is available and usable by numpy, 0 otherwise. + + mlib can be a string (one library), or a list of libraries.""" + # Check the libraries in mlib are linkable + if len(mlib) > 0: + # XXX: put an autoadd argument to 0 here and add an autoadd argument to + # CheckBroekenMathlib (otherwise we may add bogus libraries, the ones + # which do not path the CheckBrokenMathlib test). + st = config.CheckLib(mlib) + if not st: + return 0 + # Check the mlib is usable by numpy + return config.CheckBrokenMathlib(mlib) + +def check_mlibs(config, mlibs): + for mlib in mlibs: + if check_mlib(config, mlib): + return mlib + + # No mlib was found. + raise SCons.Errors.UserError("No usable mathlib was found: chose another "\ + "one using the MATHLIB env variable, eg "\ + "'MATHLIB=m python setup.py build'") + + +def is_npy_no_signal(): + """Return True if the NPY_NO_SIGNAL symbol must be defined in configuration + header.""" + return sys.platform == 'win32' + +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/setup.py b/numpy/core/setup.py index a8fd46911..869b6926f 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -18,6 +18,36 @@ FUNCTIONS_TO_CHECK = [ ('rint', 'HAVE_RINT'), ] +def is_npy_no_signal(): + """Return True if the NPY_NO_SIGNAL symbol must be defined in configuration + header.""" + return sys.platform == 'win32' + +def is_npy_no_smp(): + """Return True if the NPY_NO_SMP symbol must be defined in public + header (when SMP support cannot be reliably enabled).""" + # 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 + 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 @@ -53,28 +83,7 @@ def configuration(parent_package='',top_path=None): raise SystemError,"Failed to test configuration. "\ "See previous error messages for more information." - # 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 - if nosmp: moredefs = [('NPY_ALLOW_THREADS', '0')] - else: moredefs = [] + moredefs = [] # mathlibs = [] tc = testcode_mathlib() @@ -102,8 +111,8 @@ def configuration(parent_package='',top_path=None): if check_func(func_name): moredefs.append(defsymbol) - if sys.platform == 'win32': - moredefs.append('NPY_NO_SIGNAL') + if is_npy_no_signal(): + moredefs.append('__NPY_PRIVATE_NO_SIGNAL') if sys.platform=='win32' or os.name=='nt': from distutils.msvccompiler import get_build_architecture @@ -123,8 +132,6 @@ def configuration(parent_package='',top_path=None): target_f.write('#define %s\n' % (d)) else: target_f.write('#define %s %s\n' % (d[0],d[1])) - if not nosmp: # default is to use WITH_THREAD - target_f.write('#ifdef WITH_THREAD\n#define NPY_ALLOW_THREADS 1\n#else\n#define NPY_ALLOW_THREADS 0\n#endif\n') target_f.close() print 'File:',target target_f = open(target) @@ -151,6 +158,39 @@ def configuration(parent_package='',top_path=None): config.add_data_files((header_dir,target)) return target + def generate_numpyconfig_h(ext, build_dir): + """Depends on config.h: generate_config_h has to be called before !""" + target = join(build_dir,'numpyconfig.h') + if newer(__file__,target): + config_cmd = config.get_config_cmd() + log.info('Generating %s',target) + testcode = generate_numpyconfig_code(target) + + from distutils import sysconfig + python_include = sysconfig.get_python_inc() + python_h = join(python_include, 'Python.h') + if not os.path.isfile(python_h): + raise SystemError,\ + "Non-existing %s. Perhaps you need to install"\ + " python-dev|python-devel." % (python_h) + + config.numpy_include_dirs + result = config_cmd.try_run(testcode, + include_dirs = [python_include] + \ + config.numpy_include_dirs, + library_dirs = default_lib_dirs) + + if not result: + raise SystemError,"Failed to generate numpy configuration. "\ + "See previous error messages for more information." + + print 'File: %s' % target + target_f = open(target) + print target_f.read() + target_f.close() + print 'EOF' + return target + def generate_api_func(module_name): def generate_api(ext, build_dir): script = join(codegen_dir, module_name + '.py') @@ -205,6 +245,7 @@ def configuration(parent_package='',top_path=None): config.add_extension('multiarray', sources = [join('src','multiarraymodule.c'), generate_config_h, + generate_numpyconfig_h, generate_array_api, join('src','scalartypes.inc.src'), join('src','arraytypes.inc.src'), @@ -216,6 +257,7 @@ def configuration(parent_package='',top_path=None): config.add_extension('umath', sources = [generate_config_h, + generate_numpyconfig_h, join('src','umathmodule.c.src'), generate_umath_c, generate_ufunc_api, @@ -231,6 +273,7 @@ def configuration(parent_package='',top_path=None): config.add_extension('_sort', sources=[join('src','_sortmodule.c.src'), generate_config_h, + generate_numpyconfig_h, generate_array_api, ], ) @@ -238,6 +281,7 @@ def configuration(parent_package='',top_path=None): config.add_extension('scalarmath', sources=[join('src','scalarmathmodule.c.src'), generate_config_h, + generate_numpyconfig_h, generate_array_api, generate_ufunc_api], ) @@ -342,6 +386,85 @@ int main(int argc, char **argv) testcode = '\n'.join(testcode) return testcode +def generate_numpyconfig_code(target): + """Return the source code as a string of the code to generate the + numpyconfig header file.""" + if sys.platform == 'win32': + target = target.replace('\\','\\\\') + # Config symbols to prepend + prepends = [('NPY_SIZEOF_SHORT', 'SIZEOF_SHORT'), + ('NPY_SIZEOF_INT', 'SIZEOF_INT'), + ('NPY_SIZEOF_LONG', 'SIZEOF_LONG'), + ('NPY_SIZEOF_FLOAT', 'SIZEOF_FLOAT'), + ('NPY_SIZEOF_DOUBLE', 'SIZEOF_DOUBLE'), + ('NPY_SIZEOF_LONGDOUBLE', 'SIZEOF_LONG_DOUBLE'), + ('NPY_SIZEOF_PY_INTPTR_T', 'SIZEOF_PY_INTPTR_T')] + + testcode = [""" +#include <Python.h> +#include "config.h" + +int main() +{ + FILE* f; + + f = fopen("%s", "w"); + if (f == NULL) { + return -1; + } +""" % target] + + testcode.append(r""" + fprintf(f, "/*\n * This file is generated by %s. DO NOT EDIT \n */\n"); +""" % __file__) + + # Prepend NPY_ to any SIZEOF defines + testcode.extend([r' fprintf(f, "#define ' + i + r' %%d \n", %s);' % j for i, j in prepends]) + + # Conditionally define NPY_NO_SIGNAL + if is_npy_no_signal(): + testcode.append(r' fprintf(f, "\n#define NPY_NO_SIGNAL\n");') + + # Define NPY_NOSMP to 1 if explicitely requested, or if we cannot + # support thread support reliably + if is_npy_no_smp(): + testcode.append(r' fprintf(f, "#define NPY_NO_SMP 1\n");') + else: + testcode.append(r' fprintf(f, "#define NPY_NO_SMP 0\n");') + + tmpcode = r""" + #ifdef PY_LONG_LONG + fprintf(f, "\n#define %s %%d \n", %s); + fprintf(f, "#define %s %%d \n", %s); + #else + fprintf(f, "/* PY_LONG_LONG not defined */ \n"); + #endif""" + testcode.append(tmpcode % ('NPY_SIZEOF_LONGLONG', 'SIZEOF_LONG_LONG', + 'NPY_SIZEOF_PY_LONG_LONG', 'SIZEOF_PY_LONG_LONG')) + + testcode.append(r""" +#ifndef CHAR_BIT + { + unsigned char var = 2; + int i = 0; + while (var >= 2) { + var = var << 1; + i++; + } + fprintf(f,"#define CHAR_BIT %d\n", i+1); + } +#else + fprintf(f, "/* #define CHAR_BIT %d */\n", CHAR_BIT); +#endif""") + + testcode.append(""" + fclose(f); + + return 0; +} +""") + return "\n".join(testcode) + if __name__=='__main__': from numpy.distutils.core import setup setup(configuration=configuration) diff --git a/numpy/core/setupscons.py b/numpy/core/setupscons.py new file mode 100644 index 000000000..7118b1dab --- /dev/null +++ b/numpy/core/setupscons.py @@ -0,0 +1,106 @@ +import os +import sys +import glob +from os.path import join, basename + +from numpy.distutils import log + +from numscons import get_scons_build_dir + +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 = 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 = 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 = 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 = 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) diff --git a/numpy/core/src/arraytypes.inc.src b/numpy/core/src/arraytypes.inc.src index 25a149d04..dbee57c33 100644 --- a/numpy/core/src/arraytypes.inc.src +++ b/numpy/core/src/arraytypes.inc.src @@ -1,4 +1,5 @@ /* -*- c -*- */ +#include "config.h" static longlong MyPyLong_AsLongLong(PyObject *vv) diff --git a/numpy/core/src/multiarraymodule.c b/numpy/core/src/multiarraymodule.c index f08847449..40b287715 100644 --- a/numpy/core/src/multiarraymodule.c +++ b/numpy/core/src/multiarraymodule.c @@ -7269,7 +7269,7 @@ compare_chararrays(PyObject *dummy, PyObject *args, PyObject *kwds) } -#ifndef NPY_NO_SIGNAL +#ifndef __NPY_PRIVATE_NO_SIGNAL SIGJMP_BUF _NPY_SIGINT_BUF; diff --git a/numpy/core/src/umathmodule.c.src b/numpy/core/src/umathmodule.c.src index ec531e0e5..dfb50aba3 100644 --- a/numpy/core/src/umathmodule.c.src +++ b/numpy/core/src/umathmodule.c.src @@ -5,6 +5,7 @@ #define _UMATHMODULE #include "numpy/ufuncobject.h" #include "abstract.h" +#include "config.h" #include <math.h> /* A whole slew of basic math functions are provided originally diff --git a/numpy/distutils/command/build.py b/numpy/distutils/command/build.py index 1f5c08205..2f5dc31ab 100644 --- a/numpy/distutils/command/build.py +++ b/numpy/distutils/command/build.py @@ -32,3 +32,9 @@ class build(old_build): if build_scripts is None: self.build_scripts = os.path.join(self.build_base, 'scripts' + plat_specifier) + + def run(self): + # Make sure that scons based extensions are complete. + self.run_command('scons') + + old_build.run(self) diff --git a/numpy/distutils/command/config.py b/numpy/distutils/command/config.py index 41c8f4f02..ce42a36e0 100644 --- a/numpy/distutils/command/config.py +++ b/numpy/distutils/command/config.py @@ -101,6 +101,21 @@ class config(old_config): (body, headers, include_dirs, libraries, library_dirs, lang)) + def check_decl(self, symbol, + headers=None, include_dirs=None): + self._check_compiler() + body = """ +int main() +{ +#ifndef %s + (void) %s; +#endif + ; + return 0; +}""" % (symbol, symbol) + + return self.try_compile(body, headers, include_dirs) + def check_func(self, func, headers=None, include_dirs=None, libraries=None, library_dirs=None, diff --git a/numpy/distutils/command/scons.py b/numpy/distutils/command/scons.py new file mode 100644 index 000000000..43fe8178f --- /dev/null +++ b/numpy/distutils/command/scons.py @@ -0,0 +1,335 @@ +import os +import os.path +from os.path import join as pjoin, dirname as pdirname + +from distutils.errors import DistutilsPlatformError +from distutils.errors import DistutilsExecError, DistutilsSetupError + +from numpy.distutils.command.build_ext import build_ext as old_build_ext +from numpy.distutils.ccompiler import CCompiler +from numpy.distutils.fcompiler import FCompiler +from numpy.distutils.exec_command import find_executable +from numpy.distutils import log +from numpy.distutils.misc_util import get_numpy_include_dirs + +def get_scons_build_dir(): + """Return the top path where everything produced by scons will be put. + + The path is relative to the top setup.py""" + from numscons import get_scons_build_dir + return get_scons_build_dir() + +def get_scons_configres_dir(): + """Return the top path where everything produced by scons will be put. + + The path is relative to the top setup.py""" + from numscons import get_scons_configres_dir + return get_scons_configres_dir() + +def get_scons_configres_filename(): + """Return the top path where everything produced by scons will be put. + + The path is relative to the top setup.py""" + from numscons import get_scons_configres_filename + return get_scons_configres_filename() + +def get_scons_local_path(): + """This returns the full path where scons.py for scons-local is located.""" + from numscons import get_scons_path + return get_scons_path() + +def get_python_exec_invoc(): + """This returns the python executable from which this file is invocated.""" + # Do we need to take into account the PYTHONPATH, in a cross platform way, + # that is the string returned can be executed directly on supported + # platforms, and the sys.path of the executed python should be the same + # than the caller ? This may not be necessary, since os.system is said to + # take into accound os.environ. This actually also works for my way of + # using "local python", using the alias facility of bash. + import sys + return sys.executable + +def dirl_to_str(dirlist): + """Given a list of directories, returns a string where the paths are + concatenated by the path separator. + + example: ['foo/bar', 'bar/foo'] will return 'foo/bar:bar/foo'.""" + return os.pathsep.join(dirlist) + +def dist2sconscc(compiler): + """This converts the name passed to distutils to scons name convention (C + compiler). compiler should be a CCompiler instance. + + Example: + --compiler=intel -> intelc""" + compiler_type = compiler.compiler_type + if compiler_type == 'msvc': + return 'msvc' + elif compiler_type == 'intel': + return 'intelc' + elif compiler_type == 'mingw32': + return 'mingw' + else: + return compiler.compiler[0] + +def dist2sconsfc(compiler): + """This converts the name passed to distutils to scons name convention + (Fortran compiler). The argument should be a FCompiler instance. + + Example: + --fcompiler=intel -> ifort on linux, ifl on windows""" + if compiler.compiler_type == 'intel': + #raise NotImplementedError('FIXME: intel fortran compiler name ?') + return 'ifort' + elif compiler.compiler_type == 'gnu': + return 'g77' + elif compiler.compiler_type == 'gnu95': + return 'gfortran' + else: + # XXX: Just give up for now, and use generic fortran compiler + return 'fortran' + +def dist2sconscxx(compiler): + """This converts the name passed to distutils to scons name convention + (C++ compiler). The argument should be a Compiler instance.""" + if compiler.compiler_type == 'gnu': + return 'g++' + else: + return 'c++' + return compiler.compiler_cxx[0] + +def get_compiler_executable(compiler): + """For any give CCompiler instance, this gives us the name of C compiler + (the actual executable). + + NOTE: does NOT work with FCompiler instances.""" + # Geez, why does distutils has no common way to get the compiler name... + if compiler.compiler_type == 'msvc': + # this is harcoded in distutils... A bit cleaner way would be to + # initialize the compiler instance and then get compiler.cc, but this + # may be costly: we really just want a string. + # XXX: we need to initialize the compiler anyway, so do not use + # hardcoded string + #compiler.initialize() + #print compiler.cc + return 'cl.exe' + else: + return compiler.compiler[0] + +def get_f77_compiler_executable(compiler): + """For any give FCompiler instance, this gives us the name of F77 compiler + (the actual executable).""" + return compiler.compiler_f77[0] + +def get_cxxcompiler_executable(compiler): + """For any give CCompiler instance, this gives us the name of CXX compiler + (the actual executable). + + NOTE: does NOT work with FCompiler instances.""" + # Geez, why does distutils has no common way to get the compiler name... + if compiler.compiler_type == 'msvc': + # this is harcoded in distutils... A bit cleaner way would be to + # initialize the compiler instance and then get compiler.cc, but this + # may be costly: we really just want a string. + # XXX: we need to initialize the compiler anyway, so do not use + # hardcoded string + #compiler.initialize() + #print compiler.cc + return 'cl.exe' + else: + return compiler.compiler_cxx[0] + +def get_tool_path(compiler): + """Given a distutils.ccompiler.CCompiler class, returns the path of the + toolset related to C compilation.""" + fullpath_exec = find_executable(get_compiler_executable(compiler)) + if fullpath_exec: + fullpath = pdirname(fullpath_exec) + else: + raise DistutilsSetupError("Could not find compiler executable info for scons") + return fullpath + +def get_f77_tool_path(compiler): + """Given a distutils.ccompiler.FCompiler class, returns the path of the + toolset related to F77 compilation.""" + fullpath_exec = find_executable(get_f77_compiler_executable(compiler)) + if fullpath_exec: + fullpath = pdirname(fullpath_exec) + else: + raise DistutilsSetupError("Could not find F77 compiler executable "\ + "info for scons") + return fullpath + +def get_cxx_tool_path(compiler): + """Given a distutils.ccompiler.CCompiler class, returns the path of the + toolset related to C compilation.""" + fullpath_exec = find_executable(get_cxxcompiler_executable(compiler)) + if fullpath_exec: + fullpath = pdirname(fullpath_exec) + else: + raise DistutilsSetupError("Could not find compiler executable info for scons") + return fullpath + +def protect_path(path): + """Convert path (given as a string) to something the shell will have no + problem to understand (space, etc... problems).""" + # XXX: to this correctly, this is totally bogus for now (does not check for + # already quoted path, for example). + return '"' + path + '"' + +class scons(old_build_ext): + # XXX: add an option to the scons command for configuration (auto/force/cache). + description = "Scons builder" + user_options = old_build_ext.user_options + \ + [('jobs=', None, + "specify number of worker threads when executing scons"), + ('scons-tool-path=', None, 'specify additional path '\ + '(absolute) to look for scons tools'), + ('silent=', None, 'specify whether scons output should be silent '\ + '(1), super silent (2) or not (0, default)')] + + def initialize_options(self): + old_build_ext.initialize_options(self) + self.jobs = None + self.silent = 0 + self.scons_tool_path = '' + # If true, we bypass distutils to find the c compiler altogether. This + # is to be used in desperate cases (like incompatible visual studio + # version). + self._bypass_distutils_cc = False + self.scons_compiler = None + self.scons_compiler_path = None + self.scons_fcompiler = None + + def finalize_options(self): + old_build_ext.finalize_options(self) + if self.distribution.has_scons_scripts(): + self.sconscripts = self.distribution.get_scons_scripts() + self.pre_hooks = self.distribution.get_scons_pre_hooks() + self.post_hooks = self.distribution.get_scons_post_hooks() + self.pkg_names = self.distribution.get_scons_parent_names() + else: + self.sconscripts = [] + self.pre_hooks = [] + self.post_hooks = [] + self.pkg_names = [] + + # Try to get the same compiler than the ones used by distutils: this is + # non trivial because distutils and scons have totally different + # conventions on this one (distutils uses PATH from user's environment, + # whereas scons uses standard locations). The way we do it is once we + # got the c compiler used, we use numpy.distutils function to get the + # full path, and add the path to the env['PATH'] variable in env + # instance (this is done in numpy.distutils.scons module). + + # XXX: The logic to bypass distutils is ... not so logic. + compiler_type = self.compiler + if compiler_type == 'msvc': + self._bypass_distutils_cc = True + from numpy.distutils.ccompiler import new_compiler + try: + distutils_compiler = new_compiler(compiler=compiler_type, + verbose=self.verbose, + dry_run=self.dry_run, + force=self.force) + distutils_compiler.customize(self.distribution) + # This initialization seems necessary, sometimes, for find_executable to work... + if hasattr(distutils_compiler, 'initialize'): + distutils_compiler.initialize() + self.scons_compiler = dist2sconscc(distutils_compiler) + self.scons_compiler_path = protect_path(get_tool_path(distutils_compiler)) + except DistutilsPlatformError, e: + if not self._bypass_distutils_cc: + raise e + else: + self.scons_compiler = compiler_type + + # We do the same for the fortran compiler ... + fcompiler_type = self.fcompiler + from numpy.distutils.fcompiler import new_fcompiler + self.fcompiler = new_fcompiler(compiler = fcompiler_type, + verbose = self.verbose, + dry_run = self.dry_run, + force = self.force) + if self.fcompiler is not None: + self.fcompiler.customize(self.distribution) + + # And the C++ compiler + cxxcompiler = new_compiler(compiler = compiler_type, + verbose = self.verbose, + dry_run = self.dry_run, + force = self.force) + if cxxcompiler is not None: + cxxcompiler.customize(self.distribution, need_cxx = 1) + cxxcompiler.customize_cmd(self) + self.cxxcompiler = cxxcompiler.cxx_compiler() + #print self.cxxcompiler.compiler_cxx[0] + + def run(self): + if len(self.sconscripts) > 0: + try: + import numscons + except ImportError, e: + raise RuntimeError("importing numscons failed (error was %s), using " \ + "scons within distutils is not possible without " + "this package " % str(e)) + else: + # nothing to do, just leave it here. + return + # XXX: when a scons script is missing, scons only prints warnings, and + # does not return a failure (status is 0). We have to detect this from + # distutils (this cannot work for recursive scons builds...) + + # XXX: passing everything at command line may cause some trouble where + # there is a size limitation ? What is the standard solution in thise + # case ? + + scons_exec = get_python_exec_invoc() + scons_exec += ' ' + protect_path(pjoin(get_scons_local_path(), 'scons.py')) + + for sconscript, pre_hook, post_hook, pkg_name in zip(self.sconscripts, + self.pre_hooks, self.post_hooks, + self.pkg_names): + if pre_hook: + pre_hook() + + cmd = [scons_exec, "-f", sconscript, '-I.'] + if self.jobs: + cmd.append(" --jobs=%d" % int(self.jobs)) + cmd.append('scons_tool_path="%s"' % self.scons_tool_path) + cmd.append('src_dir="%s"' % pdirname(sconscript)) + cmd.append('pkg_name="%s"' % pkg_name) + #cmd.append('distutils_libdir=%s' % protect_path(pjoin(self.build_lib, + # pdirname(sconscript)))) + cmd.append('distutils_libdir=%s' % protect_path(pjoin(self.build_lib))) + + if not self._bypass_distutils_cc: + cmd.append('cc_opt=%s' % self.scons_compiler) + cmd.append('cc_opt_path=%s' % self.scons_compiler_path) + else: + cmd.append('cc_opt=%s' % self.scons_compiler) + + + if self.fcompiler: + cmd.append('f77_opt=%s' % dist2sconsfc(self.fcompiler)) + cmd.append('f77_opt_path=%s' % protect_path(get_f77_tool_path(self.fcompiler))) + + if self.cxxcompiler: + cmd.append('cxx_opt=%s' % dist2sconscxx(self.cxxcompiler)) + cmd.append('cxx_opt_path=%s' % protect_path(get_cxx_tool_path(self.cxxcompiler))) + + cmd.append('include_bootstrap=%s' % dirl_to_str(get_numpy_include_dirs())) + if self.silent: + if int(self.silent) == 1: + cmd.append('-Q') + elif int(self.silent) == 2: + cmd.append('-s') + cmdstr = ' '.join(cmd) + log.info("Executing scons command: %s ", cmdstr) + st = os.system(cmdstr) + if st: + print "status is %d" % st + raise DistutilsExecError("Error while executing scons command "\ + "%s (see above)" % cmdstr) + if post_hook: + post_hook() diff --git a/numpy/distutils/core.py b/numpy/distutils/core.py index 19e1b33a3..842f6fbc3 100644 --- a/numpy/distutils/core.py +++ b/numpy/distutils/core.py @@ -21,9 +21,10 @@ import distutils.core import distutils.dist from numpy.distutils.extension import Extension +from numpy.distutils.numpy_distribution import NumpyDistribution from numpy.distutils.command import config, config_compiler, \ build, build_py, build_ext, build_clib, build_src, build_scripts, \ - sdist, install_data, install_headers, install, bdist_rpm + sdist, install_data, install_headers, install, bdist_rpm, scons from numpy.distutils.misc_util import get_data_files, is_sequence, is_string numpy_cmdclass = {'build': build.build, @@ -36,6 +37,7 @@ numpy_cmdclass = {'build': build.build, 'build_py': build_py.build_py, 'build_clib': build_clib.build_clib, 'sdist': sdist.sdist, + 'scons': scons.scons, 'install_data': install_data.install_data, 'install_headers': install_headers.install_headers, 'install': install.install, @@ -95,9 +97,10 @@ def get_distribution(always=False): # class is local to a function in setuptools.command.easy_install if dist is not None and \ 'DistributionWithoutHelpCommands' in repr(dist): + raise NotImplementedError("setuptools not supported yet for numpy.scons branch") dist = None if always and dist is None: - dist = distutils.dist.Distribution() + dist = NumpyDistribution() return dist def _exit_interactive_session(_cache=[]): @@ -175,6 +178,9 @@ def setup(**attr): and 'headers' not in new_attr: new_attr['headers'] = [] + # Use our custom NumpyDistribution class instead of distutils' one + new_attr['distclass'] = NumpyDistribution + return old_setup(**new_attr) def _check_append_library(libraries, item): diff --git a/numpy/distutils/misc_util.py b/numpy/distutils/misc_util.py index 79fdd46ec..a698ae415 100644 --- a/numpy/distutils/misc_util.py +++ b/numpy/distutils/misc_util.py @@ -112,11 +112,11 @@ def njoin(*path): return minrelpath(joined) def get_mathlibs(path=None): - """Return the MATHLIB line from config.h + """Return the MATHLIB line from numpyconfig.h """ if path is None: path = os.path.join(get_numpy_include_dirs()[0], 'numpy') - config_file = os.path.join(path,'config.h') + config_file = os.path.join(path,'numpyconfig.h') fid = open(config_file) mathlibs = [] s = '#define MATHLIB' @@ -574,7 +574,7 @@ def get_frame(level=0): class Configuration(object): _list_keys = ['packages', 'ext_modules', 'data_files', 'include_dirs', - 'libraries', 'headers', 'scripts', 'py_modules'] + 'libraries', 'headers', 'scripts', 'py_modules', 'scons_data'] _dict_keys = ['package_dir'] _extra_keys = ['name', 'version'] @@ -586,6 +586,7 @@ class Configuration(object): top_path=None, package_path=None, caller_level=1, + setup_name='setup.py', **attrs): """Construct configuration instance of a package. @@ -674,6 +675,8 @@ class Configuration(object): if caller_instance.options['delegate_options_to_subpackages']: self.set_options(**caller_instance.options) + self.setup_name = setup_name + def todict(self): """Return configuration distionary suitable for passing to distutils.core.setup() function. @@ -795,7 +798,7 @@ class Configuration(object): else: subpackage_path = njoin([subpackage_path] + l[:-1]) subpackage_path = self.paths([subpackage_path])[0] - setup_py = njoin(subpackage_path, 'setup.py') + setup_py = njoin(subpackage_path, self.setup_name) if not self.options['ignore_setup_xxx_py']: if not os.path.isfile(setup_py): setup_py = njoin(subpackage_path, @@ -1165,6 +1168,55 @@ class Configuration(object): self.warn('distutils distribution has been initialized,'\ ' it may be too late to add a library '+ name) + def add_sconscript(self, sconscript, subpackage_path=None, + standalone = False, pre_hook = None, + post_hook = None, source_files = None): + """Add a sconscript to configuration. + + pre_hook and post hook should be sequences of callable, which will be + use before and after executing scons. """ + if standalone: + parent_name = None + else: + parent_name = self.name + + dist = self.get_distribution() + # Convert the sconscript name to a relative filename (relative from top + # setup.py's directory) + fullsconsname = self.paths(sconscript)[0] + + # XXX: Think about a way to automatically register source files from + # scons... + full_source_files = [] + if source_files: + full_source_files.extend([self.paths(i)[0] for i in source_files]) + + if dist is not None: + dist.scons_data.append((fullsconsname, + pre_hook, + post_hook, + full_source_files, + parent_name)) + self.warn('distutils distribution has been initialized,'\ + ' it may be too late to add a subpackage '+ subpackage_name) + # XXX: we add a fake extension, to correctly initialize some + # options in distutils command. + dist.add_extension('', sources = []) + else: + self.scons_data.append((fullsconsname, + pre_hook, + post_hook, + full_source_files, + parent_name)) + # XXX: we add a fake extension, to correctly initialize some + # options in distutils command. + self.add_extension('', sources = []) + + def add_configres(self): + from numscons import get_scons_configres_dir, get_scons_configres_filename + file = os.path.join(get_scons_configres_dir(), self.local_path, + get_scons_configres_filename()) + def add_scripts(self,*files): """Add scripts to configuration. """ @@ -1394,6 +1446,12 @@ class Configuration(object): """ self.py_modules.append((self.name,name,generate_config_py)) + def scons_make_config_py(self, name = '__config__'): + """Generate package __config__.py file containing system_info + information used during building the package. + """ + self.py_modules.append((self.name, name, scons_generate_config_py)) + def get_info(self,*names): """Get resources information. """ @@ -1425,6 +1483,50 @@ def get_numpy_include_dirs(): # else running numpy/core/setup.py return include_dirs +def scons_generate_config_py(target): + """generate config.py file containing system_info information + used during building the package. + + usage: + config['py_modules'].append((packagename, '__config__',generate_config_py)) + """ + from distutils.dir_util import mkpath + from numscons import get_scons_configres_dir, get_scons_configres_filename + d = {} + mkpath(os.path.dirname(target)) + f = open(target, 'w') + f.write('# this file is generated by %s\n' % (os.path.abspath(sys.argv[0]))) + f.write('# it contains system_info results at the time of building this package.\n') + f.write('__all__ = ["show"]\n\n') + confdir = get_scons_configres_dir() + confilename = get_scons_configres_filename() + for root, dirs, files in os.walk(confdir): + if files: + file = os.path.join(root, confilename) + assert root.startswith(confdir) + pkg_name = '.'.join(root[len(confdir)+1:].split(os.sep)) + fid = open(file, 'r') + try: + cnt = fid.read() + d[pkg_name] = eval(cnt) + finally: + fid.close() + # d is a dictionary whose keys are package names, and values the + # corresponding configuration. Each configuration is itself a dictionary + # (lib : libinfo) + f.write('_config = %s\n' % d) + f.write(r''' +def show(): + for pkg, config in _config.items(): + print "package %s configuration:" % pkg + for lib, libc in config.items(): + print ' %s' % lib + for line in libc.split('\n'): + print '\t%s' % line + ''') + f.close() + return target + ######################### def default_config_dict(name = None, parent_name = None, local_path=None): diff --git a/numpy/distutils/numpy_distribution.py b/numpy/distutils/numpy_distribution.py new file mode 100644 index 000000000..681b8b316 --- /dev/null +++ b/numpy/distutils/numpy_distribution.py @@ -0,0 +1,28 @@ +# XXX: Handle setuptools ? +from distutils.core import Distribution + +# This class is used because we add new files (sconscripts, and so on) with the +# scons command +class NumpyDistribution(Distribution): + def __init__(self, attrs = None): + # A list of (sconscripts, pre_hook, post_hook, src, parent_names) + self.scons_data = [] + Distribution.__init__(self, attrs) + + def has_scons_scripts(self): + return bool(self.scons_data) + + def get_scons_scripts(self): + return [i[0] for i in self.scons_data] + + def get_scons_pre_hooks(self): + return [i[1] for i in self.scons_data] + + def get_scons_post_hooks(self): + return [i[2] for i in self.scons_data] + + def get_scons_sources(self): + return [i[3] for i in self.scons_data] + + def get_scons_parent_names(self): + return [i[4] for i in self.scons_data] diff --git a/numpy/distutils/setupscons.py b/numpy/distutils/setupscons.py new file mode 100644 index 000000000..b16225f41 --- /dev/null +++ b/numpy/distutils/setupscons.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('distutils',parent_package,top_path) + config.add_subpackage('command') + config.add_subpackage('fcompiler') + config.add_data_dir('tests') + config.add_data_files('site.cfg') + config.make_config_py() + return config + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/f2py/setupscons.py b/numpy/f2py/setupscons.py new file mode 100755 index 000000000..1b8693df9 --- /dev/null +++ b/numpy/f2py/setupscons.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python +""" +setup.py for installing F2PY + +Usage: + python setup.py install + +Copyright 2001-2005 Pearu Peterson all rights reserved, +Pearu Peterson <pearu@cens.ioc.ee> +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +$Revision: 1.32 $ +$Date: 2005/01/30 17:22:14 $ +Pearu Peterson +""" + +__version__ = "$Id: setup.py,v 1.32 2005/01/30 17:22:14 pearu Exp $" + +import os +import sys +from distutils.dep_util import newer +from numpy.distutils import log +from numpy.distutils.core import setup +from numpy.distutils.misc_util import Configuration + +from __version__ import version + +def configuration(parent_package='',top_path=None): + config = Configuration('f2py', parent_package, top_path) + + config.add_subpackage('lib') + + config.add_data_dir('docs') + + config.add_data_files('src/fortranobject.c', + 'src/fortranobject.h', + 'f2py.1' + ) + + config.make_svn_version_py() + + def generate_f2py_py(build_dir): + f2py_exe = 'f2py'+os.path.basename(sys.executable)[6:] + if f2py_exe[-4:]=='.exe': + f2py_exe = f2py_exe[:-4] + '.py' + if 'bdist_wininst' in sys.argv and f2py_exe[-3:] != '.py': + f2py_exe = f2py_exe + '.py' + target = os.path.join(build_dir,f2py_exe) + if newer(__file__,target): + log.info('Creating %s', target) + f = open(target,'w') + f.write('''\ +#!/usr/bin/env %s +# See http://cens.ioc.ee/projects/f2py2e/ +import os, sys +for mode in ["g3-numpy", "2e-numeric", "2e-numarray", "2e-numpy"]: + try: + i=sys.argv.index("--"+mode) + del sys.argv[i] + break + except ValueError: pass +os.environ["NO_SCIPY_IMPORT"]="f2py" +if mode=="g3-numpy": + try: + from main import main + except ImportError: + from numpy.f2py.lib.api import main +elif mode=="2e-numeric": + from f2py2e import main +elif mode=="2e-numarray": + sys.argv.append("-DNUMARRAY") + from f2py2e import main +elif mode=="2e-numpy": + from numpy.f2py import main +else: + print >> sys.stderr, "Unknown mode:",`mode` + sys.exit(1) +main() +'''%(os.path.basename(sys.executable))) + f.close() + return target + + config.add_scripts(generate_f2py_py) + + log.info('F2PY Version %s', config.get_version()) + + return config + +if __name__ == "__main__": + + config = configuration(top_path='') + version = config.get_version() + print 'F2PY Version',version + config = config.todict() + + if sys.version[:3]>='2.3': + config['download_url'] = "http://cens.ioc.ee/projects/f2py2e/2.x"\ + "/F2PY-2-latest.tar.gz" + config['classifiers'] = [ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: NumPy License', + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Programming Language :: C', + 'Programming Language :: Fortran', + 'Programming Language :: Python', + 'Topic :: Scientific/Engineering', + 'Topic :: Software Development :: Code Generators', + ] + setup(version=version, + description = "F2PY - Fortran to Python Interface Generaton", + author = "Pearu Peterson", + author_email = "pearu@cens.ioc.ee", + maintainer = "Pearu Peterson", + maintainer_email = "pearu@cens.ioc.ee", + license = "BSD", + platforms = "Unix, Windows (mingw|cygwin), Mac OSX", + long_description = """\ +The Fortran to Python Interface Generator, or F2PY for short, is a +command line tool (f2py) for generating Python C/API modules for +wrapping Fortran 77/90/95 subroutines, accessing common blocks from +Python, and calling Python functions from Fortran (call-backs). +Interfacing subroutines/data from Fortran 90/95 modules is supported.""", + url = "http://cens.ioc.ee/projects/f2py2e/", + keywords = ['Fortran','f2py'], + **config) diff --git a/numpy/fft/SConstruct b/numpy/fft/SConstruct new file mode 100644 index 000000000..2a53f6477 --- /dev/null +++ b/numpy/fft/SConstruct @@ -0,0 +1,13 @@ +# Last Change: Thu Oct 18 09:00 PM 2007 J +# vim:syntax=python +import __builtin__ +__builtin__.__NUMPY_SETUP__ = True +from numpy.distutils.misc_util import get_numpy_include_dirs +from numscons import GetNumpyEnvironment, scons_get_paths + +env = GetNumpyEnvironment(ARGUMENTS) +env.Append(CPPPATH = scons_get_paths(env['include_bootstrap'])) + +fftpack_lite = env.NumpyPythonExtension('fftpack_lite', + source = ['fftpack_litemodule.c', + 'fftpack.c']) diff --git a/numpy/fft/setupscons.py b/numpy/fft/setupscons.py new file mode 100644 index 000000000..2fe9509e8 --- /dev/null +++ b/numpy/fft/setupscons.py @@ -0,0 +1,15 @@ +def configuration(parent_package = '', top_path = None): + from numpy.distutils.misc_util import Configuration, get_numpy_include_dirs + config = Configuration('fft', parent_package, top_path) + + config.add_data_dir('tests') + + config.add_sconscript('SConstruct', + source_files = ['fftpack_litemodule.c', 'fftpack.c', + 'fftpack.h']) + + return config + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/lib/SConstruct b/numpy/lib/SConstruct new file mode 100644 index 000000000..84795da48 --- /dev/null +++ b/numpy/lib/SConstruct @@ -0,0 +1,12 @@ +# Last Change: Thu Oct 18 09:00 PM 2007 J +# vim:syntax=python +import __builtin__ +__builtin__.__NUMPY_SETUP__ = True +from numpy.distutils.misc_util import get_numpy_include_dirs +from numscons import GetNumpyEnvironment, scons_get_paths + +env = GetNumpyEnvironment(ARGUMENTS) +env.Append(CPPPATH = scons_get_paths(env['include_bootstrap'])) + +_compiled_base = env.NumpyPythonExtension('_compiled_base', + source = ['src/_compiled_base.c']) diff --git a/numpy/lib/setupscons.py b/numpy/lib/setupscons.py new file mode 100644 index 000000000..ab0c304d3 --- /dev/null +++ b/numpy/lib/setupscons.py @@ -0,0 +1,16 @@ +from os.path import join + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + + config = Configuration('lib',parent_package,top_path) + + config.add_sconscript('SConstruct', + source_files = [join('src', '_compiled_base.c')]) + config.add_data_dir('tests') + + return config + +if __name__=='__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/linalg/SConstruct b/numpy/linalg/SConstruct new file mode 100644 index 000000000..24d648ef7 --- /dev/null +++ b/numpy/linalg/SConstruct @@ -0,0 +1,33 @@ +# Last Change: Fri Nov 16 05:00 PM 2007 J +# vim:syntax=python +import os.path + +import __builtin__ +__builtin__.__NUMPY_SETUP__ = True + +from numpy.distutils.misc_util import get_numpy_include_dirs, get_mathlibs +from numscons import GetNumpyEnvironment, scons_get_paths, \ + scons_get_mathlib +from numscons import CheckF77LAPACK +from numscons import write_info + +env = GetNumpyEnvironment(ARGUMENTS) +env.Append(CPPPATH = scons_get_paths(env['include_bootstrap'])) + +config = env.NumpyConfigure(custom_tests = + {'CheckLAPACK' : CheckF77LAPACK}) + +use_lapack = config.CheckLAPACK() + +mlib = scons_get_mathlib(env) +env.AppendUnique(LIBS = mlib) + +config.Finish() +write_info(env) + +sources = ['lapack_litemodule.c'] +if not use_lapack: + sources.extend(['zlapack_lite.c', 'dlapack_lite.c', 'blas_lite.c', + 'dlamch.c', 'f2c_lite.c']) +lapack_lite = env.NumpyPythonExtension('lapack_lite', source = sources) + diff --git a/numpy/linalg/setupscons.py b/numpy/linalg/setupscons.py new file mode 100644 index 000000000..d585bcaae --- /dev/null +++ b/numpy/linalg/setupscons.py @@ -0,0 +1,20 @@ + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + from numpy.distutils.system_info import get_info + config = Configuration('linalg',parent_package,top_path) + + config.add_data_dir('tests') + + config.add_sconscript('SConstruct', + source_files = ['lapack_litemodule.c', + 'zlapack_lite.c', 'dlapack_lite.c', + 'blas_lite.c', 'dlamch.c', + 'f2c_lite.c','f2c.h'], + post_hook = config.add_configres) + + return config + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/numarray/SConstruct b/numpy/numarray/SConstruct new file mode 100644 index 000000000..aa780be87 --- /dev/null +++ b/numpy/numarray/SConstruct @@ -0,0 +1,12 @@ +# Last Change: Fri Oct 19 09:00 AM 2007 J +# vim:syntax=python +import __builtin__ +__builtin__.__NUMPY_SETUP__ = True +from numpy.distutils.misc_util import get_numpy_include_dirs +from numscons import GetNumpyEnvironment, scons_get_paths + +env = GetNumpyEnvironment(ARGUMENTS) +env.Append(CPPPATH = scons_get_paths(env['include_bootstrap'])) +env.Append(CPPPATH = env['src_dir']) + +_capi = env.NumpyPythonExtension('_capi', source = ['_capi.c']) diff --git a/numpy/numarray/setupscons.py b/numpy/numarray/setupscons.py new file mode 100644 index 000000000..37d53a8ef --- /dev/null +++ b/numpy/numarray/setupscons.py @@ -0,0 +1,14 @@ +from os.path import join + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('numarray',parent_package,top_path) + + config.add_data_files('numpy/') + config.add_sconscript('SConstruct', source_files = ['_capi.c']) + + return config + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/oldnumeric/setupscons.py b/numpy/oldnumeric/setupscons.py new file mode 100644 index 000000000..82e8a6201 --- /dev/null +++ b/numpy/oldnumeric/setupscons.py @@ -0,0 +1,8 @@ + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + return Configuration('oldnumeric',parent_package,top_path) + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/random/SConstruct b/numpy/random/SConstruct new file mode 100644 index 000000000..95957ccd7 --- /dev/null +++ b/numpy/random/SConstruct @@ -0,0 +1,50 @@ +# Last Change: Tue Nov 13 11:00 PM 2007 J +# vim:syntax=python +import os + +import __builtin__ +__builtin__.__NUMPY_SETUP__ = True + +from numpy.distutils.misc_util import get_numpy_include_dirs, get_mathlibs +from numscons import GetNumpyEnvironment, scons_get_paths, \ + scons_get_mathlib + +def CheckWincrypt(context): + from copy import deepcopy + src = """\ +/* check to see if _WIN32 is defined */ +int main(int argc, char *argv[]) +{ +#ifdef _WIN32 + return 0; +#else + return 1; +#endif +} +""" + + context.Message("Checking if using wincrypt ... ") + st = context.env.TryRun(src, '.C') + if st[0] == 0: + context.Result('No') + else: + context.Result('Yes') + return st[0] + +env = GetNumpyEnvironment(ARGUMENTS) +env.Append(CPPPATH = scons_get_paths(env['include_bootstrap'])) + +mlib = scons_get_mathlib(env) +env.AppendUnique(LIBS = mlib) + +# On windows, see if we should use Advapi32 +if os.name == 'nt': + config = env.NumpyConfigure(custom_tests = {'CheckWincrypt' : CheckWincrypt}) + if config.CheckWincrypt: + config.env.AppendUnique(LIBS = 'Advapi32') + +sources = [os.path.join('mtrand', x) for x in + ['mtrand.c', 'randomkit.c', 'initarray.c', 'distributions.c']] + +# XXX: Pyrex dependency +mtrand = env.NumpyPythonExtension('mtrand', source = sources) diff --git a/numpy/random/setupscons.py b/numpy/random/setupscons.py new file mode 100644 index 000000000..969300ff6 --- /dev/null +++ b/numpy/random/setupscons.py @@ -0,0 +1,40 @@ +import glob +from os.path import join, split + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration, get_mathlibs + config = Configuration('random',parent_package,top_path) + + source_files = [join('mtrand', i) for i in ['mtrand.c', + 'mtrand.pyx', + 'numpy.pxi', + 'randomkit.c', + 'randomkit.h', + 'Python.pxi', + 'initarray.c', + 'initarray.h', + 'distributions.c', + 'distributions.h', + ]] + config.add_sconscript('SConstruct', source_files = source_files) + config.add_data_files(('.', join('mtrand', 'randomkit.h'))) + config.add_data_dir('tests') + + return config + +def testcode_wincrypt(): + return """\ +/* check to see if _WIN32 is defined */ +int main(int argc, char *argv[]) +{ +#ifdef _WIN32 + return 0; +#else + return 1; +#endif +} +""" + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/setupscons.py b/numpy/setupscons.py new file mode 100644 index 000000000..5c235d2ad --- /dev/null +++ b/numpy/setupscons.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('numpy',parent_package,top_path, setup_name = 'setupscons.py') + config.add_subpackage('distutils') + config.add_subpackage('testing') + config.add_subpackage('f2py') + config.add_subpackage('core') + config.add_subpackage('lib') + config.add_subpackage('oldnumeric') + config.add_subpackage('numarray') + config.add_subpackage('fft') + config.add_subpackage('linalg') + config.add_subpackage('random') + config.add_data_dir('doc') + config.add_data_dir('tests') + config.scons_make_config_py() # installs __config__.py + return config + +if __name__ == '__main__': + print 'This is the wrong setup.py file to run' diff --git a/numpy/testing/setupscons.py b/numpy/testing/setupscons.py new file mode 100755 index 000000000..ad248d27f --- /dev/null +++ b/numpy/testing/setupscons.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('testing',parent_package,top_path) + return config + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(maintainer = "NumPy Developers", + maintainer_email = "numpy-dev@numpy.org", + description = "NumPy test module", + url = "http://www.numpy.org", + license = "NumPy License (BSD Style)", + configuration = configuration, + ) diff --git a/setupscons.py b/setupscons.py new file mode 100755 index 000000000..802f4f907 --- /dev/null +++ b/setupscons.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +"""NumPy: array processing for numbers, strings, records, and objects. + +NumPy is a general-purpose array-processing package designed to +efficiently manipulate large multi-dimensional arrays of arbitrary +records without sacrificing too much speed for small multi-dimensional +arrays. NumPy is built on the Numeric code base and adds features +introduced by numarray as well as an extended C-API and the ability to +create arrays of arbitrary type which also makes NumPy suitable for +interfacing with general-purpose data-base applications. + +There are also basic facilities for discrete fourier transform, +basic linear algebra and random number generation. +""" + +DOCLINES = __doc__.split("\n") + +import __builtin__ +import os +import sys + +CLASSIFIERS = """\ +Development Status :: 4 - Beta +Intended Audience :: Science/Research +Intended Audience :: Developers +License :: OSI Approved +Programming Language :: C +Programming Language :: Python +Topic :: Software Development +Topic :: Scientific/Engineering +Operating System :: Microsoft :: Windows +Operating System :: POSIX +Operating System :: Unix +Operating System :: MacOS +""" + +# BEFORE importing distutils, remove MANIFEST. distutils doesn't properly +# update it when the contents of directories change. +if os.path.exists('MANIFEST'): os.remove('MANIFEST') + +# This is a bit hackish: we are setting a global variable so that the main +# numpy __init__ can detect if it is being loaded by the setup routine, to +# avoid attempting to load components that aren't built yet. While ugly, it's +# a lot more robust than what was previously being used. +__builtin__.__NUMPY_SETUP__ = True + +# DO NOT REMOVE numpy.distutils IMPORT ! This is necessary for numpy.distutils' +# monkey patching to work. +import numpy.distutils +from distutils.errors import DistutilsError +try: + import numscons +except ImportError, e: + msg = ["You cannot build numpy with scons without the numscons package "] + msg.append("(Failure was: %s)" % e) + raise DistutilsError('\n'.join(msg)) + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + + config = Configuration(None, parent_package, top_path, setup_name = 'setupscons.py') + config.set_options(ignore_setup_xxx_py=True, + assume_default_configuration=True, + delegate_options_to_subpackages=True, + quiet=True) + + config.add_subpackage('numpy') + + config.add_data_files(('numpy','*.txt'), + ('numpy','COMPATIBILITY'), + ('numpy','site.cfg.example'), + ('numpy','setup.py')) + + config.get_version('numpy/version.py') # sets config.version + + return config + +def setup_package(): + + from numpy.distutils.core import setup + + old_path = os.getcwd() + local_path = os.path.dirname(os.path.abspath(sys.argv[0])) + os.chdir(local_path) + sys.path.insert(0,local_path) + + try: + setup( + name = 'numpy', + maintainer = "NumPy Developers", + maintainer_email = "numpy-discussion@lists.sourceforge.net", + description = DOCLINES[0], + long_description = "\n".join(DOCLINES[2:]), + url = "http://numeric.scipy.org", + download_url = "http://sourceforge.net/project/showfiles.php?group_id=1369&package_id=175103", + license = 'BSD', + classifiers=filter(None, CLASSIFIERS.split('\n')), + author = "Travis E. Oliphant, et.al.", + author_email = "oliphant@ee.byu.edu", + platforms = ["Windows", "Linux", "Solaris", "Mac OS-X", "Unix"], + configuration=configuration ) + finally: + del sys.path[0] + os.chdir(old_path) + return + +if __name__ == '__main__': + setup_package() diff --git a/test.sh b/test.sh new file mode 100644 index 000000000..46aad9cbc --- /dev/null +++ b/test.sh @@ -0,0 +1,18 @@ +# PREFIX=$PWD +# rm -rf $PREFIX/build +# rm -rf $PREFIX/tmp +# MKL=None python setupscons.py scons --jobs=4 install --prefix=$PREFIX/tmp +# (cd $PREFIX/tmp && PYTHONPATH=$PREFIX/tmp/lib/python2.5/site-packages python -c "import numpy; print numpy; numpy.test(level = 9999); numpy.show_config()") + +PREFIX=$PWD +rm -rf $PREFIX/build +rm -rf $PREFIX/tmp +python setupscons.py scons --jobs=4 install --prefix=$PREFIX/tmp +(cd $PREFIX/tmp && PYTHONPATH=$PREFIX/tmp/lib/python2.5/site-packages python -c "import numpy; print numpy; numpy.test(level = 9999); numpy.show_config()") + +# PREFIX=$PWD +# #rm -rf $PREFIX/build +# #rm -rf $PREFIX/tmp +# MKL=None python setupscons.py scons --jobs=4 --silent=2 install --prefix=$PREFIX/tmp +# (cd $PREFIX/tmp/lib/python2.5/site-packages/numpy/distutils/scons/tests/f2pyext/ && \ +# PYTHONPATH=$PREFIX/tmp/lib/python2.5/site-packages python setup.py scons) |