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