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 89fb6d20cSLisandro Dalcinimport warnings 95808f684SSatish Balay 105808f684SSatish Balaytry: 115808f684SSatish Balay import setuptools 125808f684SSatish Balayexcept ImportError: 135808f684SSatish Balay setuptools = None 145808f684SSatish Balay 15f46a955bSLisandro Dalcintopdir = os.path.abspath(os.path.dirname(__file__)) 16f46a955bSLisandro Dalcinsys.path.insert(0, os.path.join(topdir, 'conf')) 17f46a955bSLisandro Dalcin 185808f684SSatish Balaypyver = sys.version_info[:2] 19aab42556SSatish Balayif pyver < (3, 6): 20aab42556SSatish Balay raise RuntimeError('Python version 3.6 or higher is required') 211e83877aSSatish Balay 22f46a955bSLisandro DalcinPNAME = 'PETSc' 23f46a955bSLisandro DalcinEMAIL = 'petsc-maint@mcs.anl.gov' 24f46a955bSLisandro DalcinPLIST = [PNAME] 25fb83dddaSLisandro Dalcin 265808f684SSatish Balay# -------------------------------------------------------------------- 275808f684SSatish Balay# Metadata 285808f684SSatish Balay# -------------------------------------------------------------------- 295808f684SSatish Balay 30*7b8d1e39SLisandro Dalcinpy_limited_api = (3, 10) 31*7b8d1e39SLisandro Dalcin 326f336411SStefano Zampini 33f46a955bSLisandro Dalcindef F(string): 34f46a955bSLisandro Dalcin return string.format( 35f46a955bSLisandro Dalcin Name=PNAME, 36f46a955bSLisandro Dalcin name=PNAME.lower(), 37f46a955bSLisandro Dalcin pyname=PNAME.lower() + '4py', 38f46a955bSLisandro Dalcin ) 395808f684SSatish Balay 406f336411SStefano Zampini 41f46a955bSLisandro Dalcindef get_name(): 42f46a955bSLisandro Dalcin return F('{pyname}') 435808f684SSatish Balay 446f336411SStefano Zampini 45f46a955bSLisandro Dalcindef get_version(): 46f46a955bSLisandro Dalcin try: 47f46a955bSLisandro Dalcin return get_version.result 48f46a955bSLisandro Dalcin except AttributeError: 49f46a955bSLisandro Dalcin pass 50f46a955bSLisandro Dalcin pkg_init_py = os.path.join(F('{pyname}'), '__init__.py') 51f46a955bSLisandro Dalcin with open(os.path.join(topdir, 'src', pkg_init_py)) as f: 525808f684SSatish Balay m = re.search(r"__version__\s*=\s*'(.*)'", f.read()) 53f46a955bSLisandro Dalcin version = m.groups()[0] 54f46a955bSLisandro Dalcin get_version.result = version 55f46a955bSLisandro Dalcin return version 565808f684SSatish Balay 576f336411SStefano Zampini 585808f684SSatish Balaydef description(): 59f46a955bSLisandro Dalcin return F('{Name} for Python') 60fb83dddaSLisandro Dalcin 616f336411SStefano Zampini 62fb83dddaSLisandro Dalcindef long_description(): 635808f684SSatish Balay with open(os.path.join(topdir, 'DESCRIPTION.rst')) as f: 645808f684SSatish Balay return f.read() 655808f684SSatish Balay 666f336411SStefano Zampini 67f46a955bSLisandro Dalcinurl = F('https://gitlab.com/{name}/{name}') 68f46a955bSLisandro Dalcinpypiroot = F('https://pypi.io/packages/source') 69f46a955bSLisandro Dalcinpypislug = F('{pyname}')[0] + F('/{pyname}') 70f46a955bSLisandro Dalcintarball = F('{pyname}-%s.tar.gz' % get_version()) 71f46a955bSLisandro Dalcindownload = '/'.join([pypiroot, pypislug, tarball]) 725808f684SSatish Balay 73fb83dddaSLisandro Dalcinclassifiers = """ 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 :: 3 82fb83dddaSLisandro DalcinProgramming Language :: Python :: Implementation :: CPython 83fb83dddaSLisandro DalcinTopic :: Scientific/Engineering 84fb83dddaSLisandro DalcinTopic :: Software Development :: Libraries :: Python Modules 85fb83dddaSLisandro DalcinDevelopment Status :: 5 - Production/Stable 86f46a955bSLisandro Dalcin""".strip().split('\n') 875808f684SSatish Balay 88fb83dddaSLisandro Dalcinkeywords = """ 89fb83dddaSLisandro Dalcinscientific computing 90fb83dddaSLisandro Dalcinparallel computing 91fb83dddaSLisandro DalcinMPI 92f46a955bSLisandro Dalcin""".strip().split('\n') 935808f684SSatish Balay 94fb83dddaSLisandro Dalcinplatforms = """ 95fb83dddaSLisandro DalcinPOSIX 96fb83dddaSLisandro DalcinLinux 97fb83dddaSLisandro DalcinmacOS 98fb83dddaSLisandro DalcinFreeBSD 99f46a955bSLisandro Dalcin""".strip().split('\n') 100fb83dddaSLisandro Dalcin 101fb83dddaSLisandro Dalcinmetadata = { 102f46a955bSLisandro Dalcin 'name': get_name(), 103f46a955bSLisandro Dalcin 'version': get_version(), 104fb83dddaSLisandro Dalcin 'description': description(), 105fb83dddaSLisandro Dalcin 'long_description': long_description(), 106fb83dddaSLisandro Dalcin 'url': url, 107fb83dddaSLisandro Dalcin 'download_url': download, 108f46a955bSLisandro Dalcin 'classifiers': classifiers, 109f46a955bSLisandro Dalcin 'keywords': keywords + PLIST, 110fb83dddaSLisandro Dalcin 'license': 'BSD-2-Clause', 111f46a955bSLisandro Dalcin 'platforms': platforms, 112fb83dddaSLisandro Dalcin 'author': 'Lisandro Dalcin', 113fb83dddaSLisandro Dalcin 'author_email': 'dalcinl@gmail.com', 114f46a955bSLisandro Dalcin 'maintainer': F('{Name} Team'), 115f46a955bSLisandro Dalcin 'maintainer_email': EMAIL, 116fb83dddaSLisandro Dalcin} 1176f336411SStefano Zampinimetadata.update( 1186f336411SStefano Zampini { 119fb83dddaSLisandro Dalcin 'requires': ['numpy'], 1206f336411SStefano Zampini } 1216f336411SStefano Zampini) 122fb83dddaSLisandro Dalcin 123fb83dddaSLisandro Dalcinmetadata_extra = { 124833126bdSLisandro Dalcin 'long_description_content_type': 'text/x-rst', 125fb83dddaSLisandro Dalcin} 1265808f684SSatish Balay 127*7b8d1e39SLisandro Dalcindef get_build_pysabi(): 128*7b8d1e39SLisandro Dalcin abi = os.environ.get("PETSC4PY_BUILD_PYSABI") 129*7b8d1e39SLisandro Dalcin if abi and sys.implementation.name == "cpython": 130*7b8d1e39SLisandro Dalcin if abi == "1": 131*7b8d1e39SLisandro Dalcin return py_limited_api 132*7b8d1e39SLisandro Dalcin if abi.startswith("cp"): 133*7b8d1e39SLisandro Dalcin abi = abi[2:] 134*7b8d1e39SLisandro Dalcin if "." in abi: 135*7b8d1e39SLisandro Dalcin x, y = abi.split(".") 136*7b8d1e39SLisandro Dalcin else: 137*7b8d1e39SLisandro Dalcin x, y = abi[0], abi[1:] 138*7b8d1e39SLisandro Dalcin return (int(x), int(y)) 139*7b8d1e39SLisandro Dalcin return None 140*7b8d1e39SLisandro Dalcin 1415808f684SSatish Balay# -------------------------------------------------------------------- 1425808f684SSatish Balay# Extension modules 1435808f684SSatish Balay# -------------------------------------------------------------------- 1445808f684SSatish Balay 1456f336411SStefano Zampini 146f46a955bSLisandro Dalcindef sources(): 1476f336411SStefano Zampini src = { 1486f336411SStefano Zampini 'source': F('{pyname}/{Name}.pyx'), 1496f336411SStefano Zampini 'depends': [ 150f46a955bSLisandro Dalcin F('{pyname}/*.pyx'), 151f46a955bSLisandro Dalcin F('{pyname}/*.pxd'), 152f46a955bSLisandro Dalcin F('{pyname}/{Name}/*.pyx'), 153f46a955bSLisandro Dalcin F('{pyname}/{Name}/*.pxd'), 154f46a955bSLisandro Dalcin F('{pyname}/{Name}/*.pxi'), 155f46a955bSLisandro Dalcin ], 1566f336411SStefano Zampini 'workdir': 'src', 1576f336411SStefano Zampini } 158f46a955bSLisandro Dalcin return [src] 159f46a955bSLisandro Dalcin 1606f336411SStefano Zampini 161fb83dddaSLisandro Dalcindef extensions(): 1628885bf16SLisandro Dalcin from os import walk 1635808f684SSatish Balay from glob import glob 1648885bf16SLisandro Dalcin from os.path import join 1656f336411SStefano Zampini 166f46a955bSLisandro Dalcin # 1675808f684SSatish Balay depends = [] 168f46a955bSLisandro Dalcin glob_join = lambda *args: glob(join(*args)) 1696f336411SStefano Zampini for pth, _, _ in walk('src'): 1708885bf16SLisandro Dalcin depends += glob_join(pth, '*.h') 1718885bf16SLisandro Dalcin depends += glob_join(pth, '*.c') 172f46a955bSLisandro Dalcin for pkg in map(str.lower, reversed(PLIST)): 173f46a955bSLisandro Dalcin if (pkg.upper() + '_DIR') in os.environ: 174f46a955bSLisandro Dalcin pd = os.environ[pkg.upper() + '_DIR'] 1758885bf16SLisandro Dalcin pa = os.environ.get('PETSC_ARCH', '') 1768885bf16SLisandro Dalcin depends += glob_join(pd, 'include', '*.h') 177f46a955bSLisandro Dalcin depends += glob_join(pd, 'include', pkg, 'private', '*.h') 178f46a955bSLisandro Dalcin depends += glob_join(pd, pa, 'include', '%sconf.h' % pkg) 179f46a955bSLisandro Dalcin # 180f46a955bSLisandro Dalcin include_dirs = [] 1810f51ee0fSAlexei Colin numpy_include = os.environ.get('NUMPY_INCLUDE') 1820f51ee0fSAlexei Colin if numpy_include is not None: 1830f51ee0fSAlexei Colin numpy_includes = [numpy_include] 1840f51ee0fSAlexei Colin else: 1855808f684SSatish Balay try: 1865808f684SSatish Balay import numpy 1876f336411SStefano Zampini 1885808f684SSatish Balay numpy_includes = [numpy.get_include()] 1895808f684SSatish Balay except ImportError: 1905808f684SSatish Balay numpy_includes = [] 191f46a955bSLisandro Dalcin include_dirs.extend(numpy_includes) 192f46a955bSLisandro Dalcin if F('{pyname}') != 'petsc4py': 193f46a955bSLisandro Dalcin try: 194f46a955bSLisandro Dalcin import petsc4py 1956f336411SStefano Zampini 196f46a955bSLisandro Dalcin petsc4py_includes = [petsc4py.get_include()] 197f46a955bSLisandro Dalcin except ImportError: 198f46a955bSLisandro Dalcin petsc4py_includes = [] 199f46a955bSLisandro Dalcin include_dirs.extend(petsc4py_includes) 200f46a955bSLisandro Dalcin # 2016f336411SStefano Zampini ext = { 2026f336411SStefano Zampini 'name': F('{pyname}.lib.{Name}'), 2036f336411SStefano Zampini 'sources': [F('src/{pyname}/{Name}.c')], 2046f336411SStefano Zampini 'depends': depends, 2056f336411SStefano Zampini 'include_dirs': [ 206f46a955bSLisandro Dalcin 'src', 207f46a955bSLisandro Dalcin F('src/{pyname}/include'), 2086f336411SStefano Zampini ] 2096f336411SStefano Zampini + include_dirs, 2106f336411SStefano Zampini 'define_macros': [ 211fb83dddaSLisandro Dalcin ('MPICH_SKIP_MPICXX', 1), 212fb83dddaSLisandro Dalcin ('OMPI_SKIP_MPICXX', 1), 213f46a955bSLisandro Dalcin ('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION'), 214fb83dddaSLisandro Dalcin ], 2156f336411SStefano Zampini } 216f46a955bSLisandro Dalcin return [ext] 2175808f684SSatish Balay 2186f336411SStefano Zampini 2195808f684SSatish Balay# -------------------------------------------------------------------- 2205808f684SSatish Balay# Setup 2215808f684SSatish Balay# -------------------------------------------------------------------- 2225808f684SSatish Balay 2236f336411SStefano Zampini 224f8c80548SLisandro Dalcindef get_release(): 225f46a955bSLisandro Dalcin suffix = os.path.join('src', 'binding', F('{pyname}')) 226f46a955bSLisandro Dalcin if not topdir.endswith(os.path.join(os.path.sep, suffix)): 227f09792b6SLisandro Dalcin return True 228f8c80548SLisandro Dalcin release = 1 229f8c80548SLisandro Dalcin rootdir = os.path.abspath(os.path.join(topdir, *[os.path.pardir] * 3)) 230f46a955bSLisandro Dalcin version_h = os.path.join(rootdir, 'include', F('{name}version.h')) 231f46a955bSLisandro Dalcin release_macro = '%s_VERSION_RELEASE' % F('{name}').upper() 2326f336411SStefano Zampini version_re = re.compile(r'#define\s+%s\s+([-]*\d+)' % release_macro) 233f8c80548SLisandro Dalcin if os.path.exists(version_h) and os.path.isfile(version_h): 234f8c80548SLisandro Dalcin with open(version_h, 'r') as f: 235f8c80548SLisandro Dalcin release = int(version_re.search(f.read()).groups()[0]) 236f8c80548SLisandro Dalcin return bool(release) 237f8c80548SLisandro Dalcin 2386f336411SStefano Zampini 239f8c80548SLisandro Dalcindef requires(pkgname, major, minor, release=True): 240f8c80548SLisandro Dalcin minor = minor + int(not release) 241f8c80548SLisandro Dalcin devel = '' if release else '.dev0' 2426f336411SStefano Zampini vmin = f'{major}.{minor}{devel}' 2436f336411SStefano Zampini vmax = f'{major}.{minor+1}' 2446f336411SStefano Zampini return f'{pkgname}>={vmin},<{vmax}' 2456f336411SStefano Zampini 246f8c80548SLisandro Dalcin 2475808f684SSatish Balaydef run_setup(): 2482149b0eaSStefano Zampini is_sdist = 'sdist' in sys.argv 2495808f684SSatish Balay setup_args = metadata.copy() 250f8c80548SLisandro Dalcin vstr = setup_args['version'].split('.')[:2] 251f8c80548SLisandro Dalcin x, y = tuple(map(int, vstr)) 252f8c80548SLisandro Dalcin release = get_release() 253f8c80548SLisandro Dalcin if not release: 2546f336411SStefano Zampini setup_args['version'] = '%d.%d.0.dev0' % (x, y + 1) 2555808f684SSatish Balay if setuptools: 2569fb6d20cSLisandro Dalcin warnings.filterwarnings( 2579fb6d20cSLisandro Dalcin 'ignore', message=r'.*fetch_build_eggs', module='setuptools' 2589fb6d20cSLisandro Dalcin ) 2595808f684SSatish Balay setup_args['zip_safe'] = False 2602149b0eaSStefano Zampini numpy_pin = 'numpy' 2612149b0eaSStefano Zampini if not is_sdist: 26230eefebbSLisandro Dalcin try: 26330eefebbSLisandro Dalcin import numpy 2646f336411SStefano Zampini 26530eefebbSLisandro Dalcin major = int(numpy.__version__.partition('.')[0]) 266f566d949SLisandro Dalcin numpy_pin = 'numpy>=1.19' if major >= 2 else 'numpy<2' 26730eefebbSLisandro Dalcin except ImportError: 2682149b0eaSStefano Zampini pass 269693647e8SLisandro Dalcin setup_args['setup_requires'] = ['numpy'] 27030eefebbSLisandro Dalcin setup_args['install_requires'] = [numpy_pin] 271f46a955bSLisandro Dalcin for pkg in map(str.lower, PLIST): 272f46a955bSLisandro Dalcin PKG_DIR = os.environ.get(pkg.upper() + '_DIR') 273f46a955bSLisandro Dalcin if not (PKG_DIR and os.path.isdir(PKG_DIR)): 274f46a955bSLisandro Dalcin package = requires(pkg, x, y, release) 275693647e8SLisandro Dalcin setup_args['setup_requires'] += [package] 276f46a955bSLisandro Dalcin setup_args['install_requires'] += [package] 277f46a955bSLisandro Dalcin if F('{pyname}') != 'petsc4py': 278f46a955bSLisandro Dalcin package = requires('petsc4py', x, y, release) 279693647e8SLisandro Dalcin setup_args['setup_requires'] += [package] 280f46a955bSLisandro Dalcin setup_args['install_requires'] += [package] 281fb83dddaSLisandro Dalcin setup_args.update(metadata_extra) 2825808f684SSatish Balay # 283f46a955bSLisandro Dalcin conf = __import__(F('conf{name}')) 284*7b8d1e39SLisandro Dalcin cython_sources = [src for src in sources()] # noqa: C416 285*7b8d1e39SLisandro Dalcin ext_modules = [conf.Extension(**ext) for ext in extensions()] 286*7b8d1e39SLisandro Dalcin # 287*7b8d1e39SLisandro Dalcin sabi = get_build_pysabi() 288*7b8d1e39SLisandro Dalcin if sabi and setuptools: 289*7b8d1e39SLisandro Dalcin api_tag = "cp{}{}".format(*sabi) 290*7b8d1e39SLisandro Dalcin options = {"bdist_wheel": {"py_limited_api": api_tag}} 291*7b8d1e39SLisandro Dalcin setup_args["options"] = options 292*7b8d1e39SLisandro Dalcin api_ver = "0x{:02X}{:02X}0000".format(*sabi) 293*7b8d1e39SLisandro Dalcin defines = [("Py_LIMITED_API", api_ver)] 294*7b8d1e39SLisandro Dalcin for ext in ext_modules: 295*7b8d1e39SLisandro Dalcin ext.define_macros.extend(defines) 296*7b8d1e39SLisandro Dalcin ext.py_limited_api = True 297*7b8d1e39SLisandro Dalcin # 298f46a955bSLisandro Dalcin conf.setup( 299fb83dddaSLisandro Dalcin packages=[ 300f46a955bSLisandro Dalcin F('{pyname}'), 301f46a955bSLisandro Dalcin F('{pyname}.lib'), 30222d6dc08SStefano Zampini F('{pyname}.lib._pytypes'), 30322d6dc08SStefano Zampini F('{pyname}.lib._pytypes.viewer'), 304fb83dddaSLisandro Dalcin ], 305f46a955bSLisandro Dalcin package_dir={'': 'src'}, 306fb83dddaSLisandro Dalcin package_data={ 307f46a955bSLisandro Dalcin F('{pyname}'): [ 308f46a955bSLisandro Dalcin F('{Name}.pxd'), 309f46a955bSLisandro Dalcin F('{Name}*.h'), 310f46a955bSLisandro Dalcin F('include/{pyname}/*.h'), 311f46a955bSLisandro Dalcin F('include/{pyname}/*.i'), 31255a74a43SLisandro Dalcin 'py.typed', 31355a74a43SLisandro Dalcin '*.pyi', 31455a74a43SLisandro Dalcin '*/*.pyi', 315fb83dddaSLisandro Dalcin ], 316f46a955bSLisandro Dalcin F('{pyname}.lib'): [ 317f46a955bSLisandro Dalcin F('{name}.cfg'), 318fb83dddaSLisandro Dalcin ], 319fb83dddaSLisandro Dalcin }, 320*7b8d1e39SLisandro Dalcin cython_sources=cython_sources, 321*7b8d1e39SLisandro Dalcin ext_modules=ext_modules, 3226f336411SStefano Zampini **setup_args, 323fb83dddaSLisandro Dalcin ) 3245808f684SSatish Balay 3256f336411SStefano Zampini 326fb83dddaSLisandro Dalcin# -------------------------------------------------------------------- 327fb83dddaSLisandro Dalcin 3286f336411SStefano Zampini 3295808f684SSatish Balaydef main(): 3305808f684SSatish Balay run_setup() 3315808f684SSatish Balay 3326f336411SStefano Zampini 3335808f684SSatish Balayif __name__ == '__main__': 3345808f684SSatish Balay main() 3355808f684SSatish Balay 3365808f684SSatish Balay# -------------------------------------------------------------------- 337