1import sys 2import os 3from distutils.core import setup, Extension 4from distutils.command.clean import clean 5from distutils.command.build_ext import build_ext 6 7def writeln(s): 8 sys.stdout.write('%s\n' % s) 9 sys.stdout.flush() 10 11# Some operating systems may use a different library directory under the 12# prefix specified by --shared. It must be manually changed. 13 14lib_path = '/lib' 15 16# Fail gracefully for old versions of Python. 17 18if sys.version[:3] < '2.6': 19 writeln("GMPY2 requires Python 2.6 or later.") 20 writeln("Please use GMPY 1.x for earlier versions of Python.") 21 sys.exit() 22 23# Improved clean command. 24 25class gmpy_clean(clean): 26 27 def run(self): 28 self.all = True 29 clean.run(self) 30 31# Define a custom build class to force a new build. 32 33class gmpy_build_ext(build_ext): 34 35 def check_versions(self): 36 # Check the specified list of include directories to verify that valid 37 # versions of MPFR and MPC are available. If so, add entries to the 38 # appropriate lists 39 40 # Find the directory specfied for SHARED or STATIC. 41 prefix = [] 42 for d in self.extensions[0].define_macros: 43 if d[0] in ('SHARED', 'STATIC'): 44 if d[1]: 45 prefix.extend(map(os.path.expanduser, d[1].split(":"))) 46 try: 47 self.extensions[0].define_macros.remove(d) 48 except ValueError: 49 pass 50 51 if sys.version.find('MSC') == -1: 52 windows = False 53 base_dir = ['/usr'] 54 addin_dirs = ['/usr/local'] 55 else: 56 windows = True 57 base_dir = [] 58 addin_dirs = [] 59 60 if prefix: 61 search_dirs = base_dir + addin_dirs + prefix 62 else: 63 search_dirs = base_dir + addin_dirs 64 65 if 'gmp' in self.extensions[0].libraries: 66 mplib = 'gmp' 67 else: 68 mplib = 'mpir' 69 70 # these two lines were not used anywhere 71 # use_mpfr = 'mpfr' in self.extensions[0].libraries 72 # use_mpc = 'mpc' in self.extensions[0].libraries 73 74 if not search_dirs: 75 return 76 77 gmp_found = '' 78 mpfr_found = '' 79 mpc_found = '' 80 81 for adir in search_dirs: 82 lookin = os.path.join(adir, 'include') 83 84 if os.path.isfile(os.path.join(lookin, mplib + '.h')): 85 gmp_found = adir 86 87 if os.path.isfile(os.path.join(lookin, 'mpfr.h')): 88 mpfr_found = adir 89 90 if os.path.isfile(os.path.join(lookin, 'mpc.h')): 91 mpc_found = adir 92 93 # Add the directory information for location where valid versions were 94 # found. This can cause confusion if there are multiple installations of 95 # the same version of Python on the system. 96 97 for adir in (gmp_found, mpfr_found, mpc_found): 98 if not adir: 99 continue 100 if adir in base_dir: 101 continue 102 if os.path.join(adir, 'include') in self.extensions[0].include_dirs: 103 continue 104 self.extensions[0].include_dirs += [os.path.join(adir, 'include')] 105 self.extensions[0].library_dirs += [os.path.join(adir, lib_path)] 106 if shared and not windows: 107 self.extensions[0].runtime_library_dirs += [os.path.join(adir, lib_path)] 108 109 def finalize_options(self): 110 build_ext.finalize_options(self) 111 gmpy_build_ext.check_versions(self) 112 # Check if --force was specified. 113 for i,d in enumerate(self.extensions[0].define_macros[:]): 114 if d[0] == 'FORCE': 115 self.force = 1 116 try: 117 self.extensions[0].define_macros.remove(d) 118 except ValueError: 119 pass 120 121# Several command line options can be used to modify compilation of GMPY2. To 122# maintain backwards compatibility with older versions of setup.py, the old 123# options are still supported. 124# 125# New-style options 126# 127# --force -> ignore timestamps and recompile 128# --mpir -> use MPIR instead of GMP (GMP is the default on 129# non-Windows operating systems) 130# --gmp -> use GMP instead of MPIR 131# --lib64 -> use /<...>/lib64 instead of /<...>/lib 132# --shared=<...> -> add the specified directory prefix to the beginning of 133# the list of directories that are searched for GMP, MPFR, 134# and MPC shared libraries 135# --static=<...> -> create a statically linked library using static files from 136# the specified directory 137 138 139# Windows build defaults to using MPIR. 140 141if sys.version.find('MSC') == -1: 142 mplib = 'gmp' 143else: 144 mplib = 'mpir' 145 146# If 'clean' is the only argument to setup.py then we want to skip looking for 147# header files. 148 149if sys.argv[1].lower() in ['build', 'build_ext', 'install']: 150 do_search = True 151else: 152 do_search = False 153 154# Parse command line arguments. If custom prefix location is specified, it is 155# passed as a define so it can be processed in the custom build_ext defined 156# above. 157 158defines = [] 159 160# Beginning with v2.1.0, MPFR and MPC will be required. 161 162force = False 163static = False 164shared = False 165 166for token in sys.argv[:]: 167 if token.lower() == '--force': 168 force = True 169 sys.argv.remove(token) 170 171 if token.lower() == '--lib64': 172 lib_path = '/lib64' 173 sys.argv.remove(token) 174 175 if token.lower() == '--mpir': 176 mplib = 'mpir' 177 sys.argv.remove(token) 178 179 if token.lower() == '--gmp': 180 mplib = 'gmp' 181 sys.argv.remove(token) 182 183 if token.lower().startswith('--shared'): 184 shared = True 185 try: 186 defines.append(('SHARED', token.split('=')[1])) 187 except IndexError: 188 defines.append(('SHARED', None)) 189 sys.argv.remove(token) 190 191 if token.lower().startswith('--static'): 192 static = True 193 try: 194 defines.append(('STATIC', token.split('=')[1])) 195 except IndexError: 196 defines.append(('STATIC', None)) 197 sys.argv.remove(token) 198 199incdirs = ['./src'] 200libdirs = [] 201rundirs = [] 202extras = [] 203 204# Specify extra link arguments for Windows. 205 206if sys.version.find('MSC') == -1: 207 my_extra_link_args = None 208else: 209 my_extra_link_args = ["/MANIFEST"] 210 211mp_found = False 212 213prefix = '' 214 215for i,d in enumerate(defines[:]): 216 if d[0] in ('SHARED', 'STATIC'): 217 if d[1]: 218 prefix = d[1] 219 defines.append((d[0], None)) 220 221writeln(prefix) 222 223if force: 224 defines.append(('FORCE', None)) 225 226if mplib == 'mpir': 227 defines.append(('MPIR', None)) 228 libs = ['mpir'] 229 if static: 230 extras.append(os.path.join(prefix, lib_path, 'libmpir.a')) 231else: 232 libs = ['gmp'] 233 if static: 234 extras.append(os.path.join(prefix, lib_path, 'libgmp.a')) 235 236libs.append('mpfr') 237if static: 238 extras.append(os.path.join(prefix, lib_path, 'libmpfr.a')) 239 240libs.append('mpc') 241if static: 242 extras.append(os.path.join(prefix, lib_path, 'libmpc.a')) 243 244writeln(str(defines)) 245 246# decomment next line (w/gcc, only!) to support gcov 247# os.environ['CFLAGS'] = '-fprofile-arcs -ftest-coverage -O0' 248 249# prepare the extension for building 250 251my_commands = {'clean' : gmpy_clean, 'build_ext' : gmpy_build_ext} 252 253gmpy2_ext = Extension('gmpy2', 254 sources=[os.path.join('src', 'gmpy2.c')], 255 libraries=libs, 256 define_macros = defines, 257 extra_objects = extras, 258 extra_link_args = my_extra_link_args) 259 260setup(name = "gmpy2", 261 version = "2.1.0a3", 262 maintainer = "Case Van Horsen", 263 maintainer_email = "casevh@gmail.com", 264 url = "http://code.google.com/p/gmpy/", 265 description = "GMP/MPIR, MPFR, and MPC interface to Python 2.6+ and 3.x", 266 classifiers = [ 267 'Development Status :: 3 - Alpha', 268 'Intended Audience :: Developers', 269 'Intended Audience :: Science/Research', 270 'License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)', 271 'Natural Language :: English', 272 'Operating System :: MacOS :: MacOS X', 273 'Operating System :: Microsoft :: Windows', 274 'Operating System :: POSIX', 275 'Programming Language :: C', 276 'Programming Language :: Python :: 2', 277 'Programming Language :: Python :: 3', 278 'Programming Language :: Python :: Implementation :: CPython', 279 'Topic :: Scientific/Engineering :: Mathematics', 280 'Topic :: Software Development :: Libraries :: Python Modules', 281 ], 282 cmdclass = my_commands, 283 ext_modules = [gmpy2_ext] 284) 285