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