Lucia Li | 6aa63b0 | 2021-11-08 21:45:14 +0800 | [diff] [blame] | 1 | import sys, os, platform |
Kevin Cheng | 757c264 | 2019-04-18 11:31:16 -0700 | [diff] [blame] | 2 | import subprocess |
| 3 | import errno |
| 4 | |
| 5 | # on Windows we give up and always import setuptools early to fix things for us |
| 6 | if sys.platform == "win32": |
| 7 | import setuptools |
| 8 | |
| 9 | |
| 10 | sources = ['c/_cffi_backend.c'] |
| 11 | libraries = ['ffi'] |
| 12 | include_dirs = ['/usr/include/ffi', |
| 13 | '/usr/include/libffi'] # may be changed by pkg-config |
| 14 | define_macros = [] |
| 15 | library_dirs = [] |
| 16 | extra_compile_args = [] |
| 17 | extra_link_args = [] |
| 18 | |
| 19 | |
| 20 | def _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 | |
| 49 | no_compiler_found = False |
| 50 | def 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 Li | 6aa63b0 | 2021-11-08 21:45:14 +0800 | [diff] [blame] | 59 | the IRC channel #python on irc.libera.chat.) |
Kevin Cheng | 757c264 | 2019-04-18 11:31:16 -0700 | [diff] [blame] | 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 | |
| 67 | def 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 | |
| 74 | def 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 | |
| 88 | def 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 | |
| 100 | def _safe_to_ignore(): |
| 101 | sys.stderr.write("***** The above error message can be safely ignored.\n\n") |
| 102 | |
| 103 | def uses_msvc(): |
| 104 | config = get_config() |
| 105 | return config.try_compile('#ifndef _MSC_VER\n#error "not MSVC"\n#endif') |
| 106 | |
| 107 | def 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 | |
| 117 | def 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 Li | 6aa63b0 | 2021-11-08 21:45:14 +0800 | [diff] [blame] | 126 | if 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 Cheng | 757c264 | 2019-04-18 11:31:16 -0700 | [diff] [blame] | 146 | else: |
| 147 | use_pkg_config() |
| 148 | ask_supports_thread() |
| 149 | ask_supports_sync_synchronize() |
| 150 | |
Lucia Li | 6aa63b0 | 2021-11-08 21:45:14 +0800 | [diff] [blame] | 151 | if '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 Cheng | 757c264 | 2019-04-18 11:31:16 -0700 | [diff] [blame] | 155 | if 'freebsd' in sys.platform: |
| 156 | include_dirs.append('/usr/local/include') |
| 157 | library_dirs.append('/usr/local/lib') |
| 158 | |
Kevin Cheng | 757c264 | 2019-04-18 11:31:16 -0700 | [diff] [blame] | 159 | if __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=""" |
| 178 | CFFI |
| 179 | ==== |
| 180 | |
| 181 | Foreign Function Interface for Python calling C code. |
| 182 | Please see the `Documentation <http://cffi.readthedocs.org/>`_. |
| 183 | |
| 184 | Contact |
| 185 | ------- |
| 186 | |
| 187 | `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_ |
| 188 | """, |
Lucia Li | 6aa63b0 | 2021-11-08 21:45:14 +0800 | [diff] [blame] | 189 | version='1.15.0', |
Kevin Cheng | 757c264 | 2019-04-18 11:31:16 -0700 | [diff] [blame] | 190 | 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 Cheng | 757c264 | 2019-04-18 11:31:16 -0700 | [diff] [blame] | 227 | 'Programming Language :: Python :: 2.7', |
| 228 | 'Programming Language :: Python :: 3', |
Kevin Cheng | 757c264 | 2019-04-18 11:31:16 -0700 | [diff] [blame] | 229 | 'Programming Language :: Python :: 3.6', |
Lucia Li | 6aa63b0 | 2021-11-08 21:45:14 +0800 | [diff] [blame] | 230 | 'Programming Language :: Python :: 3.7', |
| 231 | 'Programming Language :: Python :: 3.8', |
| 232 | 'Programming Language :: Python :: 3.9', |
| 233 | 'Programming Language :: Python :: 3.10', |
Kevin Cheng | 757c264 | 2019-04-18 11:31:16 -0700 | [diff] [blame] | 234 | 'Programming Language :: Python :: Implementation :: CPython', |
| 235 | 'Programming Language :: Python :: Implementation :: PyPy', |
Lucia Li | 6aa63b0 | 2021-11-08 21:45:14 +0800 | [diff] [blame] | 236 | 'License :: OSI Approved :: MIT License', |
Kevin Cheng | 757c264 | 2019-04-18 11:31:16 -0700 | [diff] [blame] | 237 | ], |
| 238 | ) |