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 # Generate package __init__.py file 52 from distutils.dir_util import mkpath 53 pkgdir = os.path.join('config', 'pypi') 54 pkgfile = os.path.join(pkgdir, '__init__.py') 55 if not os.path.exists(pkgdir): 56 mkpath(pkgdir) 57 if not os.path.exists(pkgfile): 58 open(pkgfile, 'wt').write(init_py) 59 # Simple-minded lookup for MPI and mpi4py 60 mpi4py = mpicc = None 61 try: 62 import mpi4py 63 conf = mpi4py.get_config() 64 mpicc = conf.get('mpicc') 65 except ImportError: # mpi4py is not installed 66 mpicc = os.environ.get('MPICC') or find_executable('mpicc') 67 except AttributeError: # mpi4py is too old 68 pass 69 if not mpi4py and mpicc: 70 if (('distribute' in sys.modules) or 71 ('setuptools' in sys.modules)): 72 metadata['install_requires']= ['mpi4py>=1.2.2'] 73 if 'setuptools' in sys.modules: 74 metadata['zip_safe'] = False 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', 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 status = os.system('%s %s %s' % ( 99 find_executable('python'), 100 os.path.join('config', 'configure.py'), 101 ' '.join(options), 102 )) 103 if status != 0: raise RuntimeError(status) 104 105def build(dry_run=False): 106 log.info('PETSc: build') 107 if dry_run: return 108 # Run PETSc builder 109 status = os.system('make all') 110 if status != 0: raise RuntimeError(status) 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 status = os.system('%s %s %s' % ( 123 find_executable('python'), 124 os.path.join('config', 'install.py'), 125 ' '.join(options), 126 )) 127 if status != 0: raise RuntimeError(status) 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