xref: /petsc/src/binding/petsc4py/setup.py (revision 5808f68492579297331054bd8ff190489c3b8c20)
1*5808f684SSatish Balay#!/usr/bin/env python
2*5808f684SSatish Balay# Author:  Lisandro Dalcin
3*5808f684SSatish Balay# Contact: dalcinl@gmail.com
4*5808f684SSatish Balay
5*5808f684SSatish Balay"""
6*5808f684SSatish BalayPETSc for Python
7*5808f684SSatish Balay"""
8*5808f684SSatish Balay
9*5808f684SSatish Balayimport sys
10*5808f684SSatish Balayimport os
11*5808f684SSatish Balayimport re
12*5808f684SSatish Balay
13*5808f684SSatish Balaytry:
14*5808f684SSatish Balay    import setuptools
15*5808f684SSatish Balayexcept ImportError:
16*5808f684SSatish Balay    setuptools = None
17*5808f684SSatish Balay
18*5808f684SSatish Balaypyver = sys.version_info[:2]
19*5808f684SSatish Balayif pyver < (2, 6) or (3, 0) <= pyver < (3, 2):
20*5808f684SSatish Balay    raise RuntimeError("Python version 2.6, 2.7 or >= 3.2 required")
21*5808f684SSatish Balayif pyver == (2, 6) or pyver == (3, 2):
22*5808f684SSatish Balay    sys.stderr.write(
23*5808f684SSatish Balay        "WARNING: Python %d.%d is not supported.\n" % pyver)
24*5808f684SSatish Balay
25*5808f684SSatish Balay# --------------------------------------------------------------------
26*5808f684SSatish Balay# Metadata
27*5808f684SSatish Balay# --------------------------------------------------------------------
28*5808f684SSatish Balay
29*5808f684SSatish Balaytopdir = os.path.abspath(os.path.dirname(__file__))
30*5808f684SSatish Balay
31*5808f684SSatish Balayfrom conf.metadata import metadata
32*5808f684SSatish Balay
33*5808f684SSatish Balaydef name():
34*5808f684SSatish Balay    return 'petsc4py'
35*5808f684SSatish Balay
36*5808f684SSatish Balaydef version():
37*5808f684SSatish Balay    with open(os.path.join(topdir, 'src', '__init__.py')) as f:
38*5808f684SSatish Balay        m = re.search(r"__version__\s*=\s*'(.*)'", f.read())
39*5808f684SSatish Balay        return m.groups()[0]
40*5808f684SSatish Balay
41*5808f684SSatish Balaydef description():
42*5808f684SSatish Balay    with open(os.path.join(topdir, 'DESCRIPTION.rst')) as f:
43*5808f684SSatish Balay        return f.read()
44*5808f684SSatish Balay
45*5808f684SSatish Balayname     = name()
46*5808f684SSatish Balayversion  = version()
47*5808f684SSatish Balay
48*5808f684SSatish Balayurl      = 'https://gitlab.com/petsc/petsc4py'
49*5808f684SSatish Balaypypiroot = 'https://pypi.io/packages/source/%s/%s/' % (name[0], name)
50*5808f684SSatish Balaydownload = pypiroot + '%(name)s-%(version)s.tar.gz' % vars()
51*5808f684SSatish Balay
52*5808f684SSatish Balaydevstat  = ['Development Status :: 5 - Production/Stable']
53*5808f684SSatish Balaykeywords = ['PETSc', 'MPI']
54*5808f684SSatish Balay
55*5808f684SSatish Balaymetadata['name'] = name
56*5808f684SSatish Balaymetadata['version'] = version
57*5808f684SSatish Balaymetadata['description'] = __doc__.strip()
58*5808f684SSatish Balaymetadata['long_description'] = description()
59*5808f684SSatish Balaymetadata['keywords'] += keywords
60*5808f684SSatish Balaymetadata['classifiers'] += devstat
61*5808f684SSatish Balaymetadata['url'] = url
62*5808f684SSatish Balaymetadata['download_url'] = download
63*5808f684SSatish Balay
64*5808f684SSatish Balaymetadata['provides'] = ['petsc4py']
65*5808f684SSatish Balaymetadata['requires'] = ['numpy']
66*5808f684SSatish Balay
67*5808f684SSatish Balay# --------------------------------------------------------------------
68*5808f684SSatish Balay# Extension modules
69*5808f684SSatish Balay# --------------------------------------------------------------------
70*5808f684SSatish Balay
71*5808f684SSatish Balaydef get_ext_modules(Extension):
72*5808f684SSatish Balay    from os   import walk, path
73*5808f684SSatish Balay    from glob import glob
74*5808f684SSatish Balay    depends = []
75*5808f684SSatish Balay    for pth, dirs, files in walk('src'):
76*5808f684SSatish Balay        depends += glob(path.join(pth, '*.h'))
77*5808f684SSatish Balay        depends += glob(path.join(pth, '*.c'))
78*5808f684SSatish Balay    try:
79*5808f684SSatish Balay        import numpy
80*5808f684SSatish Balay        numpy_includes = [numpy.get_include()]
81*5808f684SSatish Balay    except ImportError:
82*5808f684SSatish Balay        numpy_includes = []
83*5808f684SSatish Balay    return [Extension('petsc4py.lib.PETSc',
84*5808f684SSatish Balay                      sources=['src/PETSc.c',
85*5808f684SSatish Balay                               'src/libpetsc4py.c',
86*5808f684SSatish Balay                               ],
87*5808f684SSatish Balay                      include_dirs=['src/include',
88*5808f684SSatish Balay                                    ] + numpy_includes,
89*5808f684SSatish Balay                      depends=depends)]
90*5808f684SSatish Balay
91*5808f684SSatish Balay# --------------------------------------------------------------------
92*5808f684SSatish Balay# Setup
93*5808f684SSatish Balay# --------------------------------------------------------------------
94*5808f684SSatish Balay
95*5808f684SSatish Balayfrom conf.petscconf import setup, Extension
96*5808f684SSatish Balayfrom conf.petscconf import config, build, build_src, build_ext, install
97*5808f684SSatish Balayfrom conf.petscconf import clean, test, sdist
98*5808f684SSatish Balay
99*5808f684SSatish BalayCYTHON = '0.22'
100*5808f684SSatish Balay
101*5808f684SSatish Balaydef run_setup():
102*5808f684SSatish Balay    setup_args = metadata.copy()
103*5808f684SSatish Balay    if setuptools:
104*5808f684SSatish Balay        setup_args['zip_safe'] = False
105*5808f684SSatish Balay        setup_args['install_requires'] = ['numpy']
106*5808f684SSatish Balay        PETSC_DIR = os.environ.get('PETSC_DIR')
107*5808f684SSatish Balay        if not (PETSC_DIR and os.path.isdir(PETSC_DIR)):
108*5808f684SSatish Balay            vstr = setup_args['version'].split('.')[:2]
109*5808f684SSatish Balay            x, y = int(vstr[0]), int(vstr[1])
110*5808f684SSatish Balay            PETSC = ">=%s.%s,<%s.%s" % (x, y, x, y+1)
111*5808f684SSatish Balay            setup_args['install_requires'] += ['petsc'+PETSC]
112*5808f684SSatish Balay    if setuptools:
113*5808f684SSatish Balay        src = os.path.join('src', 'petsc4py.PETSc.c')
114*5808f684SSatish Balay        has_src = os.path.exists(os.path.join(topdir, src))
115*5808f684SSatish Balay        has_git = os.path.isdir(os.path.join(topdir, '.git'))
116*5808f684SSatish Balay        has_hg  = os.path.isdir(os.path.join(topdir, '.hg'))
117*5808f684SSatish Balay        if not has_src or has_git or has_hg:
118*5808f684SSatish Balay            setup_args['setup_requires'] = ['Cython>='+CYTHON]
119*5808f684SSatish Balay    #
120*5808f684SSatish Balay    setup(packages     = ['petsc4py',
121*5808f684SSatish Balay                          'petsc4py.lib',],
122*5808f684SSatish Balay          package_dir  = {'petsc4py'     : 'src',
123*5808f684SSatish Balay                          'petsc4py.lib' : 'src/lib'},
124*5808f684SSatish Balay          package_data = {'petsc4py'     : ['include/petsc4py/*.h',
125*5808f684SSatish Balay                                            'include/petsc4py/*.i',
126*5808f684SSatish Balay                                            'include/petsc4py/*.pxd',
127*5808f684SSatish Balay                                            'include/petsc4py/*.pxi',
128*5808f684SSatish Balay                                            'include/petsc4py/*.pyx',
129*5808f684SSatish Balay                                            'PETSc.pxd',],
130*5808f684SSatish Balay                          'petsc4py.lib' : ['petsc.cfg'],},
131*5808f684SSatish Balay          ext_modules  = get_ext_modules(Extension),
132*5808f684SSatish Balay          cmdclass     = {'config'     : config,
133*5808f684SSatish Balay                          'build'      : build,
134*5808f684SSatish Balay                          'build_src'  : build_src,
135*5808f684SSatish Balay                          'build_ext'  : build_ext,
136*5808f684SSatish Balay                          'install'    : install,
137*5808f684SSatish Balay                          'clean'      : clean,
138*5808f684SSatish Balay                          'test'       : test,
139*5808f684SSatish Balay                          'sdist'      : sdist,
140*5808f684SSatish Balay                          },
141*5808f684SSatish Balay          **setup_args)
142*5808f684SSatish Balay
143*5808f684SSatish Balaydef chk_cython(VERSION):
144*5808f684SSatish Balay    from distutils import log
145*5808f684SSatish Balay    from distutils.version import LooseVersion
146*5808f684SSatish Balay    from distutils.version import StrictVersion
147*5808f684SSatish Balay    warn = lambda msg='': sys.stderr.write(msg+'\n')
148*5808f684SSatish Balay    #
149*5808f684SSatish Balay    try:
150*5808f684SSatish Balay        import Cython
151*5808f684SSatish Balay    except ImportError:
152*5808f684SSatish Balay        warn("*"*80)
153*5808f684SSatish Balay        warn()
154*5808f684SSatish Balay        warn(" You need to generate C source files with Cython!!")
155*5808f684SSatish Balay        warn(" Download and install Cython <http://www.cython.org>")
156*5808f684SSatish Balay        warn()
157*5808f684SSatish Balay        warn("*"*80)
158*5808f684SSatish Balay        return False
159*5808f684SSatish Balay    #
160*5808f684SSatish Balay    try:
161*5808f684SSatish Balay        CYTHON_VERSION = Cython.__version__
162*5808f684SSatish Balay    except AttributeError:
163*5808f684SSatish Balay        from Cython.Compiler.Version import version as CYTHON_VERSION
164*5808f684SSatish Balay    REQUIRED = VERSION
165*5808f684SSatish Balay    m = re.match(r"(\d+\.\d+(?:\.\d+)?).*", CYTHON_VERSION)
166*5808f684SSatish Balay    if m:
167*5808f684SSatish Balay        Version = StrictVersion
168*5808f684SSatish Balay        AVAILABLE = m.groups()[0]
169*5808f684SSatish Balay    else:
170*5808f684SSatish Balay        Version = LooseVersion
171*5808f684SSatish Balay        AVAILABLE = CYTHON_VERSION
172*5808f684SSatish Balay    if (REQUIRED is not None and
173*5808f684SSatish Balay        Version(AVAILABLE) < Version(REQUIRED)):
174*5808f684SSatish Balay        warn("*"*80)
175*5808f684SSatish Balay        warn()
176*5808f684SSatish Balay        warn(" You need to install Cython %s (you have version %s)"
177*5808f684SSatish Balay             % (REQUIRED, CYTHON_VERSION))
178*5808f684SSatish Balay        warn(" Download and install Cython <http://www.cython.org>")
179*5808f684SSatish Balay        warn()
180*5808f684SSatish Balay        warn("*"*80)
181*5808f684SSatish Balay        return False
182*5808f684SSatish Balay    #
183*5808f684SSatish Balay    return True
184*5808f684SSatish Balay
185*5808f684SSatish Balaydef run_cython(source, depends=(), includes=(),
186*5808f684SSatish Balay               destdir_c=None, destdir_h=None,
187*5808f684SSatish Balay               wdir=None, force=False, VERSION=None):
188*5808f684SSatish Balay    from glob import glob
189*5808f684SSatish Balay    from distutils import log
190*5808f684SSatish Balay    from distutils import dep_util
191*5808f684SSatish Balay    from distutils.errors import DistutilsError
192*5808f684SSatish Balay    target = os.path.splitext(source)[0]+'.c'
193*5808f684SSatish Balay    cwd = os.getcwd()
194*5808f684SSatish Balay    try:
195*5808f684SSatish Balay        if wdir: os.chdir(wdir)
196*5808f684SSatish Balay        alldeps = [source]
197*5808f684SSatish Balay        for dep in depends:
198*5808f684SSatish Balay            alldeps += glob(dep)
199*5808f684SSatish Balay        if not (force or dep_util.newer_group(alldeps, target)):
200*5808f684SSatish Balay            log.debug("skipping '%s' -> '%s' (up-to-date)",
201*5808f684SSatish Balay                      source, target)
202*5808f684SSatish Balay            return
203*5808f684SSatish Balay    finally:
204*5808f684SSatish Balay        os.chdir(cwd)
205*5808f684SSatish Balay    if not chk_cython(VERSION):
206*5808f684SSatish Balay        raise DistutilsError("requires Cython>=%s" % VERSION)
207*5808f684SSatish Balay    log.info("cythonizing '%s' -> '%s'", source, target)
208*5808f684SSatish Balay    from conf.cythonize import cythonize
209*5808f684SSatish Balay    err = cythonize(source,
210*5808f684SSatish Balay                    includes=includes,
211*5808f684SSatish Balay                    destdir_c=destdir_c,
212*5808f684SSatish Balay                    destdir_h=destdir_h,
213*5808f684SSatish Balay                    wdir=wdir)
214*5808f684SSatish Balay    if err:
215*5808f684SSatish Balay        raise DistutilsError(
216*5808f684SSatish Balay            "Cython failure: '%s' -> '%s'" % (source, target))
217*5808f684SSatish Balay
218*5808f684SSatish Balaydef build_sources(cmd):
219*5808f684SSatish Balay    from os.path import exists, isdir, join
220*5808f684SSatish Balay    if (exists(join('src', 'petsc4py.PETSc.c')) and
221*5808f684SSatish Balay        not (isdir('.hg') or isdir('.git')) and
222*5808f684SSatish Balay        not cmd.force): return
223*5808f684SSatish Balay    # petsc4py.PETSc
224*5808f684SSatish Balay    source = 'petsc4py.PETSc.pyx'
225*5808f684SSatish Balay    depends = ('include/*/*.pxd',
226*5808f684SSatish Balay               'PETSc/*.pyx',
227*5808f684SSatish Balay               'PETSc/*.pxi',)
228*5808f684SSatish Balay    includes = ['include']
229*5808f684SSatish Balay    destdir_h = os.path.join('include', 'petsc4py')
230*5808f684SSatish Balay    run_cython(source, depends, includes,
231*5808f684SSatish Balay               destdir_c=None, destdir_h=destdir_h, wdir='src',
232*5808f684SSatish Balay               force=cmd.force, VERSION=CYTHON)
233*5808f684SSatish Balay    # libpetsc4py
234*5808f684SSatish Balay    source = os.path.join('libpetsc4py', 'libpetsc4py.pyx')
235*5808f684SSatish Balay    depends = ['include/petsc4py/*.pxd',
236*5808f684SSatish Balay               'libpetsc4py/*.pyx',
237*5808f684SSatish Balay               'libpetsc4py/*.pxi']
238*5808f684SSatish Balay    includes = ['include']
239*5808f684SSatish Balay    run_cython(source, depends, includes,
240*5808f684SSatish Balay               destdir_c=None, destdir_h=None, wdir='src',
241*5808f684SSatish Balay               force=cmd.force, VERSION=CYTHON)
242*5808f684SSatish Balay
243*5808f684SSatish Balaybuild_src.run = build_sources
244*5808f684SSatish Balay
245*5808f684SSatish Balaydef run_testsuite(cmd):
246*5808f684SSatish Balay    from distutils.errors import DistutilsError
247*5808f684SSatish Balay    sys.path.insert(0, 'test')
248*5808f684SSatish Balay    try:
249*5808f684SSatish Balay        from runtests import main
250*5808f684SSatish Balay    finally:
251*5808f684SSatish Balay        del sys.path[0]
252*5808f684SSatish Balay    if cmd.dry_run:
253*5808f684SSatish Balay        return
254*5808f684SSatish Balay    args = cmd.args[:] or []
255*5808f684SSatish Balay    if cmd.verbose < 1:
256*5808f684SSatish Balay        args.insert(0,'-q')
257*5808f684SSatish Balay    if cmd.verbose > 1:
258*5808f684SSatish Balay        args.insert(0,'-v')
259*5808f684SSatish Balay    err = main(args)
260*5808f684SSatish Balay    if err:
261*5808f684SSatish Balay        raise DistutilsError("test")
262*5808f684SSatish Balay
263*5808f684SSatish Balaytest.run = run_testsuite
264*5808f684SSatish Balay
265*5808f684SSatish Balay# --------------------------------------------------------------------
266*5808f684SSatish Balay
267*5808f684SSatish Balaydef main():
268*5808f684SSatish Balay    run_setup()
269*5808f684SSatish Balay
270*5808f684SSatish Balayif __name__ == '__main__':
271*5808f684SSatish Balay    main()
272*5808f684SSatish Balay
273*5808f684SSatish Balay# --------------------------------------------------------------------
274