xref: /petsc/setup.py (revision 908739b6f51a2f6d9b88b597d30d043b1b59d9fb)
1#!/usr/bin/env python
2
3"""
4PETSc for Python
5================
6
7Python bindings for PETSc libraries.
8"""
9
10
11## try:
12##     import setuptools
13## except ImportError:
14##     pass
15
16import sys, os
17
18# --------------------------------------------------------------------
19# Metadata
20# --------------------------------------------------------------------
21
22from conf.metadata import metadata
23
24def name():
25    return 'petsc4py'
26
27def version():
28    import re
29    fh = open(os.path.join('src', '__init__.py'))
30    try: data = fh.read()
31    finally: fh.close()
32    m = re.search(r"__version__\s*=\s*'(.*)'", data)
33    return m.groups()[0]
34
35name     = name()
36version  = version()
37
38url      = 'http://%(name)s.googlecode.com/' % vars()
39download = url + 'files/%(name)s-%(version)s.tar.gz' % vars()
40
41descr    = __doc__.strip().split('\n'); del descr[1:3]
42devstat  = ['Development Status :: 3 - Alpha']
43keywords = ['PETSc', 'MPI']
44
45metadata['name'] = name
46metadata['version'] = version
47metadata['description'] = descr.pop(0)
48metadata['long_description'] = '\n'.join(descr)
49metadata['keywords'] += keywords
50metadata['classifiers'] += devstat
51metadata['url'] = url
52metadata['download_url'] = download
53
54metadata['provides'] = ['petsc4py']
55metadata['requires'] = ['numpy']
56
57# --------------------------------------------------------------------
58# Extension modules
59# --------------------------------------------------------------------
60
61def get_ext_modules(Extension):
62    from os   import walk, path
63    from glob import glob
64    depends = []
65    for pth, dirs, files in walk('src'):
66        depends += glob(path.join(pth, '*.h'))
67        depends += glob(path.join(pth, '*.c'))
68    try:
69        import numpy
70        numpy_includes = [numpy.get_include()]
71    except ImportError:
72        numpy_includes = []
73    return [Extension('petsc4py.lib.PETSc',
74                      sources=['src/PETSc.c',
75                               'src/libpetsc4py.c',
76                               ],
77                      include_dirs=['src/include',
78                                    ] + numpy_includes,
79                      depends=depends)]
80
81# --------------------------------------------------------------------
82# Setup
83# --------------------------------------------------------------------
84
85from conf.petscconf import setup, Extension
86from conf.petscconf import config, build, build_src, build_ext
87from conf.petscconf import test, sdist
88
89def run_setup():
90    if (('distribute' in sys.modules) or
91        ('setuptools' in sys.modules)):
92        metadata['install_requires'] = ['numpy']
93        if not os.environ.get('PETSC_DIR'):
94            metadata['install_requires'].append('petsc')
95    if 'setuptools' in sys.modules:
96        metadata['zip_safe'] = False
97    setup(packages     = ['petsc4py',
98                          'petsc4py.lib',],
99          package_dir  = {'petsc4py'     : 'src',
100                          'petsc4py.lib' : 'src/lib'},
101          package_data = {'petsc4py'     : ['include/petsc4py/*.h',
102                                            'include/petsc4py/*.i',
103                                            'include/petsc4py/*.pxd',
104                                            'include/petsc4py/*.pxi',
105                                            'include/petsc4py/*.pyx',],
106                          'petsc4py.lib' : ['petsc.cfg'],},
107          ext_modules  = get_ext_modules(Extension),
108          cmdclass     = {'config'     : config,
109                          'build'      : build,
110                          'build_src'  : build_src,
111                          'build_ext'  : build_ext,
112                          'test'       : test,
113                          'sdist'      : sdist,
114                          },
115          **metadata)
116
117def chk_cython(CYTHON_VERSION_REQUIRED):
118    from distutils import log
119    from distutils.version import StrictVersion as Version
120    warn = lambda msg='': sys.stderr.write(msg+'\n')
121    #
122    cython_zip = 'cython.zip'
123    if os.path.isfile(cython_zip):
124        path = os.path.abspath(cython_zip)
125        if sys.path[0] != path:
126            sys.path.insert(0, os.path.abspath(cython_zip))
127            log.info("adding '%s' to sys.path", cython_zip)
128    #
129    try:
130        import Cython
131    except ImportError:
132        warn("*"*80)
133        warn()
134        warn(" You need to generate C source files with Cython!!")
135        warn(" Download and install Cython <http://www.cython.org>")
136        warn()
137        warn("*"*80)
138        return False
139    #
140    try:
141        CYTHON_VERSION = Cython.__version__
142    except AttributeError:
143        from Cython.Compiler.Version import version as CYTHON_VERSION
144    CYTHON_VERSION = CYTHON_VERSION.split('+', 1)[0]
145    for s in ('.alpha', 'alpha'):
146        CYTHON_VERSION = CYTHON_VERSION.replace(s, 'a')
147    for s in ('.beta',  'beta', '.rc', 'rc', '.c', 'c'):
148        CYTHON_VERSION = CYTHON_VERSION.replace(s, 'b')
149    if (CYTHON_VERSION_REQUIRED is not None and
150        Version(CYTHON_VERSION) < Version(CYTHON_VERSION_REQUIRED)):
151        warn("*"*80)
152        warn()
153        warn(" You need to install Cython %s (you have version %s)"
154             % (CYTHON_VERSION_REQUIRED, CYTHON_VERSION))
155        warn(" Download and install Cython <http://www.cython.org>")
156        warn()
157        warn("*"*80)
158        return False
159    #
160    return True
161
162def run_cython(source, depends=(), includes=(),
163               destdir_c=None, destdir_h=None, wdir=None,
164               force=False, VERSION=None):
165    from glob import glob
166    from distutils import log
167    from distutils import dep_util
168    from distutils.errors import DistutilsError
169    target = os.path.splitext(source)[0]+".c"
170    cwd = os.getcwd()
171    try:
172        if wdir: os.chdir(wdir)
173        alldeps = [source]
174        for dep in depends:
175            alldeps += glob(dep)
176        if not (force or dep_util.newer_group(alldeps, target)):
177            log.debug("skipping '%s' -> '%s' (up-to-date)",
178                      source, target)
179            return
180    finally:
181        os.chdir(cwd)
182    if not chk_cython(VERSION):
183        raise DistutilsError("requires Cython>=%s" % VERSION)
184    log.info("cythonizing '%s' -> '%s'", source, target)
185    from conf.cythonize import cythonize
186    err = cythonize(source,
187                    includes=includes,
188                    destdir_c=destdir_c,
189                    destdir_h=destdir_h,
190                    wdir=wdir)
191    if err:
192        raise DistutilsError(
193            "Cython failure: '%s' -> '%s'" % (source, target))
194
195def build_sources(cmd):
196    CYTHON_VERSION_REQUIRED = '0.13'
197    if not (os.path.isdir('.hg')  or
198            os.path.isdir('.git') or
199            cmd.force): return
200    # petsc4py.PETSc
201    source = 'petsc4py.PETSc.pyx'
202    depends = ("include/*/*.pxd",
203               "*/*.pyx",
204               "*/*.pxi",)
205    includes = ['include']
206    destdir_h = os.path.join('include', 'petsc4py')
207    run_cython(source, depends, includes,
208               destdir_c=None, destdir_h=destdir_h, wdir='src',
209               force=cmd.force, VERSION=CYTHON_VERSION_REQUIRED)
210    # libpetsc4py
211    source = os.path.join('libpetsc4py', 'libpetsc4py.pyx')
212    depends = ["include/petsc4py/*.pxd",
213               "libpetsc4py/*.pyx",
214               "libpetsc4py/*.pxi"]
215    includes = ['include']
216    run_cython(source, depends, includes,
217               destdir_c=None, destdir_h=None, wdir='src',
218               force=cmd.force, VERSION=CYTHON_VERSION_REQUIRED)
219
220build_src.run = build_sources
221
222def run_testsuite(cmd):
223    from distutils.errors import DistutilsError
224    sys.path.insert(0, 'test')
225    try:
226        from runtests import main
227    finally:
228        del sys.path[-1]
229    err = main(cmd.args or [])
230    if err:
231        raise DistutilsError("test")
232
233test.run = run_testsuite
234
235# --------------------------------------------------------------------
236
237def main():
238    run_setup()
239
240if __name__ == '__main__':
241    main()
242
243# --------------------------------------------------------------------
244