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