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