xref: /petsc/setup.py (revision 1e7f0bbd89554c5717318213f39da4ca60fd3e71)
1#!/usr/bin/env python
2
3"""
4PETSc: Portable, Extensible Toolkit for Scientific Computation
5==============================================================
6
7The Portable, Extensible Toolkit for Scientific Computation (PETSc),
8is a suite of data structures and routines for the scalable (parallel)
9solution of scientific applications modeled by partial differential
10equations. It employs the Message Passing Interface (MPI) standard for
11all message-passing communication.
12"""
13
14import sys, os
15from distutils.core import setup
16from distutils.util import get_platform
17from distutils.spawn import find_executable
18from distutils.command.build import build as _build
19if 'setuptools' in sys.modules:
20    from setuptools.command.install import install as _install
21else:
22    from distutils.command.install import install as _install
23from distutils.command.sdist import sdist as _sdist
24from distutils import log
25
26init_py = """\
27# Author:  PETSc Team
28# Contact: petsc-maint@mcs.anl.gov
29
30def get_petsc_dir():
31    import os
32    return os.path.dirname(__file__)
33
34def get_config():
35    conf = {}
36    conf['PETSC_DIR'] = get_petsc_dir()
37    return conf
38"""
39
40metadata = {
41    'provides' : ['petsc'],
42    'requires' : [],
43}
44
45def bootstrap():
46    # Set PETSC_DIR and PETSC_ARCH,
47    PETSC_DIR  = os.path.abspath(os.getcwd())
48    PETSC_ARCH = get_platform() + '-python'
49    os.environ['PETSC_DIR']  = PETSC_DIR
50    os.environ['PETSC_ARCH'] = PETSC_ARCH
51    # Generate package __init__.py file
52    from distutils.dir_util import mkpath
53    pkgdir = os.path.join('config', 'pypi')
54    pkgfile = os.path.join(pkgdir, '__init__.py')
55    if not os.path.exists(pkgdir):
56        mkpath(pkgdir)
57    if not os.path.exists(pkgfile):
58        open(pkgfile, 'wt').write(init_py)
59    # Simple-minded lookup for MPI and mpi4py
60    mpi4py = mpicc = None
61    try:
62        import mpi4py
63        conf = mpi4py.get_config()
64        mpicc = conf.get('mpicc')
65    except ImportError: # mpi4py is not installed
66        mpicc = os.environ.get('MPICC') or find_executable('mpicc')
67    except AttributeError: # mpi4py is too old
68        pass
69    if not mpi4py and mpicc:
70        if (('distribute' in sys.modules) or
71            ('setuptools' in sys.modules)):
72            metadata['install_requires']= ['mpi4py>=1.2.2']
73    if 'setuptools' in sys.modules:
74        metadata['zip_safe'] = False
75
76def config(dry_run=False):
77    log.info('PETSc: configure')
78    if dry_run: return
79    options = [
80        'PETSC_ARCH='+os.environ['PETSC_ARCH'],
81        '--with-debugging=0',
82        '--with-shared',
83        '--with-cmake=0', # not needed
84        ]
85    # MPI
86    try:
87        import mpi4py
88        conf = mpi4py.get_config()
89        mpicc = conf.get('mpicc')
90    except (ImportError, AttributeError):
91        mpicc = os.environ.get('MPICC') or find_executable('mpicc')
92    if mpicc:
93        options.append('--with-cc='+mpicc)
94    else:
95        options.append('--with-mpi=0')
96    options.append('--with-cxx=0') # XXX mpicxx?
97    options.append('--with-fc=0')  # XXX mpif90?
98    # Run PETSc configure
99    status = os.system('%s %s %s' % (
100            find_executable('python'),
101            os.path.join('config', 'configure.py'),
102            ' '.join(options),
103            ))
104    if status != 0: raise RuntimeError(status)
105
106def build(dry_run=False):
107    log.info('PETSc: build')
108    if dry_run: return
109    # Run PETSc builder
110    status = os.system('make all')
111    if status != 0: raise RuntimeError(status)
112
113def install(dest_dir, prefix=None, dry_run=False):
114    log.info('PETSc: install')
115    if dry_run: return
116    if prefix is None:
117        prefix = dest_dir
118    options = [
119        '--destDir=' + dest_dir,
120        '--prefix='  + prefix,
121        ]
122    # Run PETSc installer
123    status = os.system('%s %s %s' % (
124            find_executable('python'),
125            os.path.join('config', 'install.py'),
126            ' '.join(options),
127            ))
128    if status != 0: raise RuntimeError(status)
129
130class context:
131    def __init__(self):
132        self.sys_argv = sys.argv[:]
133        self.wdir = os.getcwd()
134    def enter(self):
135        del sys.argv[1:]
136        pdir = os.environ['PETSC_DIR']
137        os.chdir(pdir)
138        return self
139    def exit(self):
140        sys.argv[:] = self.sys_argv
141        os.chdir(self.wdir)
142
143class cmd_build(_build):
144
145    def initialize_options(self):
146        _build.initialize_options(self)
147        PETSC_ARCH = os.environ.get('PETSC_ARCH', '')
148        self.build_base = os.path.join(PETSC_ARCH, 'build-python')
149
150    def run(self):
151        _build.run(self)
152        ctx = context().enter()
153        try:
154            config(self.dry_run)
155            build(self.dry_run)
156        finally:
157            ctx.exit()
158
159class cmd_install(_install):
160
161    def initialize_options(self):
162        _install.initialize_options(self)
163        self.optimize = 1
164
165    def run(self):
166        root_dir = self.install_platlib
167        dest_dir = os.path.join(root_dir, 'petsc')
168        bdist_base = self.get_finalized_command('bdist').bdist_base
169        if dest_dir.startswith(bdist_base):
170            prefix = dest_dir[len(bdist_base)+1:]
171            prefix = prefix[prefix.index(os.path.sep):]
172        else:
173            prefix = dest_dir
174        dest_dir = os.path.abspath(dest_dir)
175        prefix   = os.path.abspath(prefix)
176        #
177        _install.run(self)
178        ctx = context().enter()
179        try:
180            install(dest_dir, prefix, self.dry_run)
181        finally:
182            ctx.exit()
183
184class cmd_sdist(_sdist):
185
186    def initialize_options(self):
187        _sdist.initialize_options(self)
188        self.force_manifest = 1
189        self.template = os.path.join('config', 'manifest.in')
190
191def version():
192    import re
193    version_re = {
194        'major'  : re.compile(r"#define\s+PETSC_VERSION_MAJOR\s+(\d+)"),
195        'minor'  : re.compile(r"#define\s+PETSC_VERSION_MINOR\s+(\d+)"),
196        'micro'  : re.compile(r"#define\s+PETSC_VERSION_SUBMINOR\s+(\d+)"),
197        'patch'  : re.compile(r"#define\s+PETSC_VERSION_PATCH\s+(\d+)"),
198        'release': re.compile(r"#define\s+PETSC_VERSION_RELEASE\s+(\d+)"),
199        }
200    petscversion_h = os.path.join('include','petscversion.h')
201    data = open(petscversion_h, 'rt').read()
202    major = int(version_re['major'].search(data).groups()[0])
203    minor = int(version_re['minor'].search(data).groups()[0])
204    micro = int(version_re['micro'].search(data).groups()[0])
205    patch = int(version_re['patch'].search(data).groups()[0])
206    release = int(version_re['release'].search(data).groups()[0])
207    if release:
208        v = "%d.%d" % (major, minor)
209        if micro > 0:
210            v += ".%d" % micro
211        if patch > 0:
212            v += ".post%d" % patch
213    else:
214        v = "%d.%d.dev%d" % (major, minor+1, 0)
215    return v
216
217def tarball():
218    VERSION = version()
219    if '.dev' in VERSION:
220        return None
221    if '.post' not in VERSION:
222        VERSION = VERSION + '.post0'
223    VERSION = VERSION.replace('.post', '-p')
224    return ('http://ftp.mcs.anl.gov/pub/petsc/release-snapshots/'
225            'petsc-lite-%s.tar.gz' % VERSION)
226
227description = __doc__.split('\n')[1:-1]; del description[1:3]
228classifiers = """
229License :: Public Domain
230Operating System :: POSIX
231Intended Audience :: Developers
232Intended Audience :: Science/Research
233Programming Language :: C
234Programming Language :: C++
235Programming Language :: Fortran
236Programming Language :: Python
237Topic :: Scientific/Engineering
238Topic :: Software Development :: Libraries
239"""
240
241bootstrap()
242setup(name='petsc',
243      version=version(),
244      description=description.pop(0),
245      long_description='\n'.join(description),
246      classifiers= classifiers.split('\n')[1:-1],
247      keywords = ['PETSc', 'MPI'],
248      platforms=['POSIX'],
249      license='PETSc',
250
251      url='http://www.mcs.anl.gov/petsc/',
252      download_url=tarball(),
253
254      author='PETSc Team',
255      author_email='petsc-maint@mcs.anl.gov',
256      maintainer='Lisandro Dalcin',
257      maintainer_email='dalcinl@gmail.com',
258
259      packages = ['petsc'],
260      package_dir = {'petsc': 'config/pypi'},
261      cmdclass={
262        'build': cmd_build,
263        'install': cmd_install,
264        'sdist': cmd_sdist,
265        },
266      **metadata)
267