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