https://bugs.python.org/issue41100 https://github.com/python/cpython/pull/21249 https://github.com/python/cpython/pull/21268 https://github.com/python/cpython/pull/21564 --- configure.orig 2020-04-20 07:13:39.000000000 +1000 +++ configure 2020-09-10 19:51:43.000000000 +1000 @@ -8474,6 +8474,9 @@ ppc) MACOSX_DEFAULT_ARCH="ppc64" ;; + arm64) + MACOSX_DEFAULT_ARCH="arm64" + ;; *) as_fn_error $? "Unexpected output of 'arch' on OSX" "$LINENO" 5 ;; --- Mac/Tools/pythonw.c.orig 2020-04-20 07:13:39.000000000 +1000 +++ Mac/Tools/pythonw.c 2020-09-10 20:22:45.000000000 +1000 @@ -114,6 +114,9 @@ #elif defined(__x86_64__) cpu_types[0] = CPU_TYPE_X86_64; +#elif defined(__arm64__) + cpu_types[0] = CPU_TYPE_ARM64; + #elif defined(__ppc__) cpu_types[0] = CPU_TYPE_POWERPC; #elif defined(__i386__) --- Lib/test/test_platform.py.orig 2020-04-20 07:13:39.000000000 +1000 +++ Lib/test/test_platform.py 2020-09-10 20:26:40.000000000 +1000 @@ -220,7 +220,7 @@ self.assertEqual(res[1], ('', '', '')) if sys.byteorder == 'little': - self.assertIn(res[2], ('i386', 'x86_64')) + self.assertIn(res[2], ('i386', 'x86_64', 'arm64')) else: self.assertEqual(res[2], 'PowerPC') --- Lib/_osx_support.py.orig 2020-04-20 07:13:39.000000000 +1000 +++ Lib/_osx_support.py 2020-09-10 20:38:30.000000000 +1000 @@ -470,6 +470,8 @@ if len(archs) == 1: machine = archs[0] + elif archs == ('arm64', 'x86_64'): + machine = 'universal2' elif archs == ('i386', 'ppc'): machine = 'fat' elif archs == ('i386', 'x86_64'): @@ -484,6 +486,10 @@ raise ValueError( "Don't know machine value for archs=%r" % (archs,)) + elif machine == 'arm': + # No 32-bit arm support on macOS + machine = 'arm64' + elif machine == 'i386': # On OSX the machine type returned by uname is always the # 32-bit variant, even if the executable architecture is --- Lib/test/test_unicode.py.orig 2020-04-20 07:13:39.000000000 +1000 +++ Lib/test/test_unicode.py 2020-09-18 01:42:41.000000000 +1000 @@ -1676,6 +1676,7 @@ def test_from_format(self): test_support.import_module('ctypes') from ctypes import ( + c_char_p, pythonapi, py_object, sizeof, c_int, c_long, c_longlong, c_ssize_t, c_uint, c_ulong, c_ulonglong, c_size_t, c_void_p) @@ -1684,6 +1685,7 @@ else: name = "PyUnicodeUCS4_FromFormat" _PyUnicode_FromFormat = getattr(pythonapi, name) + _PyUnicode_FromFormat.argtypes = (c_char_p,) _PyUnicode_FromFormat.restype = py_object def PyUnicode_FromFormat(format, *args): --- Modules/_ctypes/callbacks.c.orig 2020-04-20 07:13:39.000000000 +1000 +++ Modules/_ctypes/callbacks.c 2020-09-18 02:26:42.000000000 +1000 @@ -24,7 +24,7 @@ CThunkObject_dealloc(PyObject *_self) Py_XDECREF(self->callable); Py_XDECREF(self->restype); if (self->pcl_write) - ffi_closure_free(self->pcl_write); + Py_ffi_closure_free(self->pcl_write); PyObject_GC_Del(self); } @@ -426,7 +426,7 @@ CThunkObject *_ctypes_alloc_callback(PyO assert(CThunk_CheckExact(p)); - p->pcl_write = ffi_closure_alloc(sizeof(ffi_closure), + p->pcl_write = Py_ffi_closure_alloc(sizeof(ffi_closure), &p->pcl_exec); if (p->pcl_write == NULL) { PyErr_NoMemory(); @@ -473,12 +473,15 @@ CThunkObject *_ctypes_alloc_callback(PyO "ffi_prep_cif failed with %d", result); goto error; } -#if defined(X86_DARWIN) || defined(POWERPC_DARWIN) - result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p); -#else +#if HAVE_FFI_PREP_CLOSURE_LOC result = ffi_prep_closure_loc(p->pcl_write, &p->cif, closure_fcn, p, p->pcl_exec); +#elif defined(__APPLE__) && defined(__arm64__) + PyErr_Format(PyExc_NotImplementedError, "ffi_prep_closure_loc() is missing"); + goto error; +#else + result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p); #endif if (result != FFI_OK) { PyErr_Format(PyExc_RuntimeError, --- Modules/_ctypes/callproc.c.orig 2020-04-20 07:13:39.000000000 +1000 +++ Modules/_ctypes/callproc.c 2020-09-21 06:08:56.000000000 +1000 @@ -773,7 +773,8 @@ static int _call_function_pointer(int fl ffi_type **atypes, ffi_type *restype, void *resmem, - int argcount) + int argcount, + int argtypecount) { #ifdef WITH_THREAD PyThreadState *_save = NULL; /* For Py_BLOCK_THREADS and Py_UNBLOCK_THREADS */ @@ -801,6 +802,37 @@ static int _call_function_pointer(int fl if ((flags & FUNCFLAG_CDECL) == 0) cc = FFI_STDCALL; #endif + + /* Even on Apple-arm64 the calling convention for variadic functions conincides + * with the standard calling convention in the case that the function called + * only with its fixed arguments. Thus, we do not need a special flag to be + * set on variadic functions. We treat a function as variadic if it is called + * with a nonzero number of variadic arguments */ + int is_variadic = (argtypecount != 0 && argcount > argtypecount); + (void) is_variadic; + +#if defined(__APPLE__) && defined(__arm64__) && !defined(HAVE_FFI_PREP_CIF_VAR) + if (is_variadic) { + PyErr_SetString(PyExc_NotImplementedError, "ffi_prep_cif_var() is missing"); + return -1; + } +#endif + +#if HAVE_FFI_PREP_CIF_VAR + if (is_variadic) { + if (FFI_OK != ffi_prep_cif_var(&cif, + cc, + argtypecount, + argcount, + restype, + atypes)) { + PyErr_SetString(PyExc_RuntimeError, + "ffi_prep_cif_var failed"); + return -1; + } + } else + #endif + { if (FFI_OK != ffi_prep_cif(&cif, cc, argcount, @@ -810,6 +842,7 @@ static int _call_function_pointer(int fl "ffi_prep_cif failed"); return -1; } + } if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR)) { error_object = _ctypes_get_errobj(&space); @@ -1183,6 +1216,9 @@ PyObject *_ctypes_callproc(PPROC pProc, rtype, resbuf, Py_SAFE_DOWNCAST(argcount, Py_ssize_t, + int), + Py_SAFE_DOWNCAST(argtype_count, + Py_ssize_t, int))) goto cleanup; --- Modules/_ctypes/ctypes.h.orig 2020-04-20 07:13:39.000000000 +1000 +++ Modules/_ctypes/ctypes.h 2020-09-21 06:14:07.000000000 +1000 @@ -481,6 +481,13 @@ static void capsule_destructor_ ## name( #endif /* PY_VERSION_HEX >= 0x020700A4 */ +#if USING_MALLOC_CLOSURE_DOT_C +void Py_ffi_closure_free(void *p); +void *Py_ffi_closure_alloc(size_t size, void** codeloc); +#else +#define Py_ffi_closure_free ffi_closure_free +#define Py_ffi_closure_alloc ffi_closure_alloc +#endif /* Local Variables: --- Modules/_ctypes/malloc_closure.c.orig 2020-04-20 07:13:39.000000000 +1000 +++ Modules/_ctypes/malloc_closure.c 2020-09-21 06:22:52.000000000 +1000 @@ -89,16 +89,24 @@ static void more_core(void) /******************************************************************/ /* put the item back into the free list */ -void ffi_closure_free(void *p) +void Py_ffi_closure_free(void *p) { +#if HAVE_FFI_CLOSURE_ALLOC + ffi_closure_free(p); + return; +#else ITEM *item = (ITEM *)p; item->next = free_list; free_list = item; +#endif } /* return one item from the free list, allocating more if needed */ -void *ffi_closure_alloc(size_t ignored, void** codeloc) +void *Py_ffi_closure_alloc(size_t size, void** codeloc) { +#if HAVE_FFI_CLOSURE_ALLOC + return ffi_closure_alloc(size, codeloc); +#else ITEM *item; if (!free_list) more_core(); @@ -108,4 +116,5 @@ void *ffi_closure_alloc(size_t ignored, free_list = item->next; *codeloc = (void *)item; return (void *)item; +#endif } --- setup.py.orig 2020-04-20 07:13:39.000000000 +1000 +++ setup.py 2020-09-21 07:32:43.000000000 +1000 @@ -16,6 +16,7 @@ from distutils.command.install import install from distutils.command.install_lib import install_lib from distutils.spawn import find_executable +import distutils.command.config cross_compiling = "_PYTHON_HOST_PLATFORM" in os.environ @@ -2129,6 +2130,7 @@ if host_platform == 'darwin': sources.append('_ctypes/malloc_closure.c') + extra_compile_args.append('-DUSING_MALLOC_CLOSURE_DOT_C=1') sources.append('_ctypes/darwin/dlfcn_simple.c') extra_compile_args.append('-DMACOSX') include_dirs.append('_ctypes/darwin') @@ -2191,6 +2193,16 @@ break if ffi_inc and ffi_lib: + config = distutils.command.config.config(self.distribution) + config._check_compiler() + if any(cc in config.compiler.compiler_so for cc in ('gcc', 'clang')): + config.compiler.compiler_so += ["-Wno-unguarded-availability-new", "-Wno-unused-value"] + if config.check_func("ffi_prep_closure_loc", headers=['ffi.h'], include_dirs=[ffi_inc]): + ext.extra_compile_args.append("-DHAVE_FFI_PREP_CLOSURE_LOC=1") + if config.check_func("ffi_prep_cif_var", headers=['ffi.h'], include_dirs=[ffi_inc]): + ext.extra_compile_args.append("-DHAVE_FFI_PREP_CIF_VAR=1") + if host_platform == 'darwin' and config.check_func("ffi_closure_alloc", headers=['ffi.h'], include_dirs=[ffi_inc]): + ext.extra_compile_args.append("-DHAVE_FFI_CLOSURE_ALLOC=1") ext.include_dirs.extend(ffi_inc) ext.libraries.append(ffi_lib) self.use_system_libffi = True