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