xref: /petsc/setup.py (revision af0996ce37bc06907c37d8d91773840993d61e62)
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
1893b33a5aSLisandro Dalcin     $ pip install numpy mpi4py
1993b33a5aSLisandro Dalcin     $ pip install petsc petsc4py
2093b33a5aSLisandro Dalcin
21922ada92SLisandro Dalcin.. tip::
22922ada92SLisandro Dalcin
2393b33a5aSLisandro Dalcin  You can also install the in-development versions with::
24922ada92SLisandro Dalcin
2593b33a5aSLisandro Dalcin    $ pip install Cython numpy mpi4py
2693b33a5aSLisandro Dalcin    $ pip install --no-deps https://bitbucket.org/petsc/petsc/get/master.tar.gz
2793b33a5aSLisandro Dalcin    $ pip install --no-deps https://bitbucket.org/petsc/petsc4py/get/master.tar.gz
28ca62002aSBarry Smith
29e68ebbecSBarry Smith"""
30e68ebbecSBarry Smith
3165a891e7SLisandro Dalcinimport sys, os
3296fd8cd7SLisandro Dalcinfrom setuptools import setup
3396fd8cd7SLisandro Dalcinfrom setuptools.command.install import install as _install
34cb58ab5bSLisandro Dalcinfrom distutils.util import get_platform, split_quoted
35b88f8b63SLisandro Dalcinfrom distutils.spawn import find_executable
3665a891e7SLisandro Dalcinfrom distutils import log
3712c1d45bSMatthew G Knepley
3865a891e7SLisandro Dalcininit_py = """\
39a32381aeSLisandro Dalcin# Author:  PETSc Team
40a597b971SLisandro Dalcin# Contact: petsc-maint@mcs.anl.gov
4165a891e7SLisandro Dalcin
4265a891e7SLisandro Dalcindef get_petsc_dir():
4365a891e7SLisandro Dalcin    import os
4465a891e7SLisandro Dalcin    return os.path.dirname(__file__)
4565a891e7SLisandro Dalcin
46a32381aeSLisandro Dalcindef get_config():
47a32381aeSLisandro Dalcin    conf = {}
489fb7a39fSLisandro Dalcin    conf['PETSC_DIR'] = get_petsc_dir()
49a32381aeSLisandro Dalcin    return conf
5065a891e7SLisandro Dalcin"""
5165a891e7SLisandro Dalcin
5259e0f383SLisandro Dalcinmetadata = {
5359e0f383SLisandro Dalcin    'provides' : ['petsc'],
5496fd8cd7SLisandro Dalcin    'zip_safe' : False,
5559e0f383SLisandro Dalcin}
5659e0f383SLisandro Dalcin
5715075023SLisandro DalcinCONFIGURE_OPTIONS = []
5815075023SLisandro Dalcin
5965a891e7SLisandro Dalcindef bootstrap():
60cb58ab5bSLisandro Dalcin    # Set PETSC_DIR and PETSC_ARCH
6165a891e7SLisandro Dalcin    PETSC_DIR  = os.path.abspath(os.getcwd())
6296fd8cd7SLisandro Dalcin    PETSC_ARCH = 'arch-python-' + get_platform()
6365a891e7SLisandro Dalcin    os.environ['PETSC_DIR']  = PETSC_DIR
6465a891e7SLisandro Dalcin    os.environ['PETSC_ARCH'] = PETSC_ARCH
6565a891e7SLisandro Dalcin    sys.path.insert(0, os.path.join(PETSC_DIR, 'config'))
66*af0996ceSBarry Smith    sys.path.insert(0, os.path.join(PETSC_DIR, 'lib','petsc','conf'))
6759e0f383SLisandro Dalcin    # Generate package __init__.py file
689fb7a39fSLisandro Dalcin    from distutils.dir_util import mkpath
699fb7a39fSLisandro Dalcin    pkgdir = os.path.join('config', 'pypi')
700ddf2052SLisandro Dalcin    if not os.path.exists(pkgdir): mkpath(pkgdir)
719fb7a39fSLisandro Dalcin    pkgfile = os.path.join(pkgdir, '__init__.py')
7296fd8cd7SLisandro Dalcin    fh = open(pkgfile, 'w')
73922ada92SLisandro Dalcin    fh.write(init_py)
74922ada92SLisandro Dalcin    fh.close()
7515075023SLisandro Dalcin    # Configure options
7615075023SLisandro Dalcin    options = os.environ.get('PETSC_CONFIGURE_OPTIONS', '')
7715075023SLisandro Dalcin    CONFIGURE_OPTIONS.extend(split_quoted(options))
7815075023SLisandro Dalcin    if '--with-mpi=0' not in CONFIGURE_OPTIONS:
7959e0f383SLisandro Dalcin        # Simple-minded lookup for MPI and mpi4py
8059e0f383SLisandro Dalcin        mpi4py = mpicc = None
8159e0f383SLisandro Dalcin        try:
8259e0f383SLisandro Dalcin            import mpi4py
8359e0f383SLisandro Dalcin            conf = mpi4py.get_config()
8459e0f383SLisandro Dalcin            mpicc = conf.get('mpicc')
8559e0f383SLisandro Dalcin        except ImportError: # mpi4py is not installed
86922ada92SLisandro Dalcin            mpi4py = None
8715075023SLisandro Dalcin            mpicc = (os.environ.get('MPICC') or
8815075023SLisandro Dalcin                     find_executable('mpicc'))
891b095333SLisandro Dalcin        except AttributeError: # mpi4py is too old
9059e0f383SLisandro Dalcin            pass
91922ada92SLisandro Dalcin        if not mpi4py and mpicc:
92922ada92SLisandro Dalcin            metadata['install_requires'] = ['mpi4py>=1.2.2']
9365a891e7SLisandro Dalcin
9496fd8cd7SLisandro Dalcindef config(prefix, dry_run=False):
9565a891e7SLisandro Dalcin    log.info('PETSc: configure')
9665a891e7SLisandro Dalcin    options = [
9796fd8cd7SLisandro Dalcin        '--prefix=' + prefix,
9865a891e7SLisandro Dalcin        'PETSC_ARCH='+os.environ['PETSC_ARCH'],
99cb58ab5bSLisandro Dalcin        '--with-shared-libraries=1',
10011035aebSLisandro Dalcin        '--with-debugging=0',
101922ada92SLisandro Dalcin        '--with-c2html=0', # not needed
10265a891e7SLisandro Dalcin        ]
10315075023SLisandro Dalcin    if '--with-fc=0' in CONFIGURE_OPTIONS:
10415075023SLisandro Dalcin        options.append('--with-sowing=0')
10515075023SLisandro Dalcin    if '--with-mpi=0' not in CONFIGURE_OPTIONS:
10659e0f383SLisandro Dalcin        try:
10759e0f383SLisandro Dalcin            import mpi4py
10859e0f383SLisandro Dalcin            conf = mpi4py.get_config()
10959e0f383SLisandro Dalcin            mpicc  = conf.get('mpicc')
110cb58ab5bSLisandro Dalcin            mpicxx = conf.get('mpicxx')
111cb58ab5bSLisandro Dalcin            mpif90 = conf.get('mpif90')
11259e0f383SLisandro Dalcin        except (ImportError, AttributeError):
11359e0f383SLisandro Dalcin            mpicc  = os.environ.get('MPICC')  or find_executable('mpicc')
114cb58ab5bSLisandro Dalcin            mpicxx = os.environ.get('MPICXX') or find_executable('mpicxx')
115cb58ab5bSLisandro Dalcin            mpif90 = os.environ.get('MPIF90') or find_executable('mpif90')
11659e0f383SLisandro Dalcin        if mpicc:
11759e0f383SLisandro Dalcin            options.append('--with-cc='+mpicc)
11815075023SLisandro Dalcin            if '--with-cxx=0' not in CONFIGURE_OPTIONS:
119cb58ab5bSLisandro Dalcin                if mpicxx:
120cb58ab5bSLisandro Dalcin                    options.append('--with-cxx='+mpicxx)
12193b33a5aSLisandro Dalcin                else:
12293b33a5aSLisandro Dalcin                    options.append('--with-cxx=0')
12315075023SLisandro Dalcin            if '--with-fc=0' not in CONFIGURE_OPTIONS:
124cb58ab5bSLisandro Dalcin                if mpif90:
125cb58ab5bSLisandro Dalcin                    options.append('--with-fc='+mpif90)
12659e0f383SLisandro Dalcin                else:
12793b33a5aSLisandro Dalcin                    options.append('--with-fc=0')
12893b33a5aSLisandro Dalcin                    options.append('--with-sowing=0')
12993b33a5aSLisandro Dalcin        else:
13059e0f383SLisandro Dalcin            options.append('--with-mpi=0')
13115075023SLisandro Dalcin    options.extend(CONFIGURE_OPTIONS)
13215075023SLisandro Dalcin    #
133cb58ab5bSLisandro Dalcin    log.info('configure options:')
134cb58ab5bSLisandro Dalcin    for opt in options:
135cb58ab5bSLisandro Dalcin        log.info(' '*4 + opt)
13659e0f383SLisandro Dalcin    # Run PETSc configure
137cb58ab5bSLisandro Dalcin    if dry_run: return
13896fd8cd7SLisandro Dalcin    use_config_py = True
13996fd8cd7SLisandro Dalcin    if use_config_py:
140e68ebbecSBarry Smith        import configure
14165a891e7SLisandro Dalcin        configure.petsc_configure(options)
142e68ebbecSBarry Smith        import logger
143e68ebbecSBarry Smith        logger.Logger.defaultLog = None
14496fd8cd7SLisandro Dalcin    else:
14596fd8cd7SLisandro Dalcin        command = ['./configure'] + options
14696fd8cd7SLisandro Dalcin        status = os.system(" ".join(command))
14796fd8cd7SLisandro Dalcin        if status != 0: raise RuntimeError(status)
14812c1d45bSMatthew G Knepley
14965a891e7SLisandro Dalcindef build(dry_run=False):
15065a891e7SLisandro Dalcin    log.info('PETSc: build')
151367c215cSLisandro Dalcin    # Run PETSc build
152cb58ab5bSLisandro Dalcin    if dry_run: return
153367c215cSLisandro Dalcin    use_builder_py = False
154367c215cSLisandro Dalcin    if use_builder_py:
155e68ebbecSBarry Smith        import builder
156e68ebbecSBarry Smith        builder.PETScMaker().run()
157105e34d4SBarry Smith        import logger
158105e34d4SBarry Smith        logger.Logger.defaultLog = None
159367c215cSLisandro Dalcin    else:
160367c215cSLisandro Dalcin        make = find_executable('make')
16196fd8cd7SLisandro Dalcin        command = [make, 'all']
16296fd8cd7SLisandro Dalcin        status = os.system(" ".join(command))
163367c215cSLisandro Dalcin        if status != 0: raise RuntimeError(status)
164e68ebbecSBarry Smith
16596fd8cd7SLisandro Dalcindef install(dest_dir, dry_run=False):
16665a891e7SLisandro Dalcin    log.info('PETSc: install')
16765a891e7SLisandro Dalcin    options = [
16865a891e7SLisandro Dalcin        '--destDir=' + dest_dir,
16965a891e7SLisandro Dalcin        ]
170cb58ab5bSLisandro Dalcin    log.info('install options:')
171cb58ab5bSLisandro Dalcin    for opt in options:
172cb58ab5bSLisandro Dalcin        log.info(' '*4 + opt)
17359e0f383SLisandro Dalcin    # Run PETSc installer
174cb58ab5bSLisandro Dalcin    if dry_run: return
175367c215cSLisandro Dalcin    use_install_py = True
176367c215cSLisandro Dalcin    if use_install_py:
177105e34d4SBarry Smith        import install
17865a891e7SLisandro Dalcin        install.Installer(options).run()
17965a891e7SLisandro Dalcin        import logger
18065a891e7SLisandro Dalcin        logger.Logger.defaultLog = None
181367c215cSLisandro Dalcin    else:
182367c215cSLisandro Dalcin        make = find_executable('make')
18396fd8cd7SLisandro Dalcin        command = [make, 'install', 'DESTDIR='+dest_dir]
18496fd8cd7SLisandro Dalcin        status = os.system(" ".join(command))
185367c215cSLisandro Dalcin        if status != 0: raise RuntimeError(status)
18699468c80SLisandro Dalcin
18796fd8cd7SLisandro Dalcinclass context(object):
18899468c80SLisandro Dalcin    def __init__(self):
18999468c80SLisandro Dalcin        self.sys_argv = sys.argv[:]
19099468c80SLisandro Dalcin        self.wdir = os.getcwd()
19199468c80SLisandro Dalcin    def enter(self):
19299468c80SLisandro Dalcin        del sys.argv[1:]
19399468c80SLisandro Dalcin        pdir = os.environ['PETSC_DIR']
19499468c80SLisandro Dalcin        os.chdir(pdir)
19599468c80SLisandro Dalcin        return self
19699468c80SLisandro Dalcin    def exit(self):
19799468c80SLisandro Dalcin        sys.argv[:] = self.sys_argv
19899468c80SLisandro Dalcin        os.chdir(self.wdir)
199105e34d4SBarry Smith
20065a891e7SLisandro Dalcinclass cmd_install(_install):
20165a891e7SLisandro Dalcin
20241716173SLisandro Dalcin    def initialize_options(self):
20341716173SLisandro Dalcin        _install.initialize_options(self)
20441716173SLisandro Dalcin        self.optimize = 1
20541716173SLisandro Dalcin
20689031a3cSLisandro Dalcin    def finalize_options(self):
20789031a3cSLisandro Dalcin        _install.finalize_options(self)
20889031a3cSLisandro Dalcin        self.install_lib = self.install_platlib
20989031a3cSLisandro Dalcin        self.install_libbase = self.install_lib
21089031a3cSLisandro Dalcin
21165a891e7SLisandro Dalcin    def run(self):
21289031a3cSLisandro Dalcin        root_dir = os.path.abspath(self.install_lib)
21396fd8cd7SLisandro Dalcin        dest_dir = prefix = os.path.join(root_dir, 'petsc')
21499468c80SLisandro Dalcin        #
21599468c80SLisandro Dalcin        ctx = context().enter()
21665a891e7SLisandro Dalcin        try:
21796fd8cd7SLisandro Dalcin            config(prefix, self.dry_run)
21896fd8cd7SLisandro Dalcin            build(self.dry_run)
21996fd8cd7SLisandro Dalcin            install(dest_dir, self.dry_run)
22065a891e7SLisandro Dalcin        finally:
22199468c80SLisandro Dalcin            ctx.exit()
22296fd8cd7SLisandro Dalcin        #
22396fd8cd7SLisandro Dalcin        self.outputs = []
22496fd8cd7SLisandro Dalcin        for dirpath, _, filenames in os.walk(dest_dir):
22596fd8cd7SLisandro Dalcin            for fn in filenames:
22696fd8cd7SLisandro Dalcin                self.outputs.append(os.path.join(dirpath, fn))
22796fd8cd7SLisandro Dalcin        #
22896fd8cd7SLisandro Dalcin        _install.run(self)
22965a891e7SLisandro Dalcin
23096fd8cd7SLisandro Dalcin    def get_outputs(self):
23196fd8cd7SLisandro Dalcin        outputs = getattr(self, 'outputs', [])
23296fd8cd7SLisandro Dalcin        outputs += _install.get_outputs(self)
23396fd8cd7SLisandro Dalcin        return outputs
234a32381aeSLisandro Dalcin
23565a891e7SLisandro Dalcindef version():
2367d04d9c9SLisandro Dalcin    import re
2377d04d9c9SLisandro Dalcin    version_re = {
2387d04d9c9SLisandro Dalcin        'major'  : re.compile(r"#define\s+PETSC_VERSION_MAJOR\s+(\d+)"),
2397d04d9c9SLisandro Dalcin        'minor'  : re.compile(r"#define\s+PETSC_VERSION_MINOR\s+(\d+)"),
2407d04d9c9SLisandro Dalcin        'micro'  : re.compile(r"#define\s+PETSC_VERSION_SUBMINOR\s+(\d+)"),
2417d04d9c9SLisandro Dalcin        'patch'  : re.compile(r"#define\s+PETSC_VERSION_PATCH\s+(\d+)"),
2427d04d9c9SLisandro Dalcin        'release': re.compile(r"#define\s+PETSC_VERSION_RELEASE\s+(\d+)"),
2437d04d9c9SLisandro Dalcin        }
2447d04d9c9SLisandro Dalcin    petscversion_h = os.path.join('include','petscversion.h')
24596fd8cd7SLisandro Dalcin    data = open(petscversion_h, 'r').read()
2467d04d9c9SLisandro Dalcin    major = int(version_re['major'].search(data).groups()[0])
2477d04d9c9SLisandro Dalcin    minor = int(version_re['minor'].search(data).groups()[0])
2487d04d9c9SLisandro Dalcin    micro = int(version_re['micro'].search(data).groups()[0])
2497d04d9c9SLisandro Dalcin    patch = int(version_re['patch'].search(data).groups()[0])
2507d04d9c9SLisandro Dalcin    release = int(version_re['release'].search(data).groups()[0])
2517d04d9c9SLisandro Dalcin    if release:
2527d04d9c9SLisandro Dalcin        v = "%d.%d" % (major, minor)
2537d04d9c9SLisandro Dalcin        if micro > 0:
2547d04d9c9SLisandro Dalcin            v += ".%d" % micro
255247a1238SLisandro Dalcin        #if patch > 0:
256247a1238SLisandro Dalcin        #    v += ".post%d" % patch
2577d04d9c9SLisandro Dalcin    else:
25861a717f9SLisandro Dalcin        v = "%d.%d.dev%d" % (major, minor+1, 0)
2597d04d9c9SLisandro Dalcin    return v
26059e0f383SLisandro Dalcin
26165a891e7SLisandro Dalcindef tarball():
26250f36069SLisandro Dalcin    VERSION = version()
26350f36069SLisandro Dalcin    if '.dev' in VERSION:
264a32381aeSLisandro Dalcin        return None
2657d562c6eSLisandro Dalcin    bits = VERSION.split('.')
2667d562c6eSLisandro Dalcin    if len(bits) == 2: bits.append('0')
267247a1238SLisandro Dalcin    PETSC_VERSION = '.'.join(bits[:3])
26850f36069SLisandro Dalcin    return ('http://ftp.mcs.anl.gov/pub/petsc/release-snapshots/'
269a9157d91SLisandro Dalcin            'petsc-lite-%s.tar.gz#egg=petsc-%s' % (PETSC_VERSION, VERSION))
27065a891e7SLisandro Dalcin
27165a891e7SLisandro Dalcindescription = __doc__.split('\n')[1:-1]; del description[1:3]
27265a891e7SLisandro Dalcinclassifiers = """
27396fd8cd7SLisandro DalcinDevelopment Status :: 5 - Production/Stable
27465a891e7SLisandro DalcinIntended Audience :: Developers
27565a891e7SLisandro DalcinIntended Audience :: Science/Research
27696fd8cd7SLisandro DalcinLicense :: OSI Approved :: BSD License
27796fd8cd7SLisandro DalcinOperating System :: POSIX
27865a891e7SLisandro DalcinProgramming Language :: C
27965a891e7SLisandro DalcinProgramming Language :: C++
28065a891e7SLisandro DalcinProgramming Language :: Fortran
28165a891e7SLisandro DalcinProgramming Language :: Python
28265a891e7SLisandro DalcinTopic :: Scientific/Engineering
28365a891e7SLisandro DalcinTopic :: Software Development :: Libraries
28465a891e7SLisandro Dalcin"""
28565a891e7SLisandro Dalcin
28665a891e7SLisandro Dalcinbootstrap()
28765a891e7SLisandro Dalcinsetup(name='petsc',
28865a891e7SLisandro Dalcin      version=version(),
28965a891e7SLisandro Dalcin      description=description.pop(0),
29065a891e7SLisandro Dalcin      long_description='\n'.join(description),
29165a891e7SLisandro Dalcin      classifiers= classifiers.split('\n')[1:-1],
29265a891e7SLisandro Dalcin      keywords = ['PETSc', 'MPI'],
29365a891e7SLisandro Dalcin      platforms=['POSIX'],
29465a891e7SLisandro Dalcin      license='PETSc',
29565a891e7SLisandro Dalcin
29665a891e7SLisandro Dalcin      url='http://www.mcs.anl.gov/petsc/',
29765a891e7SLisandro Dalcin      download_url=tarball(),
29865a891e7SLisandro Dalcin
29965a891e7SLisandro Dalcin      author='PETSc Team',
30099468c80SLisandro Dalcin      author_email='petsc-maint@mcs.anl.gov',
30165a891e7SLisandro Dalcin      maintainer='Lisandro Dalcin',
30265a891e7SLisandro Dalcin      maintainer_email='dalcinl@gmail.com',
30365a891e7SLisandro Dalcin
30465a891e7SLisandro Dalcin      packages = ['petsc'],
3059fb7a39fSLisandro Dalcin      package_dir = {'petsc': 'config/pypi'},
30696fd8cd7SLisandro Dalcin      cmdclass={'install': cmd_install},
30759e0f383SLisandro Dalcin      **metadata)
308