1#!/usr/bin/env python 2# Author: Lisandro Dalcin 3# Contact: dalcinl@gmail.com 4 5""" 6PETSc for Python 7""" 8 9import sys 10import os 11#try: 12# import setuptools 13#except ImportError: 14# pass 15 16 17# -------------------------------------------------------------------- 18# Metadata 19# -------------------------------------------------------------------- 20 21topdir = os.path.abspath(os.path.dirname(__file__)) 22 23from conf.metadata import metadata 24 25def name(): 26 return 'petsc4py' 27 28def version(): 29 import re 30 fh = open(os.path.join('src', '__init__.py')) 31 try: data = fh.read() 32 finally: fh.close() 33 m = re.search(r"__version__\s*=\s*'(.*)'", data) 34 return m.groups()[0] 35 36def description(): 37 f = open(os.path.join(topdir, 'DESCRIPTION.rst')) 38 try: data = f.read() 39 finally: f.close() 40 return data 41 42name = name() 43version = version() 44 45url = 'https://bitbucket.org/petsc/%(name)s/' % vars() 46download = url + 'downloads/%(name)s-%(version)s.tar.gz' % vars() 47 48devstat = ['Development Status :: 5 - Production/Stable'] 49keywords = ['PETSc', 'MPI'] 50 51metadata['name'] = name 52metadata['version'] = version 53metadata['description'] = __doc__.strip() 54metadata['long_description'] = description() 55metadata['keywords'] += keywords 56metadata['classifiers'] += devstat 57metadata['url'] = url 58metadata['download_url'] = download 59 60metadata['provides'] = ['petsc4py'] 61metadata['requires'] = ['numpy'] 62 63# -------------------------------------------------------------------- 64# Extension modules 65# -------------------------------------------------------------------- 66 67def get_ext_modules(Extension): 68 from os import walk, path 69 from glob import glob 70 depends = [] 71 for pth, dirs, files in walk('src'): 72 depends += glob(path.join(pth, '*.h')) 73 depends += glob(path.join(pth, '*.c')) 74 try: 75 import numpy 76 numpy_includes = [numpy.get_include()] 77 except ImportError: 78 numpy_includes = [] 79 return [Extension('petsc4py.lib.PETSc', 80 sources=['src/PETSc.c', 81 'src/libpetsc4py.c', 82 ], 83 include_dirs=['src/include', 84 ] + numpy_includes, 85 depends=depends)] 86 87# -------------------------------------------------------------------- 88# Setup 89# -------------------------------------------------------------------- 90 91from conf.petscconf import setup, Extension 92from conf.petscconf import config, build, build_src, build_ext 93from conf.petscconf import test, sdist 94 95CYTHON = '0.15' 96 97def run_setup(): 98 if ('setuptools' in sys.modules): 99 from os.path import exists, join 100 metadata['zip_safe'] = False 101 metadata['install_requires'] = ['numpy'] 102 if not exists(join('src', 'petsc4py.PETSc.c')): 103 metadata['install_requires'] += ['Cython>='+CYTHON] 104 PETSC_DIR = os.environ.get('PETSC_DIR') 105 if not (PETSC_DIR and os.path.isdir(PETSC_DIR)): 106 metadata['install_requires'] += ["petsc>=3.5,<3.6"] 107 # 108 setup(packages = ['petsc4py', 109 'petsc4py.lib',], 110 package_dir = {'petsc4py' : 'src', 111 'petsc4py.lib' : 'src/lib'}, 112 package_data = {'petsc4py' : ['include/petsc4py/*.h', 113 'include/petsc4py/*.i', 114 'include/petsc4py/*.pxd', 115 'include/petsc4py/*.pxi', 116 'include/petsc4py/*.pyx',], 117 'petsc4py.lib' : ['petsc.cfg'],}, 118 ext_modules = get_ext_modules(Extension), 119 cmdclass = {'config' : config, 120 'build' : build, 121 'build_src' : build_src, 122 'build_ext' : build_ext, 123 'test' : test, 124 'sdist' : sdist, 125 }, 126 **metadata) 127 128def chk_cython(VERSION): 129 import re 130 from distutils import log 131 from distutils.version import LooseVersion 132 from distutils.version import StrictVersion 133 warn = lambda msg='': sys.stderr.write(msg+'\n') 134 # 135 cython_zip = 'cython.zip' 136 if os.path.isfile(cython_zip): 137 path = os.path.abspath(cython_zip) 138 if sys.path[0] != path: 139 sys.path.insert(0, path) 140 log.info("adding '%s' to sys.path", cython_zip) 141 # 142 try: 143 import Cython 144 except ImportError: 145 warn("*"*80) 146 warn() 147 warn(" You need to generate C source files with Cython!!") 148 warn(" Download and install Cython <http://www.cython.org>") 149 warn() 150 warn("*"*80) 151 return False 152 # 153 try: 154 CYTHON_VERSION = Cython.__version__ 155 except AttributeError: 156 from Cython.Compiler.Version import version as CYTHON_VERSION 157 REQUIRED = VERSION 158 m = re.match(r"(\d+\.\d+(?:\.\d+)?).*", CYTHON_VERSION) 159 if m: 160 Version = StrictVersion 161 AVAILABLE = m.groups()[0] 162 else: 163 Version = LooseVersion 164 AVAILABLE = CYTHON_VERSION 165 if (REQUIRED is not None and 166 Version(AVAILABLE) < Version(REQUIRED)): 167 warn("*"*80) 168 warn() 169 warn(" You need to install Cython %s (you have version %s)" 170 % (REQUIRED, CYTHON_VERSION)) 171 warn(" Download and install Cython <http://www.cython.org>") 172 warn() 173 warn("*"*80) 174 return False 175 # 176 return True 177 178def run_cython(source, depends=(), includes=(), 179 destdir_c=None, destdir_h=None, wdir=None, 180 force=False, VERSION=None): 181 from glob import glob 182 from distutils import log 183 from distutils import dep_util 184 from distutils.errors import DistutilsError 185 target = os.path.splitext(source)[0]+".c" 186 cwd = os.getcwd() 187 try: 188 if wdir: os.chdir(wdir) 189 alldeps = [source] 190 for dep in depends: 191 alldeps += glob(dep) 192 if not (force or dep_util.newer_group(alldeps, target)): 193 log.debug("skipping '%s' -> '%s' (up-to-date)", 194 source, target) 195 return 196 finally: 197 os.chdir(cwd) 198 if not chk_cython(VERSION): 199 raise DistutilsError("requires Cython>=%s" % VERSION) 200 log.info("cythonizing '%s' -> '%s'", source, target) 201 from conf.cythonize import cythonize 202 err = cythonize(source, 203 includes=includes, 204 destdir_c=destdir_c, 205 destdir_h=destdir_h, 206 wdir=wdir) 207 if err: 208 raise DistutilsError( 209 "Cython failure: '%s' -> '%s'" % (source, target)) 210 211def build_sources(cmd): 212 from os.path import exists, isdir, join 213 if (exists(join('src', 'petsc4py.PETSc.c')) and 214 not (isdir('.hg') or isdir('.git')) and 215 not cmd.force): return 216 # petsc4py.PETSc 217 source = 'petsc4py.PETSc.pyx' 218 depends = ("include/*/*.pxd", 219 "PETSc/*.pyx", 220 "PETSc/*.pxi",) 221 includes = ['include'] 222 destdir_h = os.path.join('include', 'petsc4py') 223 run_cython(source, depends, includes, 224 destdir_c=None, destdir_h=destdir_h, wdir='src', 225 force=cmd.force, VERSION=CYTHON) 226 # libpetsc4py 227 source = os.path.join('libpetsc4py', 'libpetsc4py.pyx') 228 depends = ["include/petsc4py/*.pxd", 229 "libpetsc4py/*.pyx", 230 "libpetsc4py/*.pxi"] 231 includes = ['include'] 232 run_cython(source, depends, includes, 233 destdir_c=None, destdir_h=None, wdir='src', 234 force=cmd.force, VERSION=CYTHON) 235 236build_src.run = build_sources 237 238def run_testsuite(cmd): 239 from distutils.errors import DistutilsError 240 sys.path.insert(0, 'test') 241 try: 242 from runtests import main 243 finally: 244 del sys.path[0] 245 err = main(cmd.args or []) 246 if err: 247 raise DistutilsError("test") 248 249test.run = run_testsuite 250 251# -------------------------------------------------------------------- 252 253def main(): 254 run_setup() 255 256if __name__ == '__main__': 257 main() 258 259# -------------------------------------------------------------------- 260