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.. tip:: 14 15 You can also install `petsc-master`_ with:: 16 17 $ pip install petsc==master 18 19 .. _petsc-master: https://bitbucket.org/petsc/ 20 petsc/get/master.tar.gz#egg=petsc-master 21""" 22 23import sys, os 24from distutils.core import setup 25from distutils.util import get_platform, split_quoted 26from distutils.spawn import find_executable 27from distutils.command.build import build as _build 28if 'setuptools' in sys.modules: 29 from setuptools.command.install import install as _install 30else: 31 from distutils.command.install import install as _install 32from distutils.command.sdist import sdist as _sdist 33from distutils import log 34 35init_py = """\ 36# Author: PETSc Team 37# Contact: petsc-maint@mcs.anl.gov 38 39def get_petsc_dir(): 40 import os 41 return os.path.dirname(__file__) 42 43def get_config(): 44 conf = {} 45 conf['PETSC_DIR'] = get_petsc_dir() 46 return conf 47""" 48 49metadata = { 50 'provides' : ['petsc'], 51 'requires' : [], 52} 53 54def bootstrap(): 55 # Set PETSC_DIR and PETSC_ARCH 56 PETSC_DIR = os.path.abspath(os.getcwd()) 57 PETSC_ARCH = get_platform() + '-python' 58 os.environ['PETSC_DIR'] = PETSC_DIR 59 os.environ['PETSC_ARCH'] = PETSC_ARCH 60 sys.path.insert(0, os.path.join(PETSC_DIR, 'config')) 61 sys.path.insert(0, os.path.join(PETSC_DIR, 'conf')) 62 # Generate package __init__.py file 63 from distutils.dir_util import mkpath 64 pkgdir = os.path.join('config', 'pypi') 65 if not os.path.exists(pkgdir): mkpath(pkgdir) 66 pkgfile = os.path.join(pkgdir, '__init__.py') 67 fh = open(pkgfile, 'wt') 68 fh.write(init_py) 69 fh.close() 70 # Simple-minded lookup for MPI and mpi4py 71 mpi4py = mpicc = None 72 try: 73 import mpi4py 74 conf = mpi4py.get_config() 75 mpicc = conf.get('mpicc') 76 except ImportError: # mpi4py is not installed 77 mpi4py = None 78 mpicc = os.environ.get('MPICC') or find_executable('mpicc') 79 except AttributeError: # mpi4py is too old 80 pass 81 if ('setuptools' in sys.modules): 82 metadata['zip_safe'] = False 83 if not mpi4py and mpicc: 84 metadata['install_requires']= ['mpi4py>=1.2.2'] 85 86def config(dry_run=False): 87 log.info('PETSc: configure') 88 options = [ 89 'PETSC_ARCH='+os.environ['PETSC_ARCH'], 90 '--with-shared-libraries=1', 91 '--with-debugging=0', 92 '--with-c2html=0', # not needed 93 '--with-sowing=0', 94 '--with-fc=0', 95 '--with-cxx=0', 96 #'--with-cmake=0', 97 ] 98 # MPI 99 try: 100 import mpi4py 101 conf = mpi4py.get_config() 102 mpicc = conf.get('mpicc') 103 mpicxx = conf.get('mpicxx') 104 mpif90 = conf.get('mpif90') 105 except (ImportError, AttributeError): 106 mpicc = os.environ.get('MPICC') or find_executable('mpicc') 107 mpicxx = os.environ.get('MPICXX') or find_executable('mpicxx') 108 mpif90 = os.environ.get('MPIF90') or find_executable('mpif90') 109 if mpicc: 110 options.append('--with-cc='+mpicc) 111 if mpicxx: 112 options.append('--with-cxx='+mpicxx) 113 if mpif90: 114 options.append('--with-fc='+mpif90) 115 else: 116 options.append('--with-mpi=0') 117 # Extra configure options 118 config_opts = os.environ.get('PETSC_CONFIGURE_OPTIONS', '') 119 config_opts = split_quoted(config_opts) 120 options.extend(config_opts) 121 log.info('configure options:') 122 for opt in options: 123 log.info(' '*4 + opt) 124 # Run PETSc configure 125 if dry_run: return 126 import configure 127 configure.petsc_configure(options) 128 import logger 129 logger.Logger.defaultLog = None 130 131def build(dry_run=False): 132 log.info('PETSc: build') 133 # Run PETSc build 134 if dry_run: return 135 use_builder_py = False 136 if use_builder_py: 137 import builder 138 builder.PETScMaker().run() 139 import logger 140 logger.Logger.defaultLog = None 141 else: 142 make = find_executable('make') 143 status = os.system(" ".join( 144 [make, 'all'] 145 )) 146 if status != 0: raise RuntimeError(status) 147 148def install(dest_dir, prefix=None, dry_run=False): 149 log.info('PETSc: install') 150 if prefix is None: 151 prefix = dest_dir 152 options = [ 153 '--destDir=' + dest_dir, 154 '--prefix=' + prefix, 155 ] 156 log.info('install options:') 157 for opt in options: 158 log.info(' '*4 + opt) 159 # Run PETSc installer 160 if dry_run: return 161 use_install_py = True 162 if use_install_py: 163 import install 164 install.Installer(options).run() 165 import logger 166 logger.Logger.defaultLog = None 167 else: 168 make = find_executable('make') 169 status = os.system(" ".join( 170 [make, 'install', 'DESTDIR='+dest_dir] 171 )) 172 if status != 0: raise RuntimeError(status) 173 174class context: 175 def __init__(self): 176 self.sys_argv = sys.argv[:] 177 self.wdir = os.getcwd() 178 def enter(self): 179 del sys.argv[1:] 180 pdir = os.environ['PETSC_DIR'] 181 os.chdir(pdir) 182 return self 183 def exit(self): 184 sys.argv[:] = self.sys_argv 185 os.chdir(self.wdir) 186 187class cmd_build(_build): 188 189 def initialize_options(self): 190 _build.initialize_options(self) 191 PETSC_ARCH = os.environ.get('PETSC_ARCH', '') 192 self.build_base = os.path.join(PETSC_ARCH, 'build-python') 193 194 def run(self): 195 _build.run(self) 196 ctx = context().enter() 197 try: 198 config(self.dry_run) 199 build(self.dry_run) 200 finally: 201 ctx.exit() 202 203class cmd_install(_install): 204 205 def initialize_options(self): 206 _install.initialize_options(self) 207 self.optimize = 1 208 209 def run(self): 210 root_dir = self.install_platlib 211 dest_dir = os.path.join(root_dir, 'petsc') 212 bdist_base = self.get_finalized_command('bdist').bdist_base 213 if dest_dir.startswith(bdist_base): 214 prefix = dest_dir[len(bdist_base)+1:] 215 prefix = prefix[prefix.index(os.path.sep):] 216 else: 217 prefix = dest_dir 218 dest_dir = os.path.abspath(dest_dir) 219 prefix = os.path.abspath(prefix) 220 # 221 _install.run(self) 222 ctx = context().enter() 223 try: 224 install(dest_dir, prefix, self.dry_run) 225 finally: 226 ctx.exit() 227 228class cmd_sdist(_sdist): 229 230 def initialize_options(self): 231 _sdist.initialize_options(self) 232 self.force_manifest = 1 233 self.template = os.path.join('config', 'manifest.in') 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, 'rt').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 = """ 273License :: Public Domain 274Operating System :: POSIX 275Intended Audience :: Developers 276Intended Audience :: Science/Research 277Programming Language :: C 278Programming Language :: C++ 279Programming Language :: Fortran 280Programming Language :: Python 281Topic :: Scientific/Engineering 282Topic :: Software Development :: Libraries 283""" 284 285bootstrap() 286setup(name='petsc', 287 version=version(), 288 description=description.pop(0), 289 long_description='\n'.join(description), 290 classifiers= classifiers.split('\n')[1:-1], 291 keywords = ['PETSc', 'MPI'], 292 platforms=['POSIX'], 293 license='PETSc', 294 295 url='http://www.mcs.anl.gov/petsc/', 296 download_url=tarball(), 297 298 author='PETSc Team', 299 author_email='petsc-maint@mcs.anl.gov', 300 maintainer='Lisandro Dalcin', 301 maintainer_email='dalcinl@gmail.com', 302 303 packages = ['petsc'], 304 package_dir = {'petsc': 'config/pypi'}, 305 cmdclass={ 306 'build': cmd_build, 307 'install': cmd_install, 308 'sdist': cmd_sdist, 309 }, 310 **metadata) 311