1import sys, os 2import subprocess 3import errno 4 5# on Windows we give up and always import setuptools early to fix things for us 6if sys.platform == "win32": 7 import setuptools 8 9 10sources = ['c/_cffi_backend.c'] 11libraries = ['ffi'] 12include_dirs = ['/usr/include/ffi', 13 '/usr/include/libffi'] # may be changed by pkg-config 14define_macros = [] 15library_dirs = [] 16extra_compile_args = [] 17extra_link_args = [] 18 19 20def _ask_pkg_config(resultlist, option, result_prefix='', sysroot=False): 21 pkg_config = os.environ.get('PKG_CONFIG','pkg-config') 22 try: 23 p = subprocess.Popen([pkg_config, option, 'libffi'], 24 stdout=subprocess.PIPE) 25 except OSError as e: 26 if e.errno not in [errno.ENOENT, errno.EACCES]: 27 raise 28 else: 29 t = p.stdout.read().decode().strip() 30 p.stdout.close() 31 if p.wait() == 0: 32 res = t.split() 33 # '-I/usr/...' -> '/usr/...' 34 for x in res: 35 assert x.startswith(result_prefix) 36 res = [x[len(result_prefix):] for x in res] 37 #print 'PKG_CONFIG:', option, res 38 # 39 sysroot = sysroot and os.environ.get('PKG_CONFIG_SYSROOT_DIR', '') 40 if sysroot: 41 # old versions of pkg-config don't support this env var, 42 # so here we emulate its effect if needed 43 res = [path if path.startswith(sysroot) 44 else sysroot + path 45 for path in res] 46 # 47 resultlist[:] = res 48 49no_compiler_found = False 50def no_working_compiler_found(): 51 sys.stderr.write(""" 52 No working compiler found, or bogus compiler options passed to 53 the compiler from Python's standard "distutils" module. See 54 the error messages above. Likely, the problem is not related 55 to CFFI but generic to the setup.py of any Python package that 56 tries to compile C code. (Hints: on OS/X 10.8, for errors about 57 -mno-fused-madd see http://stackoverflow.com/questions/22313407/ 58 Otherwise, see https://wiki.python.org/moin/CompLangPython or 59 the IRC channel #python on irc.freenode.net.) 60 61 Trying to continue anyway. If you are trying to install CFFI from 62 a build done in a different context, you can ignore this warning. 63 \n""") 64 global no_compiler_found 65 no_compiler_found = True 66 67def get_config(): 68 from distutils.core import Distribution 69 from distutils.sysconfig import get_config_vars 70 get_config_vars() # workaround for a bug of distutils, e.g. on OS/X 71 config = Distribution().get_command_obj('config') 72 return config 73 74def ask_supports_thread(): 75 config = get_config() 76 ok = (sys.platform != 'win32' and 77 config.try_compile('__thread int some_threadlocal_variable_42;')) 78 if ok: 79 define_macros.append(('USE__THREAD', None)) 80 else: 81 ok1 = config.try_compile('int some_regular_variable_42;') 82 if not ok1: 83 no_working_compiler_found() 84 else: 85 sys.stderr.write("Note: will not use '__thread' in the C code\n") 86 _safe_to_ignore() 87 88def ask_supports_sync_synchronize(): 89 if sys.platform == 'win32' or no_compiler_found: 90 return 91 config = get_config() 92 ok = config.try_link('int main(void) { __sync_synchronize(); return 0; }') 93 if ok: 94 define_macros.append(('HAVE_SYNC_SYNCHRONIZE', None)) 95 else: 96 sys.stderr.write("Note: will not use '__sync_synchronize()'" 97 " in the C code\n") 98 _safe_to_ignore() 99 100def _safe_to_ignore(): 101 sys.stderr.write("***** The above error message can be safely ignored.\n\n") 102 103def uses_msvc(): 104 config = get_config() 105 return config.try_compile('#ifndef _MSC_VER\n#error "not MSVC"\n#endif') 106 107def use_pkg_config(): 108 if sys.platform == 'darwin' and os.path.exists('/usr/local/bin/brew'): 109 use_homebrew_for_libffi() 110 111 _ask_pkg_config(include_dirs, '--cflags-only-I', '-I', sysroot=True) 112 _ask_pkg_config(extra_compile_args, '--cflags-only-other') 113 _ask_pkg_config(library_dirs, '--libs-only-L', '-L', sysroot=True) 114 _ask_pkg_config(extra_link_args, '--libs-only-other') 115 _ask_pkg_config(libraries, '--libs-only-l', '-l') 116 117def use_homebrew_for_libffi(): 118 # We can build by setting: 119 # PKG_CONFIG_PATH = $(brew --prefix libffi)/lib/pkgconfig 120 with os.popen('brew --prefix libffi') as brew_prefix_cmd: 121 prefix = brew_prefix_cmd.read().strip() 122 pkgconfig = os.path.join(prefix, 'lib', 'pkgconfig') 123 os.environ['PKG_CONFIG_PATH'] = ( 124 os.environ.get('PKG_CONFIG_PATH', '') + ':' + pkgconfig) 125 126 127if sys.platform == 'win32' and uses_msvc(): 128 COMPILE_LIBFFI = 'c/libffi_msvc' # from the CPython distribution 129else: 130 COMPILE_LIBFFI = None 131 132if COMPILE_LIBFFI: 133 assert os.path.isdir(COMPILE_LIBFFI), "directory not found!" 134 include_dirs[:] = [COMPILE_LIBFFI] 135 libraries[:] = [] 136 _filenames = [filename.lower() for filename in os.listdir(COMPILE_LIBFFI)] 137 _filenames = [filename for filename in _filenames 138 if filename.endswith('.c')] 139 if sys.maxsize > 2**32: 140 # 64-bit: unlist win32.c, and add instead win64.obj. If the obj 141 # happens to get outdated at some point in the future, you need to 142 # rebuild it manually from win64.asm. 143 _filenames.remove('win32.c') 144 extra_link_args.append(os.path.join(COMPILE_LIBFFI, 'win64.obj')) 145 sources.extend(os.path.join(COMPILE_LIBFFI, filename) 146 for filename in _filenames) 147else: 148 use_pkg_config() 149 ask_supports_thread() 150 ask_supports_sync_synchronize() 151 152if 'freebsd' in sys.platform: 153 include_dirs.append('/usr/local/include') 154 library_dirs.append('/usr/local/lib') 155 156if 'darwin' in sys.platform: 157 try: 158 p = subprocess.Popen(['xcrun', '--show-sdk-path'], 159 stdout=subprocess.PIPE) 160 except OSError as e: 161 if e.errno not in [errno.ENOENT, errno.EACCES]: 162 raise 163 else: 164 t = p.stdout.read().decode().strip() 165 p.stdout.close() 166 if p.wait() == 0: 167 include_dirs.append(t + '/usr/include/ffi') 168 169 170 171if __name__ == '__main__': 172 from setuptools import setup, Distribution, Extension 173 174 class CFFIDistribution(Distribution): 175 def has_ext_modules(self): 176 # Event if we don't have extension modules (e.g. on PyPy) we want to 177 # claim that we do so that wheels get properly tagged as Python 178 # specific. (thanks dstufft!) 179 return True 180 181 # On PyPy, cffi is preinstalled and it is not possible, at least for now, 182 # to install a different version. We work around it by making the setup() 183 # arguments mostly empty in this case. 184 cpython = ('_cffi_backend' not in sys.builtin_module_names) 185 186 setup( 187 name='cffi', 188 description='Foreign Function Interface for Python calling C code.', 189 long_description=""" 190CFFI 191==== 192 193Foreign Function Interface for Python calling C code. 194Please see the `Documentation <http://cffi.readthedocs.org/>`_. 195 196Contact 197------- 198 199`Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_ 200""", 201 version='1.12.2', 202 packages=['cffi'] if cpython else [], 203 package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h', 204 '_embedding.h', '_cffi_errors.h']} 205 if cpython else {}, 206 zip_safe=False, 207 208 url='http://cffi.readthedocs.org', 209 author='Armin Rigo, Maciej Fijalkowski', 210 author_email='python-cffi@googlegroups.com', 211 212 license='MIT', 213 214 distclass=CFFIDistribution, 215 ext_modules=[Extension( 216 name='_cffi_backend', 217 include_dirs=include_dirs, 218 sources=sources, 219 libraries=libraries, 220 define_macros=define_macros, 221 library_dirs=library_dirs, 222 extra_compile_args=extra_compile_args, 223 extra_link_args=extra_link_args, 224 )] if cpython else [], 225 226 install_requires=[ 227 'pycparser' if sys.version_info >= (2, 7) else 'pycparser<2.19', 228 ] if cpython else [], 229 230 entry_points = { 231 "distutils.setup_keywords": [ 232 "cffi_modules = cffi.setuptools_ext:cffi_modules", 233 ], 234 }, 235 236 classifiers=[ 237 'Programming Language :: Python', 238 'Programming Language :: Python :: 2', 239 'Programming Language :: Python :: 2.6', 240 'Programming Language :: Python :: 2.7', 241 'Programming Language :: Python :: 3', 242 'Programming Language :: Python :: 3.2', 243 'Programming Language :: Python :: 3.3', 244 'Programming Language :: Python :: 3.4', 245 'Programming Language :: Python :: 3.5', 246 'Programming Language :: Python :: 3.6', 247 'Programming Language :: Python :: Implementation :: CPython', 248 'Programming Language :: Python :: Implementation :: PyPy', 249 ], 250 ) 251