blob: 5fd1a1c008eb4cce241254d95a76a23716b8d5d7 [file] [log] [blame]
Lucia Li6aa63b02021-11-08 21:45:14 +08001import sys, os, platform
Kevin Cheng757c2642019-04-18 11:31:16 -07002import 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
Lucia Li6aa63b02021-11-08 21:45:14 +080059 the IRC channel #python on irc.libera.chat.)
Kevin Cheng757c2642019-04-18 11:31:16 -070060
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
Lucia Li6aa63b02021-11-08 21:45:14 +0800126if sys.platform == "win32" and uses_msvc():
127 if platform.machine() == "ARM64":
128 include_dirs.append(os.path.join("c/libffi_arm64/include"))
129 library_dirs.append(os.path.join("c/libffi_arm64"))
130 else:
131 COMPILE_LIBFFI = 'c/libffi_x86_x64' # from the CPython distribution
132 assert os.path.isdir(COMPILE_LIBFFI), "directory not found!"
133 include_dirs[:] = [COMPILE_LIBFFI]
134 libraries[:] = []
135 _filenames = [filename.lower() for filename in os.listdir(COMPILE_LIBFFI)]
136 _filenames = [filename for filename in _filenames
137 if filename.endswith('.c')]
138 if sys.maxsize > 2**32:
139 # 64-bit: unlist win32.c, and add instead win64.obj. If the obj
140 # happens to get outdated at some point in the future, you need to
141 # rebuild it manually from win64.asm.
142 _filenames.remove('win32.c')
143 extra_link_args.append(os.path.join(COMPILE_LIBFFI, 'win64.obj'))
144 sources.extend(os.path.join(COMPILE_LIBFFI, filename)
145 for filename in _filenames)
Kevin Cheng757c2642019-04-18 11:31:16 -0700146else:
147 use_pkg_config()
148 ask_supports_thread()
149 ask_supports_sync_synchronize()
150
Lucia Li6aa63b02021-11-08 21:45:14 +0800151if 'darwin' in sys.platform:
152 # priority is given to `pkg_config`, but always fall back on SDK's libffi.
153 extra_compile_args += ['-iwithsysroot/usr/include/ffi']
154
Kevin Cheng757c2642019-04-18 11:31:16 -0700155if 'freebsd' in sys.platform:
156 include_dirs.append('/usr/local/include')
157 library_dirs.append('/usr/local/lib')
158
Kevin Cheng757c2642019-04-18 11:31:16 -0700159if __name__ == '__main__':
160 from setuptools import setup, Distribution, Extension
161
162 class CFFIDistribution(Distribution):
163 def has_ext_modules(self):
164 # Event if we don't have extension modules (e.g. on PyPy) we want to
165 # claim that we do so that wheels get properly tagged as Python
166 # specific. (thanks dstufft!)
167 return True
168
169 # On PyPy, cffi is preinstalled and it is not possible, at least for now,
170 # to install a different version. We work around it by making the setup()
171 # arguments mostly empty in this case.
172 cpython = ('_cffi_backend' not in sys.builtin_module_names)
173
174 setup(
175 name='cffi',
176 description='Foreign Function Interface for Python calling C code.',
177 long_description="""
178CFFI
179====
180
181Foreign Function Interface for Python calling C code.
182Please see the `Documentation <http://cffi.readthedocs.org/>`_.
183
184Contact
185-------
186
187`Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_
188""",
Lucia Li6aa63b02021-11-08 21:45:14 +0800189 version='1.15.0',
Kevin Cheng757c2642019-04-18 11:31:16 -0700190 packages=['cffi'] if cpython else [],
191 package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h',
192 '_embedding.h', '_cffi_errors.h']}
193 if cpython else {},
194 zip_safe=False,
195
196 url='http://cffi.readthedocs.org',
197 author='Armin Rigo, Maciej Fijalkowski',
198 author_email='python-cffi@googlegroups.com',
199
200 license='MIT',
201
202 distclass=CFFIDistribution,
203 ext_modules=[Extension(
204 name='_cffi_backend',
205 include_dirs=include_dirs,
206 sources=sources,
207 libraries=libraries,
208 define_macros=define_macros,
209 library_dirs=library_dirs,
210 extra_compile_args=extra_compile_args,
211 extra_link_args=extra_link_args,
212 )] if cpython else [],
213
214 install_requires=[
215 'pycparser' if sys.version_info >= (2, 7) else 'pycparser<2.19',
216 ] if cpython else [],
217
218 entry_points = {
219 "distutils.setup_keywords": [
220 "cffi_modules = cffi.setuptools_ext:cffi_modules",
221 ],
222 },
223
224 classifiers=[
225 'Programming Language :: Python',
226 'Programming Language :: Python :: 2',
Kevin Cheng757c2642019-04-18 11:31:16 -0700227 'Programming Language :: Python :: 2.7',
228 'Programming Language :: Python :: 3',
Kevin Cheng757c2642019-04-18 11:31:16 -0700229 'Programming Language :: Python :: 3.6',
Lucia Li6aa63b02021-11-08 21:45:14 +0800230 'Programming Language :: Python :: 3.7',
231 'Programming Language :: Python :: 3.8',
232 'Programming Language :: Python :: 3.9',
233 'Programming Language :: Python :: 3.10',
Kevin Cheng757c2642019-04-18 11:31:16 -0700234 'Programming Language :: Python :: Implementation :: CPython',
235 'Programming Language :: Python :: Implementation :: PyPy',
Lucia Li6aa63b02021-11-08 21:45:14 +0800236 'License :: OSI Approved :: MIT License',
Kevin Cheng757c2642019-04-18 11:31:16 -0700237 ],
238 )