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