xref: /petsc/setup.py (revision 2b26979f2976cb8840d2aed9f03519841c1cab77)
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.. note::
14
15   To install ``PETSc`` and ``petsc4py`` (``mpi4py`` is optional
16   but highly recommended) use::
17
18     $ pip install numpy mpi4py
19     $ pip install petsc petsc4py
20
21.. tip::
22
23  You can also install the in-development versions with::
24
25    $ pip install Cython numpy mpi4py
26    $ pip install --no-deps https://bitbucket.org/petsc/petsc/get/master.tar.gz
27    $ pip install --no-deps https://bitbucket.org/petsc/petsc4py/get/master.tar.gz
28
29"""
30
31import sys, os
32from distutils.core import setup
33from distutils.util import get_platform, split_quoted
34from distutils.spawn import find_executable
35from distutils.command.build import build as _build
36if 'setuptools' in sys.modules:
37    from setuptools.command.install import install as _install
38else:
39    from distutils.command.install import install as _install
40from distutils.command.sdist import sdist as _sdist
41from distutils import log
42
43init_py = """\
44# Author:  PETSc Team
45# Contact: petsc-maint@mcs.anl.gov
46
47def get_petsc_dir():
48    import os
49    return os.path.dirname(__file__)
50
51def get_config():
52    conf = {}
53    conf['PETSC_DIR'] = get_petsc_dir()
54    return conf
55"""
56
57metadata = {
58    'provides' : ['petsc'],
59    'requires' : [],
60}
61
62def bootstrap():
63    # Set PETSC_DIR and PETSC_ARCH
64    PETSC_DIR  = os.path.abspath(os.getcwd())
65    PETSC_ARCH = get_platform() + '-python'
66    os.environ['PETSC_DIR']  = PETSC_DIR
67    os.environ['PETSC_ARCH'] = PETSC_ARCH
68    sys.path.insert(0, os.path.join(PETSC_DIR, 'config'))
69    sys.path.insert(0, os.path.join(PETSC_DIR, 'lib','petsc-conf'))
70    # Generate package __init__.py file
71    from distutils.dir_util import mkpath
72    pkgdir = os.path.join('config', 'pypi')
73    if not os.path.exists(pkgdir): mkpath(pkgdir)
74    pkgfile = os.path.join(pkgdir, '__init__.py')
75    fh = open(pkgfile, 'wt')
76    fh.write(init_py)
77    fh.close()
78    # Simple-minded lookup for MPI and mpi4py
79    mpi4py = mpicc = None
80    try:
81        import mpi4py
82        conf = mpi4py.get_config()
83        mpicc = conf.get('mpicc')
84    except ImportError: # mpi4py is not installed
85        mpi4py = None
86        mpicc = os.environ.get('MPICC') or find_executable('mpicc')
87    except AttributeError: # mpi4py is too old
88        pass
89    if ('setuptools' in sys.modules):
90        metadata['zip_safe'] = False
91        if not mpi4py and mpicc:
92            metadata['install_requires']= ['mpi4py>=1.2.2']
93
94def config(dry_run=False):
95    log.info('PETSc: configure')
96    options = [
97        'PETSC_ARCH='+os.environ['PETSC_ARCH'],
98        '--with-shared-libraries=1',
99        '--with-debugging=0',
100        '--with-c2html=0', # not needed
101        ]
102    # MPI
103    try:
104        import mpi4py
105        conf = mpi4py.get_config()
106        mpicc  = conf.get('mpicc')
107        mpicxx = conf.get('mpicxx')
108        mpif90 = conf.get('mpif90')
109    except (ImportError, AttributeError):
110        mpicc  = os.environ.get('MPICC')  or find_executable('mpicc')
111        mpicxx = os.environ.get('MPICXX') or find_executable('mpicxx')
112        mpif90 = os.environ.get('MPIF90') or find_executable('mpif90')
113    if mpicc:
114        options.append('--with-cc='+mpicc)
115        if mpicxx:
116            options.append('--with-cxx='+mpicxx)
117        else:
118            options.append('--with-cxx=0')
119        if mpif90:
120            options.append('--with-fc='+mpif90)
121        else:
122            options.append('--with-fc=0')
123            options.append('--with-sowing=0')
124    else:
125        options.append('--with-mpi=0')
126    # Extra configure options
127    config_opts = os.environ.get('PETSC_CONFIGURE_OPTIONS', '')
128    config_opts = split_quoted(config_opts)
129    options.extend(config_opts)
130    log.info('configure options:')
131    for opt in options:
132        log.info(' '*4 + opt)
133    # Run PETSc configure
134    if dry_run: return
135    import configure
136    configure.petsc_configure(options)
137    import logger
138    logger.Logger.defaultLog = None
139
140def build(dry_run=False):
141    log.info('PETSc: build')
142    # Run PETSc build
143    if dry_run: return
144    use_builder_py = False
145    if use_builder_py:
146        import builder
147        builder.PETScMaker().run()
148        import logger
149        logger.Logger.defaultLog = None
150    else:
151        make = find_executable('make')
152        status = os.system(" ".join(
153                [make, 'all']
154                ))
155        if status != 0: raise RuntimeError(status)
156
157def install(dest_dir, prefix=None, dry_run=False):
158    log.info('PETSc: install')
159    if prefix is None:
160        prefix = dest_dir
161    options = [
162        '--destDir=' + dest_dir,
163        '--prefix='  + prefix,
164        ]
165    log.info('install options:')
166    for opt in options:
167        log.info(' '*4 + opt)
168    # Run PETSc installer
169    if dry_run: return
170    use_install_py = True
171    if use_install_py:
172        import install
173        install.Installer(options).run()
174        import logger
175        logger.Logger.defaultLog = None
176    else:
177        make = find_executable('make')
178        status = os.system(" ".join(
179                [make, 'install', 'DESTDIR='+dest_dir]
180                ))
181        if status != 0: raise RuntimeError(status)
182
183class context:
184    def __init__(self):
185        self.sys_argv = sys.argv[:]
186        self.wdir = os.getcwd()
187    def enter(self):
188        del sys.argv[1:]
189        pdir = os.environ['PETSC_DIR']
190        os.chdir(pdir)
191        return self
192    def exit(self):
193        sys.argv[:] = self.sys_argv
194        os.chdir(self.wdir)
195
196class cmd_build(_build):
197
198    def initialize_options(self):
199        _build.initialize_options(self)
200        PETSC_ARCH = os.environ.get('PETSC_ARCH', '')
201        self.build_base = os.path.join(PETSC_ARCH, 'build-python')
202
203    def run(self):
204        _build.run(self)
205        ctx = context().enter()
206        try:
207            config(self.dry_run)
208            build(self.dry_run)
209        finally:
210            ctx.exit()
211
212class cmd_install(_install):
213
214    def initialize_options(self):
215        _install.initialize_options(self)
216        self.optimize = 1
217
218    def run(self):
219        root_dir = self.install_platlib
220        dest_dir = os.path.join(root_dir, 'petsc')
221        bdist_base = self.get_finalized_command('bdist').bdist_base
222        if dest_dir.startswith(bdist_base):
223            prefix = dest_dir[len(bdist_base)+1:]
224            prefix = prefix[prefix.index(os.path.sep):]
225        else:
226            prefix = dest_dir
227        dest_dir = os.path.abspath(dest_dir)
228        prefix   = os.path.abspath(prefix)
229        #
230        _install.run(self)
231        ctx = context().enter()
232        try:
233            install(dest_dir, prefix, self.dry_run)
234        finally:
235            ctx.exit()
236
237class cmd_sdist(_sdist):
238
239    def initialize_options(self):
240        _sdist.initialize_options(self)
241        self.force_manifest = 1
242        self.template = os.path.join('config', 'manifest.in')
243
244def version():
245    import re
246    version_re = {
247        'major'  : re.compile(r"#define\s+PETSC_VERSION_MAJOR\s+(\d+)"),
248        'minor'  : re.compile(r"#define\s+PETSC_VERSION_MINOR\s+(\d+)"),
249        'micro'  : re.compile(r"#define\s+PETSC_VERSION_SUBMINOR\s+(\d+)"),
250        'patch'  : re.compile(r"#define\s+PETSC_VERSION_PATCH\s+(\d+)"),
251        'release': re.compile(r"#define\s+PETSC_VERSION_RELEASE\s+(\d+)"),
252        }
253    petscversion_h = os.path.join('include','petscversion.h')
254    data = open(petscversion_h, 'rt').read()
255    major = int(version_re['major'].search(data).groups()[0])
256    minor = int(version_re['minor'].search(data).groups()[0])
257    micro = int(version_re['micro'].search(data).groups()[0])
258    patch = int(version_re['patch'].search(data).groups()[0])
259    release = int(version_re['release'].search(data).groups()[0])
260    if release:
261        v = "%d.%d" % (major, minor)
262        if micro > 0:
263            v += ".%d" % micro
264        #if patch > 0:
265        #    v += ".post%d" % patch
266    else:
267        v = "%d.%d.dev%d" % (major, minor+1, 0)
268    return v
269
270def tarball():
271    VERSION = version()
272    if '.dev' in VERSION:
273        return None
274    bits = VERSION.split('.')
275    if len(bits) == 2: bits.append('0')
276    PETSC_VERSION = '.'.join(bits[:3])
277    return ('http://ftp.mcs.anl.gov/pub/petsc/release-snapshots/'
278            'petsc-lite-%s.tar.gz#egg=petsc-%s' % (PETSC_VERSION, VERSION))
279
280description = __doc__.split('\n')[1:-1]; del description[1:3]
281classifiers = """
282License :: Public Domain
283Operating System :: POSIX
284Intended Audience :: Developers
285Intended Audience :: Science/Research
286Programming Language :: C
287Programming Language :: C++
288Programming Language :: Fortran
289Programming Language :: Python
290Topic :: Scientific/Engineering
291Topic :: Software Development :: Libraries
292"""
293
294bootstrap()
295setup(name='petsc',
296      version=version(),
297      description=description.pop(0),
298      long_description='\n'.join(description),
299      classifiers= classifiers.split('\n')[1:-1],
300      keywords = ['PETSc', 'MPI'],
301      platforms=['POSIX'],
302      license='PETSc',
303
304      url='http://www.mcs.anl.gov/petsc/',
305      download_url=tarball(),
306
307      author='PETSc Team',
308      author_email='petsc-maint@mcs.anl.gov',
309      maintainer='Lisandro Dalcin',
310      maintainer_email='dalcinl@gmail.com',
311
312      packages = ['petsc'],
313      package_dir = {'petsc': 'config/pypi'},
314      cmdclass={
315        'build': cmd_build,
316        'install': cmd_install,
317        'sdist': cmd_sdist,
318        },
319      **metadata)
320