xref: /petsc/src/binding/petsc4py/setup.py (revision 2149b0eadb4d0ca5e1dfee66ac7cea87b8f0b35b)
11b37a2a7SPierre Jolivet#!/usr/bin/env python3
25808f684SSatish Balay# Author:  Lisandro Dalcin
35808f684SSatish Balay# Contact: dalcinl@gmail.com
45808f684SSatish Balay
55808f684SSatish Balayimport re
6fb83dddaSLisandro Dalcinimport os
7fb83dddaSLisandro Dalcinimport sys
85808f684SSatish Balay
95808f684SSatish Balaytry:
105808f684SSatish Balay    import setuptools
115808f684SSatish Balayexcept ImportError:
125808f684SSatish Balay    setuptools = None
135808f684SSatish Balay
14f46a955bSLisandro Dalcintopdir = os.path.abspath(os.path.dirname(__file__))
15f46a955bSLisandro Dalcinsys.path.insert(0, os.path.join(topdir, 'conf'))
16f46a955bSLisandro Dalcin
175808f684SSatish Balaypyver = sys.version_info[:2]
181e83877aSSatish Balayif pyver < (2, 6) or (3, 0) <= pyver < (3, 2):
196f336411SStefano Zampini    raise RuntimeError('Python version 2.6, 2.7 or >= 3.2 required')
201e83877aSSatish Balayif pyver == (2, 6) or pyver == (3, 2):
216f336411SStefano Zampini    sys.stderr.write('WARNING: Python %d.%d is not supported.\n' % pyver)
221e83877aSSatish Balay
23f46a955bSLisandro DalcinPNAME = 'PETSc'
24f46a955bSLisandro DalcinEMAIL = 'petsc-maint@mcs.anl.gov'
25f46a955bSLisandro DalcinPLIST = [PNAME]
26fb83dddaSLisandro Dalcin
275808f684SSatish Balay# --------------------------------------------------------------------
285808f684SSatish Balay# Metadata
295808f684SSatish Balay# --------------------------------------------------------------------
305808f684SSatish Balay
316f336411SStefano Zampini
32f46a955bSLisandro Dalcindef F(string):
33f46a955bSLisandro Dalcin    return string.format(
34f46a955bSLisandro Dalcin        Name=PNAME,
35f46a955bSLisandro Dalcin        name=PNAME.lower(),
36f46a955bSLisandro Dalcin        pyname=PNAME.lower() + '4py',
37f46a955bSLisandro Dalcin    )
385808f684SSatish Balay
396f336411SStefano Zampini
40f46a955bSLisandro Dalcindef get_name():
41f46a955bSLisandro Dalcin    return F('{pyname}')
425808f684SSatish Balay
436f336411SStefano Zampini
44f46a955bSLisandro Dalcindef get_version():
45f46a955bSLisandro Dalcin    try:
46f46a955bSLisandro Dalcin        return get_version.result
47f46a955bSLisandro Dalcin    except AttributeError:
48f46a955bSLisandro Dalcin        pass
49f46a955bSLisandro Dalcin    pkg_init_py = os.path.join(F('{pyname}'), '__init__.py')
50f46a955bSLisandro Dalcin    with open(os.path.join(topdir, 'src', pkg_init_py)) as f:
515808f684SSatish Balay        m = re.search(r"__version__\s*=\s*'(.*)'", f.read())
52f46a955bSLisandro Dalcin    version = m.groups()[0]
53f46a955bSLisandro Dalcin    get_version.result = version
54f46a955bSLisandro Dalcin    return version
555808f684SSatish Balay
566f336411SStefano Zampini
575808f684SSatish Balaydef description():
58f46a955bSLisandro Dalcin    return F('{Name} for Python')
59fb83dddaSLisandro Dalcin
606f336411SStefano Zampini
61fb83dddaSLisandro Dalcindef long_description():
625808f684SSatish Balay    with open(os.path.join(topdir, 'DESCRIPTION.rst')) as f:
635808f684SSatish Balay        return f.read()
645808f684SSatish Balay
656f336411SStefano Zampini
66f46a955bSLisandro Dalcinurl = F('https://gitlab.com/{name}/{name}')
67f46a955bSLisandro Dalcinpypiroot = F('https://pypi.io/packages/source')
68f46a955bSLisandro Dalcinpypislug = F('{pyname}')[0] + F('/{pyname}')
69f46a955bSLisandro Dalcintarball = F('{pyname}-%s.tar.gz' % get_version())
70f46a955bSLisandro Dalcindownload = '/'.join([pypiroot, pypislug, tarball])
715808f684SSatish Balay
72fb83dddaSLisandro Dalcinclassifiers = """
73fb83dddaSLisandro DalcinLicense :: OSI Approved :: BSD License
74fb83dddaSLisandro DalcinOperating System :: POSIX
75fb83dddaSLisandro DalcinIntended Audience :: Developers
76fb83dddaSLisandro DalcinIntended Audience :: Science/Research
77fb83dddaSLisandro DalcinProgramming Language :: C
78fb83dddaSLisandro DalcinProgramming Language :: C++
79fb83dddaSLisandro DalcinProgramming Language :: Cython
80fb83dddaSLisandro DalcinProgramming Language :: Python
81fb83dddaSLisandro DalcinProgramming Language :: Python :: 2
82fb83dddaSLisandro DalcinProgramming Language :: Python :: 3
83fb83dddaSLisandro DalcinProgramming Language :: Python :: Implementation :: CPython
84fb83dddaSLisandro DalcinTopic :: Scientific/Engineering
85fb83dddaSLisandro DalcinTopic :: Software Development :: Libraries :: Python Modules
86fb83dddaSLisandro DalcinDevelopment Status :: 5 - Production/Stable
87f46a955bSLisandro Dalcin""".strip().split('\n')
885808f684SSatish Balay
89fb83dddaSLisandro Dalcinkeywords = """
90fb83dddaSLisandro Dalcinscientific computing
91fb83dddaSLisandro Dalcinparallel computing
92fb83dddaSLisandro DalcinMPI
93f46a955bSLisandro Dalcin""".strip().split('\n')
945808f684SSatish Balay
95fb83dddaSLisandro Dalcinplatforms = """
96fb83dddaSLisandro DalcinPOSIX
97fb83dddaSLisandro DalcinLinux
98fb83dddaSLisandro DalcinmacOS
99fb83dddaSLisandro DalcinFreeBSD
100f46a955bSLisandro Dalcin""".strip().split('\n')
101fb83dddaSLisandro Dalcin
102fb83dddaSLisandro Dalcinmetadata = {
103f46a955bSLisandro Dalcin    'name': get_name(),
104f46a955bSLisandro Dalcin    'version': get_version(),
105fb83dddaSLisandro Dalcin    'description': description(),
106fb83dddaSLisandro Dalcin    'long_description': long_description(),
107fb83dddaSLisandro Dalcin    'url': url,
108fb83dddaSLisandro Dalcin    'download_url': download,
109f46a955bSLisandro Dalcin    'classifiers': classifiers,
110f46a955bSLisandro Dalcin    'keywords': keywords + PLIST,
111fb83dddaSLisandro Dalcin    'license': 'BSD-2-Clause',
112f46a955bSLisandro Dalcin    'platforms': platforms,
113fb83dddaSLisandro Dalcin    'author': 'Lisandro Dalcin',
114fb83dddaSLisandro Dalcin    'author_email': 'dalcinl@gmail.com',
115f46a955bSLisandro Dalcin    'maintainer': F('{Name} Team'),
116f46a955bSLisandro Dalcin    'maintainer_email': EMAIL,
117fb83dddaSLisandro Dalcin}
1186f336411SStefano Zampinimetadata.update(
1196f336411SStefano Zampini    {
120fb83dddaSLisandro Dalcin        'requires': ['numpy'],
1216f336411SStefano Zampini    }
1226f336411SStefano Zampini)
123fb83dddaSLisandro Dalcin
124fb83dddaSLisandro Dalcinmetadata_extra = {
125833126bdSLisandro Dalcin    'long_description_content_type': 'text/x-rst',
126fb83dddaSLisandro Dalcin}
1275808f684SSatish Balay
1285808f684SSatish Balay# --------------------------------------------------------------------
1295808f684SSatish Balay# Extension modules
1305808f684SSatish Balay# --------------------------------------------------------------------
1315808f684SSatish Balay
1326f336411SStefano Zampini
133f46a955bSLisandro Dalcindef sources():
1346f336411SStefano Zampini    src = {
1356f336411SStefano Zampini        'source': F('{pyname}/{Name}.pyx'),
1366f336411SStefano Zampini        'depends': [
137f46a955bSLisandro Dalcin            F('{pyname}/*.pyx'),
138f46a955bSLisandro Dalcin            F('{pyname}/*.pxd'),
139f46a955bSLisandro Dalcin            F('{pyname}/{Name}/*.pyx'),
140f46a955bSLisandro Dalcin            F('{pyname}/{Name}/*.pxd'),
141f46a955bSLisandro Dalcin            F('{pyname}/{Name}/*.pxi'),
142f46a955bSLisandro Dalcin        ],
1436f336411SStefano Zampini        'workdir': 'src',
1446f336411SStefano Zampini    }
145f46a955bSLisandro Dalcin    return [src]
146f46a955bSLisandro Dalcin
1476f336411SStefano Zampini
148fb83dddaSLisandro Dalcindef extensions():
1498885bf16SLisandro Dalcin    from os import walk
1505808f684SSatish Balay    from glob import glob
1518885bf16SLisandro Dalcin    from os.path import join
1526f336411SStefano Zampini
153f46a955bSLisandro Dalcin    #
1545808f684SSatish Balay    depends = []
155f46a955bSLisandro Dalcin    glob_join = lambda *args: glob(join(*args))
1566f336411SStefano Zampini    for pth, _, _ in walk('src'):
1578885bf16SLisandro Dalcin        depends += glob_join(pth, '*.h')
1588885bf16SLisandro Dalcin        depends += glob_join(pth, '*.c')
159f46a955bSLisandro Dalcin    for pkg in map(str.lower, reversed(PLIST)):
160f46a955bSLisandro Dalcin        if (pkg.upper() + '_DIR') in os.environ:
161f46a955bSLisandro Dalcin            pd = os.environ[pkg.upper() + '_DIR']
1628885bf16SLisandro Dalcin            pa = os.environ.get('PETSC_ARCH', '')
1638885bf16SLisandro Dalcin            depends += glob_join(pd, 'include', '*.h')
164f46a955bSLisandro Dalcin            depends += glob_join(pd, 'include', pkg, 'private', '*.h')
165f46a955bSLisandro Dalcin            depends += glob_join(pd, pa, 'include', '%sconf.h' % pkg)
166f46a955bSLisandro Dalcin    #
167f46a955bSLisandro Dalcin    include_dirs = []
1680f51ee0fSAlexei Colin    numpy_include = os.environ.get('NUMPY_INCLUDE')
1690f51ee0fSAlexei Colin    if numpy_include is not None:
1700f51ee0fSAlexei Colin        numpy_includes = [numpy_include]
1710f51ee0fSAlexei Colin    else:
1725808f684SSatish Balay        try:
1735808f684SSatish Balay            import numpy
1746f336411SStefano Zampini
1755808f684SSatish Balay            numpy_includes = [numpy.get_include()]
1765808f684SSatish Balay        except ImportError:
1775808f684SSatish Balay            numpy_includes = []
178f46a955bSLisandro Dalcin    include_dirs.extend(numpy_includes)
179f46a955bSLisandro Dalcin    if F('{pyname}') != 'petsc4py':
180f46a955bSLisandro Dalcin        try:
181f46a955bSLisandro Dalcin            import petsc4py
1826f336411SStefano Zampini
183f46a955bSLisandro Dalcin            petsc4py_includes = [petsc4py.get_include()]
184f46a955bSLisandro Dalcin        except ImportError:
185f46a955bSLisandro Dalcin            petsc4py_includes = []
186f46a955bSLisandro Dalcin        include_dirs.extend(petsc4py_includes)
187f46a955bSLisandro Dalcin    #
1886f336411SStefano Zampini    ext = {
1896f336411SStefano Zampini        'name': F('{pyname}.lib.{Name}'),
1906f336411SStefano Zampini        'sources': [F('src/{pyname}/{Name}.c')],
1916f336411SStefano Zampini        'depends': depends,
1926f336411SStefano Zampini        'include_dirs': [
193f46a955bSLisandro Dalcin            'src',
194f46a955bSLisandro Dalcin            F('src/{pyname}/include'),
1956f336411SStefano Zampini        ]
1966f336411SStefano Zampini        + include_dirs,
1976f336411SStefano Zampini        'define_macros': [
198fb83dddaSLisandro Dalcin            ('MPICH_SKIP_MPICXX', 1),
199fb83dddaSLisandro Dalcin            ('OMPI_SKIP_MPICXX', 1),
200f46a955bSLisandro Dalcin            ('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION'),
201fb83dddaSLisandro Dalcin        ],
2026f336411SStefano Zampini    }
203f46a955bSLisandro Dalcin    return [ext]
2045808f684SSatish Balay
2056f336411SStefano Zampini
2065808f684SSatish Balay# --------------------------------------------------------------------
2075808f684SSatish Balay# Setup
2085808f684SSatish Balay# --------------------------------------------------------------------
2095808f684SSatish Balay
2106f336411SStefano Zampini
211f8c80548SLisandro Dalcindef get_release():
212f46a955bSLisandro Dalcin    suffix = os.path.join('src', 'binding', F('{pyname}'))
213f46a955bSLisandro Dalcin    if not topdir.endswith(os.path.join(os.path.sep, suffix)):
214f09792b6SLisandro Dalcin        return True
215f8c80548SLisandro Dalcin    release = 1
216f8c80548SLisandro Dalcin    rootdir = os.path.abspath(os.path.join(topdir, *[os.path.pardir] * 3))
217f46a955bSLisandro Dalcin    version_h = os.path.join(rootdir, 'include', F('{name}version.h'))
218f46a955bSLisandro Dalcin    release_macro = '%s_VERSION_RELEASE' % F('{name}').upper()
2196f336411SStefano Zampini    version_re = re.compile(r'#define\s+%s\s+([-]*\d+)' % release_macro)
220f8c80548SLisandro Dalcin    if os.path.exists(version_h) and os.path.isfile(version_h):
221f8c80548SLisandro Dalcin        with open(version_h, 'r') as f:
222f8c80548SLisandro Dalcin            release = int(version_re.search(f.read()).groups()[0])
223f8c80548SLisandro Dalcin    return bool(release)
224f8c80548SLisandro Dalcin
2256f336411SStefano Zampini
226f8c80548SLisandro Dalcindef requires(pkgname, major, minor, release=True):
227f8c80548SLisandro Dalcin    minor = minor + int(not release)
228f8c80548SLisandro Dalcin    devel = '' if release else '.dev0'
2296f336411SStefano Zampini    vmin = f'{major}.{minor}{devel}'
2306f336411SStefano Zampini    vmax = f'{major}.{minor+1}'
2316f336411SStefano Zampini    return f'{pkgname}>={vmin},<{vmax}'
2326f336411SStefano Zampini
233f8c80548SLisandro Dalcin
2345808f684SSatish Balaydef run_setup():
235*2149b0eaSStefano Zampini    is_sdist = 'sdist' in sys.argv
2365808f684SSatish Balay    setup_args = metadata.copy()
237f8c80548SLisandro Dalcin    vstr = setup_args['version'].split('.')[:2]
238f8c80548SLisandro Dalcin    x, y = tuple(map(int, vstr))
239f8c80548SLisandro Dalcin    release = get_release()
240f8c80548SLisandro Dalcin    if not release:
2416f336411SStefano Zampini        setup_args['version'] = '%d.%d.0.dev0' % (x, y + 1)
2425808f684SSatish Balay    if setuptools:
2435808f684SSatish Balay        setup_args['zip_safe'] = False
244*2149b0eaSStefano Zampini        numpy_pin = 'numpy'
245*2149b0eaSStefano Zampini        if not is_sdist:
24630eefebbSLisandro Dalcin            try:
24730eefebbSLisandro Dalcin                import numpy
2486f336411SStefano Zampini
24930eefebbSLisandro Dalcin                major = int(numpy.__version__.partition('.')[0])
250f566d949SLisandro Dalcin                numpy_pin = 'numpy>=1.19' if major >= 2 else 'numpy<2'
25130eefebbSLisandro Dalcin            except ImportError:
252*2149b0eaSStefano Zampini                pass
253693647e8SLisandro Dalcin        setup_args['setup_requires'] = ['numpy']
25430eefebbSLisandro Dalcin        setup_args['install_requires'] = [numpy_pin]
255f46a955bSLisandro Dalcin        for pkg in map(str.lower, PLIST):
256f46a955bSLisandro Dalcin            PKG_DIR = os.environ.get(pkg.upper() + '_DIR')
257f46a955bSLisandro Dalcin            if not (PKG_DIR and os.path.isdir(PKG_DIR)):
258f46a955bSLisandro Dalcin                package = requires(pkg, x, y, release)
259693647e8SLisandro Dalcin                setup_args['setup_requires'] += [package]
260f46a955bSLisandro Dalcin                setup_args['install_requires'] += [package]
261f46a955bSLisandro Dalcin        if F('{pyname}') != 'petsc4py':
262f46a955bSLisandro Dalcin            package = requires('petsc4py', x, y, release)
263693647e8SLisandro Dalcin            setup_args['setup_requires'] += [package]
264f46a955bSLisandro Dalcin            setup_args['install_requires'] += [package]
265fb83dddaSLisandro Dalcin        setup_args.update(metadata_extra)
2665808f684SSatish Balay    #
267f46a955bSLisandro Dalcin    conf = __import__(F('conf{name}'))
268f46a955bSLisandro Dalcin    conf.setup(
269fb83dddaSLisandro Dalcin        packages=[
270f46a955bSLisandro Dalcin            F('{pyname}'),
271f46a955bSLisandro Dalcin            F('{pyname}.lib'),
272fb83dddaSLisandro Dalcin        ],
273f46a955bSLisandro Dalcin        package_dir={'': 'src'},
274fb83dddaSLisandro Dalcin        package_data={
275f46a955bSLisandro Dalcin            F('{pyname}'): [
276f46a955bSLisandro Dalcin                F('{Name}.pxd'),
277f46a955bSLisandro Dalcin                F('{Name}*.h'),
278f46a955bSLisandro Dalcin                F('include/{pyname}/*.h'),
279f46a955bSLisandro Dalcin                F('include/{pyname}/*.i'),
28055a74a43SLisandro Dalcin                'py.typed',
28155a74a43SLisandro Dalcin                '*.pyi',
28255a74a43SLisandro Dalcin                '*/*.pyi',
283fb83dddaSLisandro Dalcin            ],
284f46a955bSLisandro Dalcin            F('{pyname}.lib'): [
285f46a955bSLisandro Dalcin                F('{name}.cfg'),
286fb83dddaSLisandro Dalcin            ],
287fb83dddaSLisandro Dalcin        },
2886f336411SStefano Zampini        cython_sources=[src for src in sources()],  # noqa: C416
2896f336411SStefano Zampini        ext_modules=[conf.Extension(**ext) for ext in extensions()],
2906f336411SStefano Zampini        **setup_args,
291fb83dddaSLisandro Dalcin    )
2925808f684SSatish Balay
2936f336411SStefano Zampini
294fb83dddaSLisandro Dalcin# --------------------------------------------------------------------
295fb83dddaSLisandro Dalcin
2966f336411SStefano Zampini
2975808f684SSatish Balaydef main():
2985808f684SSatish Balay    run_setup()
2995808f684SSatish Balay
3006f336411SStefano Zampini
3015808f684SSatish Balayif __name__ == '__main__':
3025808f684SSatish Balay    main()
3035808f684SSatish Balay
3045808f684SSatish Balay# --------------------------------------------------------------------
305