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