xref: /petsc/src/binding/petsc4py/setup.py (revision f8c80548c315cef92d65bf07af610a23cd3eb939)
15808f684SSatish Balay#!/usr/bin/env python
25808f684SSatish Balay# Author:  Lisandro Dalcin
35808f684SSatish Balay# Contact: dalcinl@gmail.com
45808f684SSatish Balay
55808f684SSatish Balay"""
65808f684SSatish BalayPETSc for Python
75808f684SSatish Balay"""
85808f684SSatish Balay
95808f684SSatish Balayimport sys
105808f684SSatish Balayimport os
115808f684SSatish Balayimport re
125808f684SSatish Balay
135808f684SSatish Balaytry:
145808f684SSatish Balay    import setuptools
155808f684SSatish Balayexcept ImportError:
165808f684SSatish Balay    setuptools = None
175808f684SSatish Balay
185808f684SSatish Balaypyver = sys.version_info[:2]
195808f684SSatish Balayif pyver < (2, 6) or (3, 0) <= pyver < (3, 2):
205808f684SSatish Balay    raise RuntimeError("Python version 2.6, 2.7 or >= 3.2 required")
215808f684SSatish Balayif pyver == (2, 6) or pyver == (3, 2):
225808f684SSatish Balay    sys.stderr.write(
235808f684SSatish Balay        "WARNING: Python %d.%d is not supported.\n" % pyver)
245808f684SSatish Balay
255808f684SSatish Balay# --------------------------------------------------------------------
265808f684SSatish Balay# Metadata
275808f684SSatish Balay# --------------------------------------------------------------------
285808f684SSatish Balay
295808f684SSatish Balaytopdir = os.path.abspath(os.path.dirname(__file__))
30a9c71d45SLisandro Dalcinsys.path.insert(0, topdir)
315808f684SSatish Balay
325808f684SSatish Balayfrom conf.metadata import metadata
335808f684SSatish Balay
345808f684SSatish Balaydef name():
355808f684SSatish Balay    return 'petsc4py'
365808f684SSatish Balay
375808f684SSatish Balaydef version():
385808f684SSatish Balay    with open(os.path.join(topdir, 'src', '__init__.py')) as f:
395808f684SSatish Balay        m = re.search(r"__version__\s*=\s*'(.*)'", f.read())
405808f684SSatish Balay        return m.groups()[0]
415808f684SSatish Balay
425808f684SSatish Balaydef description():
435808f684SSatish Balay    with open(os.path.join(topdir, 'DESCRIPTION.rst')) as f:
445808f684SSatish Balay        return f.read()
455808f684SSatish Balay
465808f684SSatish Balayname     = name()
475808f684SSatish Balayversion  = version()
485808f684SSatish Balay
49eaf87d4bSBarry Smithurl      = 'https://gitlab.com/petsc/petsc'
505808f684SSatish Balaypypiroot = 'https://pypi.io/packages/source/%s/%s/' % (name[0], name)
515808f684SSatish Balaydownload = pypiroot + '%(name)s-%(version)s.tar.gz' % vars()
525808f684SSatish Balay
535808f684SSatish Balaydevstat  = ['Development Status :: 5 - Production/Stable']
545808f684SSatish Balaykeywords = ['PETSc', 'MPI']
555808f684SSatish Balay
565808f684SSatish Balaymetadata['name'] = name
575808f684SSatish Balaymetadata['version'] = version
585808f684SSatish Balaymetadata['description'] = __doc__.strip()
595808f684SSatish Balaymetadata['long_description'] = description()
605808f684SSatish Balaymetadata['keywords'] += keywords
615808f684SSatish Balaymetadata['classifiers'] += devstat
625808f684SSatish Balaymetadata['url'] = url
635808f684SSatish Balaymetadata['download_url'] = download
645808f684SSatish Balay
655808f684SSatish Balaymetadata['provides'] = ['petsc4py']
665808f684SSatish Balaymetadata['requires'] = ['numpy']
675808f684SSatish Balay
685808f684SSatish Balay# --------------------------------------------------------------------
695808f684SSatish Balay# Extension modules
705808f684SSatish Balay# --------------------------------------------------------------------
715808f684SSatish Balay
725808f684SSatish Balaydef get_ext_modules(Extension):
738885bf16SLisandro Dalcin    from os import walk
745808f684SSatish Balay    from glob import glob
758885bf16SLisandro Dalcin    from os.path import join
768885bf16SLisandro Dalcin    glob_join = lambda *args: glob(join(*args))
775808f684SSatish Balay    depends = []
785808f684SSatish Balay    for pth, dirs, files in walk('src'):
798885bf16SLisandro Dalcin        depends += glob_join(pth, '*.h')
808885bf16SLisandro Dalcin        depends += glob_join(pth, '*.c')
818885bf16SLisandro Dalcin    if 'PETSC_DIR' in os.environ:
828885bf16SLisandro Dalcin        pd = os.environ['PETSC_DIR']
838885bf16SLisandro Dalcin        pa = os.environ.get('PETSC_ARCH', '')
848885bf16SLisandro Dalcin        depends += glob_join(pd, 'include', '*.h')
858885bf16SLisandro Dalcin        depends += glob_join(pd, 'include', 'petsc', 'private', '*.h')
868885bf16SLisandro Dalcin        depends += glob_join(pd, pa, 'include', 'petscconf.h')
870f51ee0fSAlexei Colin    numpy_include = os.environ.get('NUMPY_INCLUDE')
880f51ee0fSAlexei Colin    if numpy_include is not None:
890f51ee0fSAlexei Colin        numpy_includes = [numpy_include]
900f51ee0fSAlexei Colin    else:
915808f684SSatish Balay        try:
925808f684SSatish Balay            import numpy
935808f684SSatish Balay            numpy_includes = [numpy.get_include()]
945808f684SSatish Balay        except ImportError:
955808f684SSatish Balay            numpy_includes = []
965808f684SSatish Balay    return [Extension('petsc4py.lib.PETSc',
975808f684SSatish Balay                      sources=['src/PETSc.c',
985808f684SSatish Balay                               'src/libpetsc4py.c',
995808f684SSatish Balay                               ],
1005808f684SSatish Balay                      include_dirs=['src/include',
1015808f684SSatish Balay                                    ] + numpy_includes,
1025808f684SSatish Balay                      depends=depends)]
1035808f684SSatish Balay
1045808f684SSatish Balay# --------------------------------------------------------------------
1055808f684SSatish Balay# Setup
1065808f684SSatish Balay# --------------------------------------------------------------------
1075808f684SSatish Balay
1085808f684SSatish Balayfrom conf.petscconf import setup, Extension
1095808f684SSatish Balayfrom conf.petscconf import config, build, build_src, build_ext, install
1105808f684SSatish Balayfrom conf.petscconf import clean, test, sdist
1115808f684SSatish Balay
112a9c71d45SLisandro DalcinCYTHON = '0.24'
1135808f684SSatish Balay
114*f8c80548SLisandro Dalcindef get_release():
115*f8c80548SLisandro Dalcin    release = 1
116*f8c80548SLisandro Dalcin    if topdir.endswith(os.path.join(os.path.sep, 'src', 'binding', name)):
117*f8c80548SLisandro Dalcin        topname = name.replace('4py', '')
118*f8c80548SLisandro Dalcin        rootdir = os.path.abspath(os.path.join(topdir, *[os.path.pardir]*3))
119*f8c80548SLisandro Dalcin        version_h = os.path.join(rootdir, 'include', '%sversion.h' % topname)
120*f8c80548SLisandro Dalcin        release_macro = '%s_VERSION_RELEASE' % topname.upper()
121*f8c80548SLisandro Dalcin        version_re = re.compile(r"#define\s+%s\s+([-]*\d+)" % release_macro)
122*f8c80548SLisandro Dalcin        if os.path.exists(version_h) and os.path.isfile(version_h):
123*f8c80548SLisandro Dalcin            with open(version_h, 'r') as f:
124*f8c80548SLisandro Dalcin                release = int(version_re.search(f.read()).groups()[0])
125*f8c80548SLisandro Dalcin    return bool(release)
126*f8c80548SLisandro Dalcin
127*f8c80548SLisandro Dalcindef requires(pkgname, major, minor, release=True):
128*f8c80548SLisandro Dalcin    minor = minor + int(not release)
129*f8c80548SLisandro Dalcin    devel = '' if release else '.dev0'
130*f8c80548SLisandro Dalcin    vmin = "%s.%s%s" % (major, minor, devel)
131*f8c80548SLisandro Dalcin    vmax = "%s.%s" % (major, minor + 1)
132*f8c80548SLisandro Dalcin    return "%s>=%s,<%s" % (pkgname, vmin, vmax)
133*f8c80548SLisandro Dalcin
1345808f684SSatish Balaydef run_setup():
1355808f684SSatish Balay    setup_args = metadata.copy()
136*f8c80548SLisandro Dalcin    vstr = setup_args['version'].split('.')[:2]
137*f8c80548SLisandro Dalcin    x, y = tuple(map(int, vstr))
138*f8c80548SLisandro Dalcin    release = get_release()
139*f8c80548SLisandro Dalcin    if not release:
140*f8c80548SLisandro Dalcin        setup_args['version'] = "%d.%d.0.dev0" %(x, y+1)
1415808f684SSatish Balay    if setuptools:
1425808f684SSatish Balay        setup_args['zip_safe'] = False
1435808f684SSatish Balay        setup_args['install_requires'] = ['numpy']
1445808f684SSatish Balay        PETSC_DIR = os.environ.get('PETSC_DIR')
1455808f684SSatish Balay        if not (PETSC_DIR and os.path.isdir(PETSC_DIR)):
146*f8c80548SLisandro Dalcin            petsc = requires('petsc', x, y, release)
147*f8c80548SLisandro Dalcin            setup_args['install_requires'] += [petsc]
1485808f684SSatish Balay    if setuptools:
1495808f684SSatish Balay        src = os.path.join('src', 'petsc4py.PETSc.c')
1505808f684SSatish Balay        has_src = os.path.exists(os.path.join(topdir, src))
1515808f684SSatish Balay        has_git = os.path.isdir(os.path.join(topdir, '.git'))
1525808f684SSatish Balay        has_hg  = os.path.isdir(os.path.join(topdir, '.hg'))
1533594a89dSLisandro Dalcin        suffix = os.path.join('src', 'binding', 'petsc4py')
1543594a89dSLisandro Dalcin        in_petsc = topdir.endswith(os.path.sep + suffix)
1553594a89dSLisandro Dalcin        if not has_src or has_git or has_hg or in_petsc:
1565808f684SSatish Balay            setup_args['setup_requires'] = ['Cython>='+CYTHON]
1575808f684SSatish Balay    #
1585808f684SSatish Balay    setup(packages     = ['petsc4py',
1595808f684SSatish Balay                          'petsc4py.lib',],
1605808f684SSatish Balay          package_dir  = {'petsc4py'     : 'src',
1615808f684SSatish Balay                          'petsc4py.lib' : 'src/lib'},
1625808f684SSatish Balay          package_data = {'petsc4py'     : ['include/petsc4py/*.h',
1635808f684SSatish Balay                                            'include/petsc4py/*.i',
1645808f684SSatish Balay                                            'include/petsc4py/*.pxd',
1655808f684SSatish Balay                                            'include/petsc4py/*.pxi',
1665808f684SSatish Balay                                            'include/petsc4py/*.pyx',
1675808f684SSatish Balay                                            'PETSc.pxd',],
1685808f684SSatish Balay                          'petsc4py.lib' : ['petsc.cfg'],},
1695808f684SSatish Balay          ext_modules  = get_ext_modules(Extension),
1705808f684SSatish Balay          cmdclass     = {'config'     : config,
1715808f684SSatish Balay                          'build'      : build,
1725808f684SSatish Balay                          'build_src'  : build_src,
1735808f684SSatish Balay                          'build_ext'  : build_ext,
1745808f684SSatish Balay                          'install'    : install,
1755808f684SSatish Balay                          'clean'      : clean,
1765808f684SSatish Balay                          'test'       : test,
1775808f684SSatish Balay                          'sdist'      : sdist,
1785808f684SSatish Balay                          },
1795808f684SSatish Balay          **setup_args)
1805808f684SSatish Balay
1815808f684SSatish Balaydef chk_cython(VERSION):
1825808f684SSatish Balay    from distutils import log
1835808f684SSatish Balay    from distutils.version import LooseVersion
1845808f684SSatish Balay    from distutils.version import StrictVersion
1855808f684SSatish Balay    warn = lambda msg='': sys.stderr.write(msg+'\n')
1865808f684SSatish Balay    #
1875808f684SSatish Balay    try:
1885808f684SSatish Balay        import Cython
1895808f684SSatish Balay    except ImportError:
1905808f684SSatish Balay        warn("*"*80)
1915808f684SSatish Balay        warn()
1925808f684SSatish Balay        warn(" You need to generate C source files with Cython!!")
1935808f684SSatish Balay        warn(" Download and install Cython <http://www.cython.org>")
1945808f684SSatish Balay        warn()
1955808f684SSatish Balay        warn("*"*80)
1965808f684SSatish Balay        return False
1975808f684SSatish Balay    #
1985808f684SSatish Balay    try:
1995808f684SSatish Balay        CYTHON_VERSION = Cython.__version__
2005808f684SSatish Balay    except AttributeError:
2015808f684SSatish Balay        from Cython.Compiler.Version import version as CYTHON_VERSION
2025808f684SSatish Balay    REQUIRED = VERSION
2035808f684SSatish Balay    m = re.match(r"(\d+\.\d+(?:\.\d+)?).*", CYTHON_VERSION)
2045808f684SSatish Balay    if m:
2055808f684SSatish Balay        Version = StrictVersion
2065808f684SSatish Balay        AVAILABLE = m.groups()[0]
2075808f684SSatish Balay    else:
2085808f684SSatish Balay        Version = LooseVersion
2095808f684SSatish Balay        AVAILABLE = CYTHON_VERSION
2105808f684SSatish Balay    if (REQUIRED is not None and
2115808f684SSatish Balay        Version(AVAILABLE) < Version(REQUIRED)):
2125808f684SSatish Balay        warn("*"*80)
2135808f684SSatish Balay        warn()
2145808f684SSatish Balay        warn(" You need to install Cython %s (you have version %s)"
2155808f684SSatish Balay             % (REQUIRED, CYTHON_VERSION))
2165808f684SSatish Balay        warn(" Download and install Cython <http://www.cython.org>")
2175808f684SSatish Balay        warn()
2185808f684SSatish Balay        warn("*"*80)
2195808f684SSatish Balay        return False
2205808f684SSatish Balay    #
2215808f684SSatish Balay    return True
2225808f684SSatish Balay
223a9c71d45SLisandro Dalcindef run_cython(source, target=None,
224a9c71d45SLisandro Dalcin               depends=(), includes=(),
2255808f684SSatish Balay               destdir_c=None, destdir_h=None,
2265808f684SSatish Balay               wdir=None, force=False, VERSION=None):
2275808f684SSatish Balay    from glob import glob
2285808f684SSatish Balay    from distutils import log
2295808f684SSatish Balay    from distutils import dep_util
2305808f684SSatish Balay    from distutils.errors import DistutilsError
231a9c71d45SLisandro Dalcin    if target is None:
2325808f684SSatish Balay        target = os.path.splitext(source)[0]+'.c'
2335808f684SSatish Balay    cwd = os.getcwd()
2345808f684SSatish Balay    try:
2355808f684SSatish Balay        if wdir: os.chdir(wdir)
2365808f684SSatish Balay        alldeps = [source]
2375808f684SSatish Balay        for dep in depends:
2385808f684SSatish Balay            alldeps += glob(dep)
2395808f684SSatish Balay        if not (force or dep_util.newer_group(alldeps, target)):
2405808f684SSatish Balay            log.debug("skipping '%s' -> '%s' (up-to-date)",
2415808f684SSatish Balay                      source, target)
2425808f684SSatish Balay            return
2435808f684SSatish Balay    finally:
2445808f684SSatish Balay        os.chdir(cwd)
2455808f684SSatish Balay    if not chk_cython(VERSION):
2465808f684SSatish Balay        raise DistutilsError("requires Cython>=%s" % VERSION)
2475808f684SSatish Balay    log.info("cythonizing '%s' -> '%s'", source, target)
2485808f684SSatish Balay    from conf.cythonize import cythonize
249a9c71d45SLisandro Dalcin    err = cythonize(source, target,
2505808f684SSatish Balay                    includes=includes,
2515808f684SSatish Balay                    destdir_c=destdir_c,
2525808f684SSatish Balay                    destdir_h=destdir_h,
2535808f684SSatish Balay                    wdir=wdir)
2545808f684SSatish Balay    if err:
2555808f684SSatish Balay        raise DistutilsError(
2565808f684SSatish Balay            "Cython failure: '%s' -> '%s'" % (source, target))
2575808f684SSatish Balay
2585808f684SSatish Balaydef build_sources(cmd):
2595808f684SSatish Balay    from os.path import exists, isdir, join
260ccd2fb5eSBarry Smith
2615808f684SSatish Balay    # petsc4py.PETSc
2625808f684SSatish Balay    source = 'petsc4py.PETSc.pyx'
263a9c71d45SLisandro Dalcin    target = 'petsc4py.PETSc.c'
264ccd2fb5eSBarry Smith    depends = ['include/*/*.pxd',
2655808f684SSatish Balay               'PETSc/*.pyx',
266ccd2fb5eSBarry Smith               'PETSc/*.pxi']
2675808f684SSatish Balay    includes = ['include']
2685808f684SSatish Balay    destdir_h = os.path.join('include', 'petsc4py')
269a9c71d45SLisandro Dalcin    run_cython(source, target,
270a9c71d45SLisandro Dalcin               depends=depends, includes=includes,
2715808f684SSatish Balay               destdir_c=None, destdir_h=destdir_h, wdir='src',
2725808f684SSatish Balay               force=cmd.force, VERSION=CYTHON)
2735808f684SSatish Balay    # libpetsc4py
2745808f684SSatish Balay    source = os.path.join('libpetsc4py', 'libpetsc4py.pyx')
2755808f684SSatish Balay    depends = ['include/petsc4py/*.pxd',
2765808f684SSatish Balay               'libpetsc4py/*.pyx',
2775808f684SSatish Balay               'libpetsc4py/*.pxi']
2785808f684SSatish Balay    includes = ['include']
279a9c71d45SLisandro Dalcin    run_cython(source,
280a9c71d45SLisandro Dalcin               depends=depends, includes=includes,
2815808f684SSatish Balay               destdir_c=None, destdir_h=None, wdir='src',
2825808f684SSatish Balay               force=cmd.force, VERSION=CYTHON)
2835808f684SSatish Balay
2845808f684SSatish Balaybuild_src.run = build_sources
2855808f684SSatish Balay
2865808f684SSatish Balaydef run_testsuite(cmd):
2875808f684SSatish Balay    from distutils.errors import DistutilsError
2885808f684SSatish Balay    sys.path.insert(0, 'test')
2895808f684SSatish Balay    try:
2905808f684SSatish Balay        from runtests import main
2915808f684SSatish Balay    finally:
2925808f684SSatish Balay        del sys.path[0]
2935808f684SSatish Balay    if cmd.dry_run:
2945808f684SSatish Balay        return
2955808f684SSatish Balay    args = cmd.args[:] or []
2965808f684SSatish Balay    if cmd.verbose < 1:
2975808f684SSatish Balay        args.insert(0,'-q')
2985808f684SSatish Balay    if cmd.verbose > 1:
2995808f684SSatish Balay        args.insert(0,'-v')
3005808f684SSatish Balay    err = main(args)
3015808f684SSatish Balay    if err:
3025808f684SSatish Balay        raise DistutilsError("test")
3035808f684SSatish Balay
3045808f684SSatish Balaytest.run = run_testsuite
3055808f684SSatish Balay
3065808f684SSatish Balay# --------------------------------------------------------------------
3075808f684SSatish Balay
3085808f684SSatish Balaydef main():
3095808f684SSatish Balay    run_setup()
3105808f684SSatish Balay
3115808f684SSatish Balayif __name__ == '__main__':
3125808f684SSatish Balay    main()
3135808f684SSatish Balay
3145808f684SSatish Balay# --------------------------------------------------------------------
315