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