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 = False 139 if use_config_py: 140 import configure 141 configure.petsc_configure(options) 142 import logger 143 logger.Logger.defaultLog = None 144 else: 145 python = find_executable('python2') or find_executable('python') 146 command = [python, './configure'] + options 147 status = os.system(" ".join(command)) 148 if status != 0: raise RuntimeError(status) 149 150def build(dry_run=False): 151 log.info('PETSc: build') 152 # Run PETSc build 153 if dry_run: return 154 use_builder_py = False 155 if use_builder_py: 156 import builder 157 builder.PETScMaker().run() 158 import logger 159 logger.Logger.defaultLog = None 160 else: 161 make = find_executable('make') 162 command = [make, 'all'] 163 status = os.system(" ".join(command)) 164 if status != 0: raise RuntimeError(status) 165 166def install(dry_run=False): 167 log.info('PETSc: install') 168 # Run PETSc installer 169 if dry_run: return 170 use_install_py = False 171 if use_install_py: 172 import install 173 install.Installer().run() 174 import logger 175 logger.Logger.defaultLog = None 176 else: 177 make = find_executable('make') 178 command = [make, 'install'] 179 status = os.system(" ".join(command)) 180 if status != 0: raise RuntimeError(status) 181 182class context(object): 183 def __init__(self): 184 self.sys_argv = sys.argv[:] 185 self.wdir = os.getcwd() 186 def enter(self): 187 del sys.argv[1:] 188 pdir = os.environ['PETSC_DIR'] 189 os.chdir(pdir) 190 return self 191 def exit(self): 192 sys.argv[:] = self.sys_argv 193 os.chdir(self.wdir) 194 195class cmd_install(_install): 196 197 def initialize_options(self): 198 _install.initialize_options(self) 199 self.optimize = 1 200 201 def finalize_options(self): 202 _install.finalize_options(self) 203 self.install_lib = self.install_platlib 204 self.install_libbase = self.install_lib 205 206 def run(self): 207 root_dir = os.path.abspath(self.install_lib) 208 prefix = os.path.join(root_dir, 'petsc') 209 # 210 ctx = context().enter() 211 try: 212 config(prefix, self.dry_run) 213 build(self.dry_run) 214 install(self.dry_run) 215 finally: 216 ctx.exit() 217 # 218 self.outputs = [] 219 for dirpath, _, filenames in os.walk(prefix): 220 for fn in filenames: 221 self.outputs.append(os.path.join(dirpath, fn)) 222 # 223 _install.run(self) 224 225 def get_outputs(self): 226 outputs = getattr(self, 'outputs', []) 227 outputs += _install.get_outputs(self) 228 return outputs 229 230def version(): 231 import re 232 version_re = { 233 'major' : re.compile(r"#define\s+PETSC_VERSION_MAJOR\s+(\d+)"), 234 'minor' : re.compile(r"#define\s+PETSC_VERSION_MINOR\s+(\d+)"), 235 'micro' : re.compile(r"#define\s+PETSC_VERSION_SUBMINOR\s+(\d+)"), 236 'release': re.compile(r"#define\s+PETSC_VERSION_RELEASE\s+([-]*\d+)"), 237 } 238 petscversion_h = os.path.join('include','petscversion.h') 239 data = open(petscversion_h, 'r').read() 240 major = int(version_re['major'].search(data).groups()[0]) 241 minor = int(version_re['minor'].search(data).groups()[0]) 242 micro = int(version_re['micro'].search(data).groups()[0]) 243 release = int(version_re['release'].search(data).groups()[0]) 244 if release > 0 : 245 v = "%d.%d.%d" % (major, minor, micro) 246 else: 247 v = "%d.%d.0.dev%d" % (major, minor+1, 0) 248 return v 249 250def tarball(): 251 VERSION = version() 252 if '.dev' in VERSION: return None 253 return ('http://ftp.mcs.anl.gov/pub/petsc/release-snapshots/' 254 'petsc-lite-%s.tar.gz#egg=petsc-%s' % (VERSION, VERSION)) 255 256description = __doc__.split('\n')[1:-1]; del description[1:3] 257classifiers = """ 258Development Status :: 5 - Production/Stable 259Intended Audience :: Developers 260Intended Audience :: Science/Research 261License :: OSI Approved :: BSD License 262Operating System :: POSIX 263Programming Language :: C 264Programming Language :: C++ 265Programming Language :: Fortran 266Programming Language :: Python 267Topic :: Scientific/Engineering 268Topic :: Software Development :: Libraries 269""" 270 271if 'bdist_wheel' in sys.argv: 272 sys.stderr.write("petsc: this package cannot be built as a wheel\n") 273 sys.exit(1) 274 275bootstrap() 276setup(name='petsc', 277 version=version(), 278 description=description.pop(0), 279 long_description='\n'.join(description), 280 classifiers= classifiers.split('\n')[1:-1], 281 keywords = ['PETSc', 'MPI'], 282 platforms=['POSIX'], 283 license='BSD', 284 285 url='http://www.mcs.anl.gov/petsc/', 286 download_url=tarball(), 287 288 author='PETSc Team', 289 author_email='petsc-maint@mcs.anl.gov', 290 maintainer='Lisandro Dalcin', 291 maintainer_email='dalcinl@gmail.com', 292 293 packages = ['petsc'], 294 package_dir = {'petsc': 'config/pypi'}, 295 cmdclass={'install': cmd_install}, 296 **metadata) 297