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