import sys, os
import subprocess
import errno
sources = ['c/_cffi_backend.c']
libraries = ['ffi']
include_dirs = ['/usr/include/ffi',
'/usr/include/libffi'] # may be changed by pkg-config
define_macros = []
library_dirs = []
extra_compile_args = []
extra_link_args = []
def _ask_pkg_config(resultlist, option, result_prefix='', sysroot=False):
pkg_config = os.environ.get('PKG_CONFIG','pkg-config')
try:
p = subprocess.Popen([pkg_config, option, 'libffi'],
stdout=subprocess.PIPE)
except OSError as e:
if e.errno not in [errno.ENOENT, errno.EACCES]:
raise
else:
t = p.stdout.read().decode().strip()
p.stdout.close()
if p.wait() == 0:
res = t.split()
# '-I/usr/...' -> '/usr/...'
for x in res:
assert x.startswith(result_prefix)
res = [x[len(result_prefix):] for x in res]
#print 'PKG_CONFIG:', option, res
#
sysroot = sysroot and os.environ.get('PKG_CONFIG_SYSROOT_DIR', '')
if sysroot:
# old versions of pkg-config don't support this env var,
# so here we emulate its effect if needed
res = [path if path.startswith(sysroot)
else sysroot + path
for path in res]
#
resultlist[:] = res
def no_working_compiler_found():
sys.stderr.write("""
No working compiler found, or bogus compiler options
passed to the compiler from Python's distutils module.
See the error messages above.
(If they are about -mno-fused-madd and you are on OS/X 10.8,
see http://stackoverflow.com/questions/22313407/ .)\n""")
sys.exit(1)
def ask_supports_thread():
from distutils.core import Distribution
from distutils.sysconfig import get_config_vars
get_config_vars() # workaround for a bug of distutils, e.g. on OS/X
config = Distribution().get_command_obj('config')
ok = config.try_compile('__thread int some_threadlocal_variable_42;')
if ok:
define_macros.append(('USE__THREAD', None))
else:
ok1 = config.try_compile('int some_regular_variable_42;')
if not ok1:
no_working_compiler_found()
sys.stderr.write("Note: will not use '__thread' in the C code\n")
sys.stderr.write("The above error message can be safely ignored\n")
def use_pkg_config():
if sys.platform == 'darwin' and os.path.exists('/usr/local/bin/brew'):
use_homebrew_for_libffi()
_ask_pkg_config(include_dirs, '--cflags-only-I', '-I', sysroot=True)
_ask_pkg_config(extra_compile_args, '--cflags-only-other')
_ask_pkg_config(library_dirs, '--libs-only-L', '-L', sysroot=True)
_ask_pkg_config(extra_link_args, '--libs-only-other')
_ask_pkg_config(libraries, '--libs-only-l', '-l')
def use_homebrew_for_libffi():
# We can build by setting:
# PKG_CONFIG_PATH = $(brew --prefix libffi)/lib/pkgconfig
with os.popen('brew --prefix libffi') as brew_prefix_cmd:
prefix = brew_prefix_cmd.read().strip()
pkgconfig = os.path.join(prefix, 'lib', 'pkgconfig')
os.environ['PKG_CONFIG_PATH'] = (
os.environ.get('PKG_CONFIG_PATH', '') + ':' + pkgconfig)
if sys.platform == 'win32':
COMPILE_LIBFFI = 'c/libffi_msvc' # from the CPython distribution
else:
COMPILE_LIBFFI = None
if COMPILE_LIBFFI:
assert os.path.isdir(COMPILE_LIBFFI), "directory not found!"
include_dirs[:] = [COMPILE_LIBFFI]
libraries[:] = []
_filenames = [filename.lower() for filename in os.listdir(COMPILE_LIBFFI)]
_filenames = [filename for filename in _filenames
if filename.endswith('.c')]
if sys.maxsize > 2**32:
# 64-bit: unlist win32.c, and add instead win64.obj. If the obj
# happens to get outdated at some point in the future, you need to
# rebuild it manually from win64.asm.
_filenames.remove('win32.c')
extra_link_args.append(os.path.join(COMPILE_LIBFFI, 'win64.obj'))
sources.extend(os.path.join(COMPILE_LIBFFI, filename)
for filename in _filenames)
else:
use_pkg_config()
ask_supports_thread()
if 'freebsd' in sys.platform:
include_dirs.append('/usr/local/include')
if __name__ == '__main__':
from setuptools import setup, Distribution, Extension
class CFFIDistribution(Distribution):
def has_ext_modules(self):
# Event if we don't have extension modules (e.g. on PyPy) we want to
# claim that we do so that wheels get properly tagged as Python
# specific. (thanks dstufft!)
return True
# On PyPy, cffi is preinstalled and it is not possible, at least for now,
# to install a different version. We work around it by making the setup()
# arguments mostly empty in this case.
cpython = ('_cffi_backend' not in sys.builtin_module_names)
setup(
name='cffi',
description='Foreign Function Interface for Python calling C code.',
long_description="""
CFFI
====
Foreign Function Interface for Python calling C code.
Please see the `Documentation `_.
Contact
-------
`Mailing list `_
""",
version='1.5.2',
packages=['cffi'] if cpython else [],
package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h',
'_embedding.h']}
if cpython else {},
zip_safe=False,
url='http://cffi.readthedocs.org',
author='Armin Rigo, Maciej Fijalkowski',
author_email='python-cffi@googlegroups.com',
license='MIT',
distclass=CFFIDistribution,
ext_modules=[Extension(
name='_cffi_backend',
include_dirs=include_dirs,
sources=sources,
libraries=libraries,
define_macros=define_macros,
library_dirs=library_dirs,
extra_compile_args=extra_compile_args,
extra_link_args=extra_link_args,
)] if cpython else [],
install_requires=[
'pycparser',
] if cpython else [],
entry_points = {
"distutils.setup_keywords": [
"cffi_modules = cffi.setuptools_ext:cffi_modules",
],
} if cpython else {},
classifiers=[
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
],
)