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