setup.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import sys, os
  2. import subprocess
  3. import errno
  4. sources = ['c/_cffi_backend.c']
  5. libraries = ['ffi']
  6. include_dirs = ['/usr/include/ffi',
  7. '/usr/include/libffi'] # may be changed by pkg-config
  8. define_macros = []
  9. library_dirs = []
  10. extra_compile_args = []
  11. extra_link_args = []
  12. def _ask_pkg_config(resultlist, option, result_prefix='', sysroot=False):
  13. pkg_config = os.environ.get('PKG_CONFIG','pkg-config')
  14. try:
  15. p = subprocess.Popen([pkg_config, option, 'libffi'],
  16. stdout=subprocess.PIPE)
  17. except OSError as e:
  18. if e.errno not in [errno.ENOENT, errno.EACCES]:
  19. raise
  20. else:
  21. t = p.stdout.read().decode().strip()
  22. p.stdout.close()
  23. if p.wait() == 0:
  24. res = t.split()
  25. # '-I/usr/...' -> '/usr/...'
  26. for x in res:
  27. assert x.startswith(result_prefix)
  28. res = [x[len(result_prefix):] for x in res]
  29. #print 'PKG_CONFIG:', option, res
  30. #
  31. sysroot = sysroot and os.environ.get('PKG_CONFIG_SYSROOT_DIR', '')
  32. if sysroot:
  33. # old versions of pkg-config don't support this env var,
  34. # so here we emulate its effect if needed
  35. res = [path if path.startswith(sysroot)
  36. else sysroot + path
  37. for path in res]
  38. #
  39. resultlist[:] = res
  40. def no_working_compiler_found():
  41. sys.stderr.write("""
  42. No working compiler found, or bogus compiler options
  43. passed to the compiler from Python's distutils module.
  44. See the error messages above.
  45. (If they are about -mno-fused-madd and you are on OS/X 10.8,
  46. see http://stackoverflow.com/questions/22313407/ .)\n""")
  47. sys.exit(1)
  48. def ask_supports_thread():
  49. from distutils.core import Distribution
  50. from distutils.sysconfig import get_config_vars
  51. get_config_vars() # workaround for a bug of distutils, e.g. on OS/X
  52. config = Distribution().get_command_obj('config')
  53. ok = config.try_compile('__thread int some_threadlocal_variable_42;')
  54. if ok:
  55. define_macros.append(('USE__THREAD', None))
  56. else:
  57. ok1 = config.try_compile('int some_regular_variable_42;')
  58. if not ok1:
  59. no_working_compiler_found()
  60. sys.stderr.write("Note: will not use '__thread' in the C code\n")
  61. sys.stderr.write("The above error message can be safely ignored\n")
  62. def use_pkg_config():
  63. if sys.platform == 'darwin' and os.path.exists('/usr/local/bin/brew'):
  64. use_homebrew_for_libffi()
  65. _ask_pkg_config(include_dirs, '--cflags-only-I', '-I', sysroot=True)
  66. _ask_pkg_config(extra_compile_args, '--cflags-only-other')
  67. _ask_pkg_config(library_dirs, '--libs-only-L', '-L', sysroot=True)
  68. _ask_pkg_config(extra_link_args, '--libs-only-other')
  69. _ask_pkg_config(libraries, '--libs-only-l', '-l')
  70. def use_homebrew_for_libffi():
  71. # We can build by setting:
  72. # PKG_CONFIG_PATH = $(brew --prefix libffi)/lib/pkgconfig
  73. with os.popen('brew --prefix libffi') as brew_prefix_cmd:
  74. prefix = brew_prefix_cmd.read().strip()
  75. pkgconfig = os.path.join(prefix, 'lib', 'pkgconfig')
  76. os.environ['PKG_CONFIG_PATH'] = (
  77. os.environ.get('PKG_CONFIG_PATH', '') + ':' + pkgconfig)
  78. if sys.platform == 'win32':
  79. COMPILE_LIBFFI = 'c/libffi_msvc' # from the CPython distribution
  80. else:
  81. COMPILE_LIBFFI = None
  82. if COMPILE_LIBFFI:
  83. assert os.path.isdir(COMPILE_LIBFFI), "directory not found!"
  84. include_dirs[:] = [COMPILE_LIBFFI]
  85. libraries[:] = []
  86. _filenames = [filename.lower() for filename in os.listdir(COMPILE_LIBFFI)]
  87. _filenames = [filename for filename in _filenames
  88. if filename.endswith('.c')]
  89. if sys.maxsize > 2**32:
  90. # 64-bit: unlist win32.c, and add instead win64.obj. If the obj
  91. # happens to get outdated at some point in the future, you need to
  92. # rebuild it manually from win64.asm.
  93. _filenames.remove('win32.c')
  94. extra_link_args.append(os.path.join(COMPILE_LIBFFI, 'win64.obj'))
  95. sources.extend(os.path.join(COMPILE_LIBFFI, filename)
  96. for filename in _filenames)
  97. else:
  98. use_pkg_config()
  99. ask_supports_thread()
  100. if 'freebsd' in sys.platform:
  101. include_dirs.append('/usr/local/include')
  102. if __name__ == '__main__':
  103. from setuptools import setup, Distribution, Extension
  104. class CFFIDistribution(Distribution):
  105. def has_ext_modules(self):
  106. # Event if we don't have extension modules (e.g. on PyPy) we want to
  107. # claim that we do so that wheels get properly tagged as Python
  108. # specific. (thanks dstufft!)
  109. return True
  110. # On PyPy, cffi is preinstalled and it is not possible, at least for now,
  111. # to install a different version. We work around it by making the setup()
  112. # arguments mostly empty in this case.
  113. cpython = ('_cffi_backend' not in sys.builtin_module_names)
  114. setup(
  115. name='cffi',
  116. description='Foreign Function Interface for Python calling C code.',
  117. long_description="""
  118. CFFI
  119. ====
  120. Foreign Function Interface for Python calling C code.
  121. Please see the `Documentation <http://cffi.readthedocs.org/>`_.
  122. Contact
  123. -------
  124. `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_
  125. """,
  126. version='1.5.2',
  127. packages=['cffi'] if cpython else [],
  128. package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h',
  129. '_embedding.h']}
  130. if cpython else {},
  131. zip_safe=False,
  132. url='http://cffi.readthedocs.org',
  133. author='Armin Rigo, Maciej Fijalkowski',
  134. author_email='python-cffi@googlegroups.com',
  135. license='MIT',
  136. distclass=CFFIDistribution,
  137. ext_modules=[Extension(
  138. name='_cffi_backend',
  139. include_dirs=include_dirs,
  140. sources=sources,
  141. libraries=libraries,
  142. define_macros=define_macros,
  143. library_dirs=library_dirs,
  144. extra_compile_args=extra_compile_args,
  145. extra_link_args=extra_link_args,
  146. )] if cpython else [],
  147. install_requires=[
  148. 'pycparser',
  149. ] if cpython else [],
  150. entry_points = {
  151. "distutils.setup_keywords": [
  152. "cffi_modules = cffi.setuptools_ext:cffi_modules",
  153. ],
  154. } if cpython else {},
  155. classifiers=[
  156. 'Programming Language :: Python',
  157. 'Programming Language :: Python :: 2',
  158. 'Programming Language :: Python :: 2.6',
  159. 'Programming Language :: Python :: 2.7',
  160. 'Programming Language :: Python :: 3',
  161. 'Programming Language :: Python :: 3.2',
  162. 'Programming Language :: Python :: 3.3',
  163. 'Programming Language :: Python :: 3.4',
  164. 'Programming Language :: Python :: Implementation :: CPython',
  165. 'Programming Language :: Python :: Implementation :: PyPy',
  166. ],
  167. )