Skip to content

Commit 80f852b

Browse files
use system libffi for older releases of Mac OS
1 parent da30587 commit 80f852b

File tree

5 files changed

+91
-31
lines changed

5 files changed

+91
-31
lines changed

Modules/_ctypes/callbacks.c

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ CThunkObject_dealloc(PyObject *myself)
1818
Py_XDECREF(self->callable);
1919
Py_XDECREF(self->restype);
2020
if (self->pcl_write)
21-
ffi_closure_free(self->pcl_write);
21+
Py_ffi_closure_free(self->pcl_write);
2222
PyObject_GC_Del(self);
2323
}
2424

@@ -361,8 +361,7 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable,
361361

362362
assert(CThunk_CheckExact((PyObject *)p));
363363

364-
p->pcl_write = ffi_closure_alloc(sizeof(ffi_closure),
365-
&p->pcl_exec);
364+
p->pcl_write = Py_ffi_closure_alloc(sizeof(ffi_closure), &p->pcl_exec);
366365
if (p->pcl_write == NULL) {
367366
PyErr_NoMemory();
368367
goto error;
@@ -408,13 +407,29 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable,
408407
"ffi_prep_cif failed with %d", result);
409408
goto error;
410409
}
411-
#if defined(X86_DARWIN) || defined(POWERPC_DARWIN)
412-
result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p);
410+
#if HAVE_FFI_PREP_CLOSURE_LOC
411+
# if USING_APPLE_OS_LIBFFI
412+
# define HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME __builtin_available(macos 11, ios 13, watchos 6, tvos 13, *)
413+
# else
414+
# define HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME true
415+
# endif
416+
if (HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME) {
417+
result = ffi_prep_closure_loc(p->pcl_write, &p->cif, closure_fcn,
418+
p,
419+
p->pcl_exec);
420+
} else
421+
#endif
422+
{
423+
#if USING_APPLE_OS_LIBFFI && defined(__arm64__)
424+
PyErr_Format(PyExc_NotImplementedError, "ffi_prep_closure_loc() is missing");
425+
goto error;
413426
#else
414-
result = ffi_prep_closure_loc(p->pcl_write, &p->cif, closure_fcn,
415-
p,
416-
p->pcl_exec);
427+
#pragma clang diagnostic push
428+
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
429+
result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p);
430+
#pragma clang diagnostic pop
417431
#endif
432+
}
418433
if (result != FFI_OK) {
419434
PyErr_Format(PyExc_RuntimeError,
420435
"ffi_prep_closure failed with %d", result);

Modules/_ctypes/callproc.c

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
#include "Python.h"
5858
#include "structmember.h" // PyMemberDef
5959

60+
#include <stdbool.h>
61+
6062
#ifdef MS_WIN32
6163
#include <windows.h>
6264
#include <tchar.h>
@@ -837,26 +839,52 @@ static int _call_function_pointer(int flags,
837839
cc = FFI_STDCALL;
838840
#endif
839841

840-
#if HAVE_FFI_PREP_CIF_VAR
842+
# if USING_APPLE_OS_LIBFFI
843+
# define HAVE_FFI_PREP_CIF_VAR_RUNTIME __builtin_available(macos 11, ios 13, watchos 6, tvos 13, *)
844+
# elif HAVE_FFI_PREP_CIF_VAR
845+
# define HAVE_FFI_PREP_CIF_VAR_RUNTIME true
846+
# else
847+
# define HAVE_FFI_PREP_CIF_VAR_RUNTIME false
848+
# endif
849+
841850
/* Everyone SHOULD set f.variadic=True on variadic function pointers, but
842851
* lots of existing code will not. If there's at least one arg and more
843852
* args are passed than are defined in the prototype, then it must be a
844853
* variadic function. */
845-
if ((flags & FUNCFLAG_VARIADIC) ||
846-
(argtypecount != 0 && argcount > argtypecount))
847-
{
848-
if (FFI_OK != ffi_prep_cif_var(&cif,
849-
cc,
850-
argtypecount,
851-
argcount,
852-
restype,
853-
atypes)) {
854-
PyErr_SetString(PyExc_RuntimeError,
855-
"ffi_prep_cif_var failed");
854+
bool is_variadic = (flags & FUNCFLAG_VARIADIC) || (argtypecount != 0 && argcount > argtypecount);
855+
(void) is_variadic;
856+
857+
#if defined(__APPLE__) && defined(__arm64__)
858+
if (is_variadic) {
859+
if (HAVE_FFI_PREP_CIF_VAR_RUNTIME) {
860+
} else {
861+
PyErr_SetString(PyExc_NotImplementedError, "ffi_prep_cif_var() is missing");
856862
return -1;
857863
}
858-
} else {
864+
}
865+
#endif
866+
867+
bool called_ffi_prep_cif_var = false;
868+
869+
#if HAVE_FFI_PREP_CIF_VAR
870+
if (is_variadic) {
871+
if (HAVE_FFI_PREP_CIF_VAR_RUNTIME) {
872+
if (FFI_OK != ffi_prep_cif_var(&cif,
873+
cc,
874+
argtypecount,
875+
argcount,
876+
restype,
877+
atypes)) {
878+
PyErr_SetString(PyExc_RuntimeError,
879+
"ffi_prep_cif_var failed");
880+
return -1;
881+
}
882+
called_ffi_prep_cif_var = true;
883+
}
884+
}
859885
#endif
886+
887+
if (!called_ffi_prep_cif_var) {
860888
if (FFI_OK != ffi_prep_cif(&cif,
861889
cc,
862890
argcount,
@@ -866,9 +894,7 @@ static int _call_function_pointer(int flags,
866894
"ffi_prep_cif failed");
867895
return -1;
868896
}
869-
#if HAVE_FFI_PREP_CIF_VAR
870897
}
871-
#endif
872898

873899
if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR)) {
874900
error_object = _ctypes_get_errobj(&space);

Modules/_ctypes/ctypes.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,14 @@ PyObject *_ctypes_get_errobj(int **pspace);
367367
extern PyObject *ComError;
368368
#endif
369369

370+
#if USING_MALLOC_CLOSURE_DOT_C
371+
void Py_ffi_closure_free(void *p);
372+
void *Py_ffi_closure_alloc(size_t size, void** codeloc);
373+
#else
374+
#define Py_ffi_closure_free ffi_closure_free
375+
#define Py_ffi_closure_alloc ffi_closure_alloc
376+
#endif
377+
370378
/*
371379
Local Variables:
372380
compile-command: "python setup.py -q build install --home ~"

Modules/_ctypes/malloc_closure.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,16 +89,27 @@ static void more_core(void)
8989
/******************************************************************/
9090

9191
/* put the item back into the free list */
92-
void ffi_closure_free(void *p)
92+
void Py_ffi_closure_free(void *p)
9393
{
94+
#if USING_APPLE_OS_LIBFFI
95+
if (__builtin_available(macos 11, ios 13, watchos 6, tvos 13, *)) {
96+
ffi_closure_free(p);
97+
return;
98+
}
99+
#endif
94100
ITEM *item = (ITEM *)p;
95101
item->next = free_list;
96102
free_list = item;
97103
}
98104

99105
/* return one item from the free list, allocating more if needed */
100-
void *ffi_closure_alloc(size_t ignored, void** codeloc)
106+
void *Py_ffi_closure_alloc(size_t size, void** codeloc)
101107
{
108+
#if USING_APPLE_OS_LIBFFI
109+
if (__builtin_available(macos 11, ios 13, watchos 6, tvos 13, *)) {
110+
return ffi_closure_alloc(size, codeloc);
111+
}
112+
#endif
102113
ITEM *item;
103114
if (!free_list)
104115
more_core();

setup.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2151,7 +2151,8 @@ def configure_ctypes(self, ext):
21512151
def detect_ctypes(self):
21522152
# Thomas Heller's _ctypes module
21532153

2154-
if not sysconfig.get_config_var("LIBFFI_INCLUDEDIR") and is_macosx_at_least((10,15)):
2154+
if (not sysconfig.get_config_var("LIBFFI_INCLUDEDIR") and
2155+
(is_macosx_at_least((10,15)) or '-arch arm64' in sysconfig.get_config_var("CFLAGS"))):
21552156
self.use_system_libffi = True
21562157
else:
21572158
self.use_system_libffi = '--with-system-ffi' in sysconfig.get_config_var("CONFIG_ARGS")
@@ -2168,6 +2169,7 @@ def detect_ctypes(self):
21682169

21692170
if MACOS:
21702171
sources.append('_ctypes/malloc_closure.c')
2172+
extra_compile_args.append('-DUSING_MALLOC_CLOSURE_DOT_C=1')
21712173
sources.append('_ctypes/darwin/dlfcn_simple.c')
21722174
extra_compile_args.append('-DMACOSX')
21732175
include_dirs.append('_ctypes/darwin')
@@ -2209,6 +2211,7 @@ def detect_ctypes(self):
22092211
if MACOS:
22102212
if not self.use_system_libffi:
22112213
return
2214+
ext.extra_compile_args.append("-DUSING_APPLE_OS_LIBFFI=1")
22122215
ffi_in_sdk = os.path.join(macosx_sdk_root(), "usr/include/ffi")
22132216
if os.path.exists(ffi_in_sdk):
22142217
ffi_inc = ffi_in_sdk
@@ -2235,13 +2238,10 @@ def detect_ctypes(self):
22352238

22362239
if ffi_inc and ffi_lib:
22372240
ffi_headers = glob(os.path.join(ffi_inc, '*.h'))
2238-
if grep_headers_for('ffi_closure_alloc', ffi_headers):
2239-
try:
2240-
sources.remove('_ctypes/malloc_closure.c')
2241-
except ValueError:
2242-
pass
22432241
if grep_headers_for('ffi_prep_cif_var', ffi_headers):
22442242
ext.extra_compile_args.append("-DHAVE_FFI_PREP_CIF_VAR=1")
2243+
if grep_headers_for('ffi_prep_closure_loc', ffi_headers):
2244+
ext.extra_compile_args.append("-DHAVE_FFI_PREP_CLOSURE_LOC=1")
22452245
ext.include_dirs.append(ffi_inc)
22462246
ext.libraries.append(ffi_lib)
22472247
self.use_system_libffi = True

0 commit comments

Comments
 (0)