/ scripts / setup.py
setup.py
  1  import sys
  2  import os
  3  from distutils.core import setup, Extension
  4  from distutils.command.clean import clean
  5  from distutils.command.build_ext import build_ext
  6  
  7  def 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  
 14  lib_path = '/lib'
 15  
 16  # Fail gracefully for old versions of Python.
 17  
 18  if 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  
 25  class 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  
 33  class 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  
141  if sys.version.find('MSC') == -1:
142      mplib = 'gmp'
143  else:
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  
149  if sys.argv[1].lower() in ['build', 'build_ext', 'install']:
150      do_search = True
151  else:
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  
158  defines = []
159  
160  # Beginning with v2.1.0, MPFR and MPC will be required.
161  
162  force = False
163  static = False
164  shared = False
165  
166  for 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  
199  incdirs = ['./src']
200  libdirs = []
201  rundirs = []
202  extras = []
203  
204  # Specify extra link arguments for Windows.
205  
206  if sys.version.find('MSC') == -1:
207      my_extra_link_args = None
208  else:
209      my_extra_link_args = ["/MANIFEST"]
210  
211  mp_found = False
212  
213  prefix = ''
214  
215  for 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  
221  writeln(prefix)
222  
223  if force:
224      defines.append(('FORCE', None))
225  
226  if mplib == 'mpir':
227      defines.append(('MPIR', None))
228      libs = ['mpir']
229      if static:
230          extras.append(os.path.join(prefix, lib_path, 'libmpir.a'))
231  else:
232      libs = ['gmp']
233      if static:
234          extras.append(os.path.join(prefix, lib_path, 'libgmp.a'))
235  
236  libs.append('mpfr')
237  if static:
238      extras.append(os.path.join(prefix, lib_path, 'libmpfr.a'))
239  
240  libs.append('mpc')
241  if static:
242      extras.append(os.path.join(prefix, lib_path, 'libmpc.a'))
243  
244  writeln(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  
251  my_commands = {'clean' : gmpy_clean, 'build_ext' : gmpy_build_ext}
252  
253  gmpy2_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  
260  setup(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  )