xref: /petsc/setup.py (revision 9dddd24924da2034e9ad37bd0330bf8579e05078)
1e68ebbecSBarry Smith#!/usr/bin/env python
2e68ebbecSBarry Smith
3e68ebbecSBarry Smith"""
465a891e7SLisandro DalcinPETSc: Portable, Extensible Toolkit for Scientific Computation
565a891e7SLisandro Dalcin==============================================================
665a891e7SLisandro Dalcin
765a891e7SLisandro DalcinThe Portable, Extensible Toolkit for Scientific Computation (PETSc),
865a891e7SLisandro Dalcinis a suite of data structures and routines for the scalable (parallel)
965a891e7SLisandro Dalcinsolution of scientific applications modeled by partial differential
1065a891e7SLisandro Dalcinequations. It employs the Message Passing Interface (MPI) standard for
1165a891e7SLisandro Dalcinall message-passing communication.
12922ada92SLisandro Dalcin
1393b33a5aSLisandro Dalcin.. note::
1493b33a5aSLisandro Dalcin
1593b33a5aSLisandro Dalcin   To install ``PETSc`` and ``petsc4py`` (``mpi4py`` is optional
1693b33a5aSLisandro Dalcin   but highly recommended) use::
1793b33a5aSLisandro Dalcin
18eaf87d4bSBarry Smith     $ python -m pip install numpy mpi4py  (or pip install numpy mpi4py)
19eaf87d4bSBarry Smith     $ python -m pip install petsc petsc4py (or pip install petsc petsc4py)
2093b33a5aSLisandro Dalcin
21922ada92SLisandro Dalcin.. tip::
22922ada92SLisandro Dalcin
2393b33a5aSLisandro Dalcin  You can also install the in-development versions with::
24922ada92SLisandro Dalcin
25eaf87d4bSBarry Smith    $ python -m pip install Cython numpy mpi4py
26*9dddd249SSatish Balay    $ python -m pip install --no-deps https://gitlab.com/petsc/petsc/-/archive/main/petsc-main.tar.gz
27ca62002aSBarry Smith
28007ce00dSBarry Smith  To set the MPI compilers use the environmental variables ``MPICC``, ``MPICXX``, ``MPIF90``.
29007ce00dSBarry Smith
30007ce00dSBarry Smith  Provide any ``PETSc`` ./configure options using the environmental variable ``PETSC_CONFIGURE_OPTIONS``.
31007ce00dSBarry Smith
32007ce00dSBarry Smith  Do not use the ``PETSc`` ``./configure`` options ``--with-cc``, ``--with-cxx``, ``--with-fc``, or ``--with-mpi-dir``.
33007ce00dSBarry Smith
34007ce00dSBarry Smith  If ``mpi4py`` is installed the compilers will obtained from that installation and ``MPICC``, ``MPICXX``, ``MPIF90`` will be ignored.
35007ce00dSBarry Smith
36e68ebbecSBarry Smith"""
37e68ebbecSBarry Smith
3865a891e7SLisandro Dalcinimport sys, os
3996fd8cd7SLisandro Dalcinfrom setuptools import setup
4096fd8cd7SLisandro Dalcinfrom setuptools.command.install import install as _install
41cb58ab5bSLisandro Dalcinfrom distutils.util import get_platform, split_quoted
42b88f8b63SLisandro Dalcinfrom distutils.spawn import find_executable
4365a891e7SLisandro Dalcinfrom distutils import log
4412c1d45bSMatthew G Knepley
4565a891e7SLisandro Dalcininit_py = """\
46a32381aeSLisandro Dalcin# Author:  PETSc Team
47a597b971SLisandro Dalcin# Contact: petsc-maint@mcs.anl.gov
4865a891e7SLisandro Dalcin
4965a891e7SLisandro Dalcindef get_petsc_dir():
5065a891e7SLisandro Dalcin    import os
5165a891e7SLisandro Dalcin    return os.path.dirname(__file__)
5265a891e7SLisandro Dalcin
53a32381aeSLisandro Dalcindef get_config():
54a32381aeSLisandro Dalcin    conf = {}
559fb7a39fSLisandro Dalcin    conf['PETSC_DIR'] = get_petsc_dir()
56a32381aeSLisandro Dalcin    return conf
5765a891e7SLisandro Dalcin"""
5865a891e7SLisandro Dalcin
5959e0f383SLisandro Dalcinmetadata = {
6059e0f383SLisandro Dalcin    'provides' : ['petsc'],
6196fd8cd7SLisandro Dalcin    'zip_safe' : False,
6259e0f383SLisandro Dalcin}
6359e0f383SLisandro Dalcin
6415075023SLisandro DalcinCONFIGURE_OPTIONS = []
6515075023SLisandro Dalcin
6665a891e7SLisandro Dalcindef bootstrap():
67cb58ab5bSLisandro Dalcin    # Set PETSC_DIR and PETSC_ARCH
6865a891e7SLisandro Dalcin    PETSC_DIR  = os.path.abspath(os.getcwd())
6996fd8cd7SLisandro Dalcin    PETSC_ARCH = 'arch-python-' + get_platform()
7065a891e7SLisandro Dalcin    os.environ['PETSC_DIR']  = PETSC_DIR
7165a891e7SLisandro Dalcin    os.environ['PETSC_ARCH'] = PETSC_ARCH
7265a891e7SLisandro Dalcin    sys.path.insert(0, os.path.join(PETSC_DIR, 'config'))
73af0996ceSBarry Smith    sys.path.insert(0, os.path.join(PETSC_DIR, 'lib','petsc','conf'))
7459e0f383SLisandro Dalcin    # Generate package __init__.py file
759fb7a39fSLisandro Dalcin    from distutils.dir_util import mkpath
769fb7a39fSLisandro Dalcin    pkgdir = os.path.join('config', 'pypi')
770ddf2052SLisandro Dalcin    if not os.path.exists(pkgdir): mkpath(pkgdir)
789fb7a39fSLisandro Dalcin    pkgfile = os.path.join(pkgdir, '__init__.py')
7996fd8cd7SLisandro Dalcin    fh = open(pkgfile, 'w')
80922ada92SLisandro Dalcin    fh.write(init_py)
81922ada92SLisandro Dalcin    fh.close()
8215075023SLisandro Dalcin    # Configure options
8315075023SLisandro Dalcin    options = os.environ.get('PETSC_CONFIGURE_OPTIONS', '')
8415075023SLisandro Dalcin    CONFIGURE_OPTIONS.extend(split_quoted(options))
85007ce00dSBarry Smith    for i in CONFIGURE_OPTIONS:
865f9afd5aSLawrence Mitchell        if i.startswith('--with-mpi-dir='):
87007ce00dSBarry Smith            raise RuntimeError("Do not use --with-mpi-dir, use the environmental variables MPICC, MPICXX, MPIF90")
885f9afd5aSLawrence Mitchell        if i.startswith('--with-cc='):
89007ce00dSBarry Smith            raise RuntimeError("Do not use --with-cc, use the environmental variable MPICC")
905f9afd5aSLawrence Mitchell        if i.startswith('--with-cxx=') and i != "--with-cxx=0":
91007ce00dSBarry Smith            raise RuntimeError("Do not use --with-cxx, use the environmental variable MPICXX")
925f9afd5aSLawrence Mitchell        if i.startswith('--with-fc=') and i != "--with-fc=0":
93007ce00dSBarry Smith            raise RuntimeError("Do not use --with-fc, use the environmental variable MPIF90")
94007ce00dSBarry Smith
9515075023SLisandro Dalcin    if '--with-mpi=0' not in CONFIGURE_OPTIONS:
9659e0f383SLisandro Dalcin        # Simple-minded lookup for MPI and mpi4py
9759e0f383SLisandro Dalcin        mpi4py = mpicc = None
9859e0f383SLisandro Dalcin        try:
9959e0f383SLisandro Dalcin            import mpi4py
10059e0f383SLisandro Dalcin            conf = mpi4py.get_config()
10159e0f383SLisandro Dalcin            mpicc = conf.get('mpicc')
10259e0f383SLisandro Dalcin        except ImportError: # mpi4py is not installed
103922ada92SLisandro Dalcin            mpi4py = None
10415075023SLisandro Dalcin            mpicc = (os.environ.get('MPICC') or
10515075023SLisandro Dalcin                     find_executable('mpicc'))
1061b095333SLisandro Dalcin        except AttributeError: # mpi4py is too old
10759e0f383SLisandro Dalcin            pass
108922ada92SLisandro Dalcin        if not mpi4py and mpicc:
109922ada92SLisandro Dalcin            metadata['install_requires'] = ['mpi4py>=1.2.2']
11065a891e7SLisandro Dalcin
11196fd8cd7SLisandro Dalcindef config(prefix, dry_run=False):
11265a891e7SLisandro Dalcin    log.info('PETSc: configure')
11365a891e7SLisandro Dalcin    options = [
11496fd8cd7SLisandro Dalcin        '--prefix=' + prefix,
11565a891e7SLisandro Dalcin        'PETSC_ARCH='+os.environ['PETSC_ARCH'],
116cb58ab5bSLisandro Dalcin        '--with-shared-libraries=1',
11711035aebSLisandro Dalcin        '--with-debugging=0',
118922ada92SLisandro Dalcin        '--with-c2html=0', # not needed
11965a891e7SLisandro Dalcin        ]
12015075023SLisandro Dalcin    if '--with-fc=0' in CONFIGURE_OPTIONS:
12115075023SLisandro Dalcin        options.append('--with-sowing=0')
12215075023SLisandro Dalcin    if '--with-mpi=0' not in CONFIGURE_OPTIONS:
12359e0f383SLisandro Dalcin        try:
12459e0f383SLisandro Dalcin            import mpi4py
12559e0f383SLisandro Dalcin            conf = mpi4py.get_config()
12659e0f383SLisandro Dalcin            mpicc  = conf.get('mpicc')
127cb58ab5bSLisandro Dalcin            mpicxx = conf.get('mpicxx')
128cb58ab5bSLisandro Dalcin            mpif90 = conf.get('mpif90')
12959e0f383SLisandro Dalcin        except (ImportError, AttributeError):
13059e0f383SLisandro Dalcin            mpicc  = os.environ.get('MPICC')  or find_executable('mpicc')
131cb58ab5bSLisandro Dalcin            mpicxx = os.environ.get('MPICXX') or find_executable('mpicxx')
132cb58ab5bSLisandro Dalcin            mpif90 = os.environ.get('MPIF90') or find_executable('mpif90')
13359e0f383SLisandro Dalcin        if mpicc:
13459e0f383SLisandro Dalcin            options.append('--with-cc='+mpicc)
13515075023SLisandro Dalcin            if '--with-cxx=0' not in CONFIGURE_OPTIONS:
136cb58ab5bSLisandro Dalcin                if mpicxx:
137cb58ab5bSLisandro Dalcin                    options.append('--with-cxx='+mpicxx)
13893b33a5aSLisandro Dalcin                else:
13993b33a5aSLisandro Dalcin                    options.append('--with-cxx=0')
14015075023SLisandro Dalcin            if '--with-fc=0' not in CONFIGURE_OPTIONS:
141cb58ab5bSLisandro Dalcin                if mpif90:
142cb58ab5bSLisandro Dalcin                    options.append('--with-fc='+mpif90)
14359e0f383SLisandro Dalcin                else:
14493b33a5aSLisandro Dalcin                    options.append('--with-fc=0')
14593b33a5aSLisandro Dalcin                    options.append('--with-sowing=0')
14693b33a5aSLisandro Dalcin        else:
14759e0f383SLisandro Dalcin            options.append('--with-mpi=0')
14815075023SLisandro Dalcin    options.extend(CONFIGURE_OPTIONS)
14915075023SLisandro Dalcin    #
150cb58ab5bSLisandro Dalcin    log.info('configure options:')
151cb58ab5bSLisandro Dalcin    for opt in options:
152cb58ab5bSLisandro Dalcin        log.info(' '*4 + opt)
15359e0f383SLisandro Dalcin    # Run PETSc configure
154cb58ab5bSLisandro Dalcin    if dry_run: return
1550a0dac6aSLisandro Dalcin    use_config_py = False
15696fd8cd7SLisandro Dalcin    if use_config_py:
157e68ebbecSBarry Smith        import configure
15865a891e7SLisandro Dalcin        configure.petsc_configure(options)
159e68ebbecSBarry Smith        import logger
160e68ebbecSBarry Smith        logger.Logger.defaultLog = None
16196fd8cd7SLisandro Dalcin    else:
1620a0dac6aSLisandro Dalcin        python = find_executable('python2') or find_executable('python')
1630a0dac6aSLisandro Dalcin        command = [python, './configure'] + options
16496fd8cd7SLisandro Dalcin        status = os.system(" ".join(command))
16596fd8cd7SLisandro Dalcin        if status != 0: raise RuntimeError(status)
16612c1d45bSMatthew G Knepley
16765a891e7SLisandro Dalcindef build(dry_run=False):
16865a891e7SLisandro Dalcin    log.info('PETSc: build')
169367c215cSLisandro Dalcin    # Run PETSc build
170cb58ab5bSLisandro Dalcin    if dry_run: return
171367c215cSLisandro Dalcin    use_builder_py = False
172367c215cSLisandro Dalcin    if use_builder_py:
173e68ebbecSBarry Smith        import builder
174e68ebbecSBarry Smith        builder.PETScMaker().run()
175105e34d4SBarry Smith        import logger
176105e34d4SBarry Smith        logger.Logger.defaultLog = None
177367c215cSLisandro Dalcin    else:
178367c215cSLisandro Dalcin        make = find_executable('make')
17996fd8cd7SLisandro Dalcin        command = [make, 'all']
18096fd8cd7SLisandro Dalcin        status = os.system(" ".join(command))
181367c215cSLisandro Dalcin        if status != 0: raise RuntimeError(status)
182e68ebbecSBarry Smith
1838c408988SSatish Balaydef install(dry_run=False):
18465a891e7SLisandro Dalcin    log.info('PETSc: install')
18559e0f383SLisandro Dalcin    # Run PETSc installer
186cb58ab5bSLisandro Dalcin    if dry_run: return
1870a0dac6aSLisandro Dalcin    use_install_py = False
188367c215cSLisandro Dalcin    if use_install_py:
189105e34d4SBarry Smith        import install
1908c408988SSatish Balay        install.Installer().run()
19165a891e7SLisandro Dalcin        import logger
19265a891e7SLisandro Dalcin        logger.Logger.defaultLog = None
193367c215cSLisandro Dalcin    else:
194367c215cSLisandro Dalcin        make = find_executable('make')
1958c408988SSatish Balay        command = [make, 'install']
19696fd8cd7SLisandro Dalcin        status = os.system(" ".join(command))
197367c215cSLisandro Dalcin        if status != 0: raise RuntimeError(status)
19899468c80SLisandro Dalcin
19996fd8cd7SLisandro Dalcinclass context(object):
20099468c80SLisandro Dalcin    def __init__(self):
20199468c80SLisandro Dalcin        self.sys_argv = sys.argv[:]
20299468c80SLisandro Dalcin        self.wdir = os.getcwd()
20399468c80SLisandro Dalcin    def enter(self):
20499468c80SLisandro Dalcin        del sys.argv[1:]
20599468c80SLisandro Dalcin        pdir = os.environ['PETSC_DIR']
20699468c80SLisandro Dalcin        os.chdir(pdir)
20799468c80SLisandro Dalcin        return self
20899468c80SLisandro Dalcin    def exit(self):
20999468c80SLisandro Dalcin        sys.argv[:] = self.sys_argv
21099468c80SLisandro Dalcin        os.chdir(self.wdir)
211105e34d4SBarry Smith
21265a891e7SLisandro Dalcinclass cmd_install(_install):
21365a891e7SLisandro Dalcin
21441716173SLisandro Dalcin    def initialize_options(self):
21541716173SLisandro Dalcin        _install.initialize_options(self)
21641716173SLisandro Dalcin        self.optimize = 1
21741716173SLisandro Dalcin
21889031a3cSLisandro Dalcin    def finalize_options(self):
21989031a3cSLisandro Dalcin        _install.finalize_options(self)
22089031a3cSLisandro Dalcin        self.install_lib = self.install_platlib
22189031a3cSLisandro Dalcin        self.install_libbase = self.install_lib
22289031a3cSLisandro Dalcin
22365a891e7SLisandro Dalcin    def run(self):
22489031a3cSLisandro Dalcin        root_dir = os.path.abspath(self.install_lib)
2258c408988SSatish Balay        prefix = os.path.join(root_dir, 'petsc')
22699468c80SLisandro Dalcin        #
22799468c80SLisandro Dalcin        ctx = context().enter()
22865a891e7SLisandro Dalcin        try:
22996fd8cd7SLisandro Dalcin            config(prefix, self.dry_run)
23096fd8cd7SLisandro Dalcin            build(self.dry_run)
2318c408988SSatish Balay            install(self.dry_run)
23265a891e7SLisandro Dalcin        finally:
23399468c80SLisandro Dalcin            ctx.exit()
23496fd8cd7SLisandro Dalcin        #
23596fd8cd7SLisandro Dalcin        self.outputs = []
2368c408988SSatish Balay        for dirpath, _, filenames in os.walk(prefix):
23796fd8cd7SLisandro Dalcin            for fn in filenames:
23896fd8cd7SLisandro Dalcin                self.outputs.append(os.path.join(dirpath, fn))
23996fd8cd7SLisandro Dalcin        #
24096fd8cd7SLisandro Dalcin        _install.run(self)
24165a891e7SLisandro Dalcin
24296fd8cd7SLisandro Dalcin    def get_outputs(self):
24396fd8cd7SLisandro Dalcin        outputs = getattr(self, 'outputs', [])
24496fd8cd7SLisandro Dalcin        outputs += _install.get_outputs(self)
24596fd8cd7SLisandro Dalcin        return outputs
246a32381aeSLisandro Dalcin
24765a891e7SLisandro Dalcindef version():
2487d04d9c9SLisandro Dalcin    import re
2497d04d9c9SLisandro Dalcin    version_re = {
2507d04d9c9SLisandro Dalcin        'major'  : re.compile(r"#define\s+PETSC_VERSION_MAJOR\s+(\d+)"),
2517d04d9c9SLisandro Dalcin        'minor'  : re.compile(r"#define\s+PETSC_VERSION_MINOR\s+(\d+)"),
2527d04d9c9SLisandro Dalcin        'micro'  : re.compile(r"#define\s+PETSC_VERSION_SUBMINOR\s+(\d+)"),
25315261b6dSSatish Balay        'release': re.compile(r"#define\s+PETSC_VERSION_RELEASE\s+([-]*\d+)"),
2547d04d9c9SLisandro Dalcin        }
2557d04d9c9SLisandro Dalcin    petscversion_h = os.path.join('include','petscversion.h')
25696fd8cd7SLisandro Dalcin    data = open(petscversion_h, 'r').read()
2577d04d9c9SLisandro Dalcin    major = int(version_re['major'].search(data).groups()[0])
2587d04d9c9SLisandro Dalcin    minor = int(version_re['minor'].search(data).groups()[0])
2597d04d9c9SLisandro Dalcin    micro = int(version_re['micro'].search(data).groups()[0])
2607d04d9c9SLisandro Dalcin    release = int(version_re['release'].search(data).groups()[0])
26115261b6dSSatish Balay    if release > 0 :
2620a0dac6aSLisandro Dalcin        v = "%d.%d.%d" % (major, minor, micro)
2637d04d9c9SLisandro Dalcin    else:
2640a0dac6aSLisandro Dalcin        v = "%d.%d.0.dev%d" % (major, minor+1, 0)
2657d04d9c9SLisandro Dalcin    return v
26659e0f383SLisandro Dalcin
26765a891e7SLisandro Dalcindef tarball():
26850f36069SLisandro Dalcin    VERSION = version()
2690a0dac6aSLisandro Dalcin    if '.dev' in VERSION: return None
270a8d69d7bSBarry Smith    return ('http://ftp.mcs.anl.gov/pub/petsc/release-snapshots//'
2710a0dac6aSLisandro Dalcin            'petsc-lite-%s.tar.gz#egg=petsc-%s' % (VERSION, VERSION))
27265a891e7SLisandro Dalcin
27365a891e7SLisandro Dalcindescription = __doc__.split('\n')[1:-1]; del description[1:3]
27465a891e7SLisandro Dalcinclassifiers = """
27596fd8cd7SLisandro DalcinDevelopment Status :: 5 - Production/Stable
27665a891e7SLisandro DalcinIntended Audience :: Developers
27765a891e7SLisandro DalcinIntended Audience :: Science/Research
27896fd8cd7SLisandro DalcinLicense :: OSI Approved :: BSD License
27996fd8cd7SLisandro DalcinOperating System :: POSIX
28065a891e7SLisandro DalcinProgramming Language :: C
28165a891e7SLisandro DalcinProgramming Language :: C++
28265a891e7SLisandro DalcinProgramming Language :: Fortran
28365a891e7SLisandro DalcinProgramming Language :: Python
28465a891e7SLisandro DalcinTopic :: Scientific/Engineering
28565a891e7SLisandro DalcinTopic :: Software Development :: Libraries
28665a891e7SLisandro Dalcin"""
28765a891e7SLisandro Dalcin
2880a0dac6aSLisandro Dalcinif 'bdist_wheel' in sys.argv:
2890a0dac6aSLisandro Dalcin    sys.stderr.write("petsc: this package cannot be built as a wheel\n")
2900a0dac6aSLisandro Dalcin    sys.exit(1)
2910a0dac6aSLisandro Dalcin
29265a891e7SLisandro Dalcinbootstrap()
29365a891e7SLisandro Dalcinsetup(name='petsc',
29465a891e7SLisandro Dalcin      version=version(),
29565a891e7SLisandro Dalcin      description=description.pop(0),
29665a891e7SLisandro Dalcin      long_description='\n'.join(description),
29765a891e7SLisandro Dalcin      classifiers= classifiers.split('\n')[1:-1],
29865a891e7SLisandro Dalcin      keywords = ['PETSc', 'MPI'],
29965a891e7SLisandro Dalcin      platforms=['POSIX'],
300405e6c8eSLisandro Dalcin      license='BSD',
30165a891e7SLisandro Dalcin
302a8d69d7bSBarry Smith      url='https://www.mcs.anl.gov/petsc/',
30365a891e7SLisandro Dalcin      download_url=tarball(),
30465a891e7SLisandro Dalcin
30565a891e7SLisandro Dalcin      author='PETSc Team',
30699468c80SLisandro Dalcin      author_email='petsc-maint@mcs.anl.gov',
30765a891e7SLisandro Dalcin      maintainer='Lisandro Dalcin',
30865a891e7SLisandro Dalcin      maintainer_email='dalcinl@gmail.com',
30965a891e7SLisandro Dalcin
31065a891e7SLisandro Dalcin      packages = ['petsc'],
3119fb7a39fSLisandro Dalcin      package_dir = {'petsc': 'config/pypi'},
31296fd8cd7SLisandro Dalcin      cmdclass={'install': cmd_install},
31359e0f383SLisandro Dalcin      **metadata)
314