From 03a5d65387db282f77a8bc92581cd734133329b5 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Wed, 12 Oct 2022 18:52:53 +0100 Subject: [PATCH] Add CPython 3.7.15, 3.8.15, and 3.9.15 (#2482) Co-authored-by: Ivan Pozdeev --- .../python-build/share/python-build/3.7.15 | 9 + .../python-build/share/python-build/3.8.15 | 9 + .../python-build/share/python-build/3.9.15 | 9 + ...system-libffi-patches-for-arm64-macO.patch | 310 ++++++++++++++++++ ...x-_decimal-for-arm64-Mac-OS-GH-21228.patch | 37 +++ ...error-when-opening-header-with-non-U.patch | 30 ++ 6 files changed, 404 insertions(+) create mode 100644 plugins/python-build/share/python-build/3.7.15 create mode 100644 plugins/python-build/share/python-build/3.8.15 create mode 100644 plugins/python-build/share/python-build/3.9.15 create mode 100644 plugins/python-build/share/python-build/patches/3.7.15/Python-3.7.15/0001-Port-ctypes-and-system-libffi-patches-for-arm64-macO.patch create mode 100644 plugins/python-build/share/python-build/patches/3.7.15/Python-3.7.15/0002-bpo-41100-fix-_decimal-for-arm64-Mac-OS-GH-21228.patch create mode 100644 plugins/python-build/share/python-build/patches/3.7.15/Python-3.7.15/0003-bpo-42351-Avoid-error-when-opening-header-with-non-U.patch diff --git a/plugins/python-build/share/python-build/3.7.15 b/plugins/python-build/share/python-build/3.7.15 new file mode 100644 index 00000000..3aab86cf --- /dev/null +++ b/plugins/python-build/share/python-build/3.7.15 @@ -0,0 +1,9 @@ +prefer_openssl11 +export PYTHON_BUILD_CONFIGURE_WITH_OPENSSL=1 +install_package "openssl-1.1.1q" "https://www.openssl.org/source/openssl-1.1.1q.tar.gz#d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca" mac_openssl --if has_broken_mac_openssl +install_package "readline-8.1" "https://ftpmirror.gnu.org/readline/readline-8.1.tar.gz#f8ceb4ee131e3232226a17f51b164afc46cd0b9e6cef344be87c65962cb82b02" mac_readline --if has_broken_mac_readline +if has_tar_xz_support; then + install_package "Python-3.7.15" "https://www.python.org/ftp/python/3.7.15/Python-3.7.15.tar.xz#5911475a07ac2b53d746e88a0716af6d2b4734941919136ea0d33fb9c75b9714" standard verify_py37 copy_python_gdb ensurepip +else + install_package "Python-3.7.15" "https://www.python.org/ftp/python/3.7.15/Python-3.7.15.tgz#cf2993798ae8430f3af3a00d96d9fdf320719f4042f039380dca79967c25e436" standard verify_py37 copy_python_gdb ensurepip +fi diff --git a/plugins/python-build/share/python-build/3.8.15 b/plugins/python-build/share/python-build/3.8.15 new file mode 100644 index 00000000..83ef126f --- /dev/null +++ b/plugins/python-build/share/python-build/3.8.15 @@ -0,0 +1,9 @@ +prefer_openssl11 +export PYTHON_BUILD_CONFIGURE_WITH_OPENSSL=1 +install_package "openssl-1.1.1q" "https://www.openssl.org/source/openssl-1.1.1q.tar.gz#d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca" mac_openssl --if has_broken_mac_openssl +install_package "readline-8.1" "https://ftpmirror.gnu.org/readline/readline-8.1.tar.gz#f8ceb4ee131e3232226a17f51b164afc46cd0b9e6cef344be87c65962cb82b02" mac_readline --if has_broken_mac_readline +if has_tar_xz_support; then + install_package "Python-3.8.15" "https://www.python.org/ftp/python/3.8.15/Python-3.8.15.tar.xz#5114fc7918a2a5e20eb5aac696b30c36f412c6ef24b13f5c9eb9e056982d9550" standard verify_py38 copy_python_gdb ensurepip +else + install_package "Python-3.8.15" "https://www.python.org/ftp/python/3.8.15/Python-3.8.15.tgz#924d46999df82aa2eaa1de5ca51d6800ffb56b4bf52486a28f40634e3362abc4" standard verify_py38 copy_python_gdb ensurepip +fi diff --git a/plugins/python-build/share/python-build/3.9.15 b/plugins/python-build/share/python-build/3.9.15 new file mode 100644 index 00000000..39c37223 --- /dev/null +++ b/plugins/python-build/share/python-build/3.9.15 @@ -0,0 +1,9 @@ +prefer_openssl11 +export PYTHON_BUILD_CONFIGURE_WITH_OPENSSL=1 +install_package "openssl-1.1.1q" "https://www.openssl.org/source/openssl-1.1.1q.tar.gz#d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca" mac_openssl --if has_broken_mac_openssl +install_package "readline-8.1" "https://ftpmirror.gnu.org/readline/readline-8.1.tar.gz#f8ceb4ee131e3232226a17f51b164afc46cd0b9e6cef344be87c65962cb82b02" mac_readline --if has_broken_mac_readline +if has_tar_xz_support; then + install_package "Python-3.9.15" "https://www.python.org/ftp/python/3.9.15/Python-3.9.15.tar.xz#12daff6809528d9f6154216950423c9e30f0e47336cb57c6aa0b4387dd5eb4b2" standard verify_py39 copy_python_gdb ensurepip +else + install_package "Python-3.9.15" "https://www.python.org/ftp/python/3.9.15/Python-3.9.15.tgz#48d1ccb29d5fbaf1fb8f912271d09f7450e426d4dfe95978ef6aaada70ece4d8" standard verify_py39 copy_python_gdb ensurepip +fi diff --git a/plugins/python-build/share/python-build/patches/3.7.15/Python-3.7.15/0001-Port-ctypes-and-system-libffi-patches-for-arm64-macO.patch b/plugins/python-build/share/python-build/patches/3.7.15/Python-3.7.15/0001-Port-ctypes-and-system-libffi-patches-for-arm64-macO.patch new file mode 100644 index 00000000..f23946d0 --- /dev/null +++ b/plugins/python-build/share/python-build/patches/3.7.15/Python-3.7.15/0001-Port-ctypes-and-system-libffi-patches-for-arm64-macO.patch @@ -0,0 +1,310 @@ +From: Christian Hammond +Date: Wed, 15 Dec 2021 23:12:36 -0800 +Subject: Port ctypes and system libffi patches for arm64/macOS 10.15+ to Python 3.7.12 + +This ports the following ctypes and libffi pyenv patches for Python +2.7.18 to Python 3.7.12: + +* `0004-Use-system-libffi-for-Mac-OS-10.15-and-up.patch` +* `0005-ctypes-use-the-correct-ABI-for-variadic-functions.patch` +* `0006-ctypes-probe-libffi-for-ffi_closure_alloc-and-ffi_pr.patch` + +These patches enable use of system libffi (fixing a broken `ctypes` +module on arm64 targets) and enable calling variadic functions on arm64. +They've been combined from patches port from Homebrew to pyenv by Takumi +Sueda, updated to work on the Python 3.7.12 codebase. + +The Homebrew patches are themselves backports of changes in Python 3.9 +and 3.10. That patch can be found at: + +https://github.com/Homebrew/formula-patches/blob/master/python/3.8.7.patch + +diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst +index 715d595b24..7743144978 100644 +--- a/Doc/library/ctypes.rst ++++ b/Doc/library/ctypes.rst +@@ -1551,6 +1551,13 @@ They are instances of a private class: + value usable as argument (integer, string, ctypes instance). This allows + defining adapters that can adapt custom objects as function parameters. + ++ .. attribute:: variadic ++ ++ Assign a boolean to specify that the function takes a variable number of ++ arguments. This does not matter on most platforms, but for Apple arm64 ++ platforms variadic functions have a different calling convention than ++ normal functions. ++ + .. attribute:: errcheck + + Assign a Python function or another callable to this attribute. The +diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py +index 4ebd82d3e0..7b73c190b6 100644 +--- a/Lib/test/test_unicode.py ++++ b/Lib/test/test_unicode.py +@@ -2458,11 +2458,14 @@ class CAPITest(unittest.TestCase): + def test_from_format(self): + 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) + name = "PyUnicode_FromFormat" + _PyUnicode_FromFormat = getattr(pythonapi, name) ++ _PyUnicode_FromFormat.argtypes = (c_char_p,) ++ _PyUnicode_FromFormat.variadic = True + _PyUnicode_FromFormat.restype = py_object + + def PyUnicode_FromFormat(format, *args): +diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c +index dd0c61fd8a..79137e1dc7 100644 +--- a/Modules/_ctypes/_ctypes.c ++++ b/Modules/_ctypes/_ctypes.c +@@ -3174,6 +3174,34 @@ PyCFuncPtr_get_restype(PyCFuncPtrObject *self, void *Py_UNUSED(ignored)) + } + } + ++static int ++PyCFuncPtr_set_variadic(PyCFuncPtrObject *self, PyObject *ob) ++{ ++ StgDictObject *dict = PyObject_stgdict((PyObject *)self); ++ assert(dict); ++ int r = PyObject_IsTrue(ob); ++ if (r == 1) { ++ dict->flags |= FUNCFLAG_VARIADIC; ++ return 0; ++ } else if (r == 0) { ++ dict->flags &= ~FUNCFLAG_VARIADIC; ++ return 0; ++ } else { ++ return -1; ++ } ++} ++ ++static PyObject * ++PyCFuncPtr_get_variadic(PyCFuncPtrObject *self) ++{ ++ StgDictObject *dict = PyObject_stgdict((PyObject *)self); ++ assert(dict); /* Cannot be NULL for PyCFuncPtrObject instances */ ++ if (dict->flags & FUNCFLAG_VARIADIC) ++ Py_RETURN_TRUE; ++ else ++ Py_RETURN_FALSE; ++} ++ + static int + PyCFuncPtr_set_argtypes(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored)) + { +@@ -3219,6 +3247,8 @@ static PyGetSetDef PyCFuncPtr_getsets[] = { + { "argtypes", (getter)PyCFuncPtr_get_argtypes, + (setter)PyCFuncPtr_set_argtypes, + "specify the argument types", NULL }, ++ { "variadic", (getter)PyCFuncPtr_get_variadic, (setter)PyCFuncPtr_set_variadic, ++ "specify if function takes variable number of arguments", NULL }, + { NULL, NULL } + }; + +@@ -5632,6 +5662,7 @@ PyInit__ctypes(void) + PyModule_AddObject(m, "FUNCFLAG_USE_ERRNO", PyLong_FromLong(FUNCFLAG_USE_ERRNO)); + PyModule_AddObject(m, "FUNCFLAG_USE_LASTERROR", PyLong_FromLong(FUNCFLAG_USE_LASTERROR)); + PyModule_AddObject(m, "FUNCFLAG_PYTHONAPI", PyLong_FromLong(FUNCFLAG_PYTHONAPI)); ++ PyModule_AddObject(m, "FUNCFLAG_VARIADIC", PyLong_FromLong(FUNCFLAG_VARIADIC)); + PyModule_AddStringConstant(m, "__version__", "1.1.0"); + + PyModule_AddObject(m, "_memmove_addr", PyLong_FromVoidPtr(memmove)); +diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c +index 9cbf9801ad..e7fe11176b 100644 +--- a/Modules/_ctypes/callproc.c ++++ b/Modules/_ctypes/callproc.c +@@ -754,7 +756,8 @@ static int _call_function_pointer(int flags, + ffi_type **atypes, + ffi_type *restype, + void *resmem, +- int argcount) ++ int argcount, ++ int argtypecount) + { + PyThreadState *_save = NULL; /* For Py_BLOCK_THREADS and Py_UNBLOCK_THREADS */ + PyObject *error_object = NULL; +@@ -780,15 +783,39 @@ static int _call_function_pointer(int flags, + if ((flags & FUNCFLAG_CDECL) == 0) + cc = FFI_STDCALL; + #endif +- if (FFI_OK != ffi_prep_cif(&cif, +- cc, +- argcount, +- restype, +- atypes)) { +- PyErr_SetString(PyExc_RuntimeError, +- "ffi_prep_cif failed"); +- return -1; ++ ++#if HAVE_FFI_PREP_CIF_VAR ++ /* Everyone SHOULD set f.variadic=True on variadic function pointers, but ++ * lots of existing code will not. If there's at least one arg and more ++ * args are passed than are defined in the prototype, then it must be a ++ * variadic function. */ ++ if ((flags & FUNCFLAG_VARIADIC) || ++ (argtypecount != 0 && argcount > argtypecount)) ++ { ++ 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, ++ restype, ++ atypes)) { ++ PyErr_SetString(PyExc_RuntimeError, ++ "ffi_prep_cif failed"); ++ return -1; ++ } ++#if HAVE_FFI_PREP_CIF_VAR + } ++#endif + + if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR)) { + error_object = _ctypes_get_errobj(&space); +@@ -1187,9 +1214,8 @@ PyObject *_ctypes_callproc(PPROC pProc, + + if (-1 == _call_function_pointer(flags, pProc, avalues, atypes, + rtype, resbuf, +- Py_SAFE_DOWNCAST(argcount, +- Py_ssize_t, +- int))) ++ Py_SAFE_DOWNCAST(argcount, Py_ssize_t, int), ++ Py_SAFE_DOWNCAST(argtype_count, Py_ssize_t, int))) + goto cleanup; + + #ifdef WORDS_BIGENDIAN +diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h +index e58f85233c..e45975f6ad 100644 +--- a/Modules/_ctypes/ctypes.h ++++ b/Modules/_ctypes/ctypes.h +@@ -285,6 +285,7 @@ PyObject *_ctypes_callproc(PPROC pProc, + #define FUNCFLAG_PYTHONAPI 0x4 + #define FUNCFLAG_USE_ERRNO 0x8 + #define FUNCFLAG_USE_LASTERROR 0x10 ++#define FUNCFLAG_VARIADIC 0x20 + + #define TYPEFLAG_ISPOINTER 0x100 + #define TYPEFLAG_HASPOINTER 0x200 +diff --git a/setup.py b/setup.py +index bf90600eaa..48ff120e9a 100644 +--- a/setup.py ++++ b/setup.py +@@ -142,6 +142,13 @@ def macosx_sdk_root(): + + return MACOS_SDK_ROOT + ++def is_macosx_at_least(vers): ++ if host_platform == 'darwin': ++ dep_target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') ++ if dep_target: ++ return tuple(map(int, str(dep_target).split('.'))) >= vers ++ return False ++ + def is_macosx_sdk_path(path): + """ + Returns True if 'path' can be located in an OSX SDK +@@ -150,6 +157,13 @@ def is_macosx_sdk_path(path): + or path.startswith('/System/') + or path.startswith('/Library/') ) + ++def grep_headers_for(function, headers): ++ for header in headers: ++ with open(header, 'r') as f: ++ if function in f.read(): ++ return True ++ return False ++ + def find_file(filename, std_dirs, paths): + """Searches for the directory where a given file is located, + and returns a possibly-empty list of additional directories, or None +@@ -1972,7 +1986,11 @@ class PyBuildExt(build_ext): + return True + + def detect_ctypes(self, inc_dirs, lib_dirs): +- self.use_system_libffi = False ++ if not sysconfig.get_config_var("LIBFFI_INCLUDEDIR") and is_macosx_at_least((10,15)): ++ self.use_system_libffi = True ++ else: ++ self.use_system_libffi = '--with-system-ffi' in sysconfig.get_config_var("CONFIG_ARGS") ++ + include_dirs = [] + extra_compile_args = [] + extra_link_args = [] +@@ -2018,30 +2036,47 @@ class PyBuildExt(build_ext): + libraries=['m']) + self.extensions.extend([ext, ext_test]) + ++ ffi_inc = sysconfig.get_config_var("LIBFFI_INCLUDEDIR") ++ ffi_lib = None ++ + if host_platform == 'darwin': +- if '--with-system-ffi' not in sysconfig.get_config_var("CONFIG_ARGS"): ++ if not self.use_system_libffi: + return +- # OS X 10.5 comes with libffi.dylib; the include files are +- # in /usr/include/ffi +- inc_dirs.append('/usr/include/ffi') +- +- ffi_inc = [sysconfig.get_config_var("LIBFFI_INCLUDEDIR")] +- if not ffi_inc or ffi_inc[0] == '': +- ffi_inc = find_file('ffi.h', [], inc_dirs) +- if ffi_inc is not None: +- ffi_h = ffi_inc[0] + '/ffi.h' ++ ffi_in_sdk = os.path.join(macosx_sdk_root(), "usr/include/ffi") ++ if os.path.exists(ffi_in_sdk): ++ ffi_inc = ffi_in_sdk ++ ffi_lib = 'ffi' ++ else: ++ # OS X 10.5 comes with libffi.dylib; the include files are ++ # in /usr/include/ffi ++ inc_dirs.append('/usr/include/ffi') ++ ++ if not ffi_inc: ++ found = find_file('ffi.h', [], inc_dirs) ++ if found: ++ ffi_inc = found[0] ++ if ffi_inc: ++ ffi_h = ffi_inc + '/ffi.h' + if not os.path.exists(ffi_h): + ffi_inc = None + print('Header file {} does not exist'.format(ffi_h)) +- ffi_lib = None +- if ffi_inc is not None: +- for lib_name in ('ffi', 'ffi_pic'): ++ ++ if ffi_lib is None and ffi_inc: ++ for lib_name in ('ffi_convenience', 'ffi_pic', 'ffi'): + if (self.compiler.find_library_file(lib_dirs, lib_name)): + ffi_lib = lib_name + break + + if ffi_inc and ffi_lib: +- ext.include_dirs.extend(ffi_inc) ++ ffi_headers = glob(os.path.join(ffi_inc, '*.h')) ++ if grep_headers_for('ffi_closure_alloc', ffi_headers): ++ try: ++ sources.remove('_ctypes/malloc_closure.c') ++ except ValueError: ++ pass ++ if grep_headers_for('ffi_prep_cif_var', ffi_headers): ++ ext.extra_compile_args.append("-DHAVE_FFI_PREP_CIF_VAR=1") ++ ext.include_dirs.append(ffi_inc) + ext.libraries.append(ffi_lib) + self.use_system_libffi = True + +-- +2.30.1 (Apple Git-130) + diff --git a/plugins/python-build/share/python-build/patches/3.7.15/Python-3.7.15/0002-bpo-41100-fix-_decimal-for-arm64-Mac-OS-GH-21228.patch b/plugins/python-build/share/python-build/patches/3.7.15/Python-3.7.15/0002-bpo-41100-fix-_decimal-for-arm64-Mac-OS-GH-21228.patch new file mode 100644 index 00000000..8ad6c829 --- /dev/null +++ b/plugins/python-build/share/python-build/patches/3.7.15/Python-3.7.15/0002-bpo-41100-fix-_decimal-for-arm64-Mac-OS-GH-21228.patch @@ -0,0 +1,37 @@ +From f2595c038ed7bfd182d9d05d83786106ebd02ca0 Mon Sep 17 00:00:00 2001 +From: Lawrence D'Anna <64555057+lawrence-danna-apple@users.noreply.github.com> +Date: Tue, 30 Jun 2020 02:15:46 -0700 +Subject: [PATCH] bpo-41100: fix _decimal for arm64 Mac OS (GH-21228) + +Patch by Lawrence Danna. +--- + .../Core and Builtins/2020-06-30-04-44-29.bpo-41100.PJwA6F.rst | 1 + + Modules/_decimal/libmpdec/mpdecimal.h | 3 +++ + 2 files changed, 4 insertions(+) + create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-06-30-04-44-29.bpo-41100.PJwA6F.rst + +diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-06-30-04-44-29.bpo-41100.PJwA6F.rst b/Misc/NEWS.d/next/Core and Builtins/2020-06-30-04-44-29.bpo-41100.PJwA6F.rst +new file mode 100644 +index 0000000000..d6176d69f0 +--- /dev/null ++++ b/Misc/NEWS.d/next/Core and Builtins/2020-06-30-04-44-29.bpo-41100.PJwA6F.rst +@@ -0,0 +1 @@ ++add arm64 to the allowable Mac OS arches in mpdecimal.h +\ No newline at end of file +diff --git a/Modules/_decimal/libmpdec/mpdecimal.h b/Modules/_decimal/libmpdec/mpdecimal.h +index a67dd9bc12..3e9c8185c3 100644 +--- a/Modules/_decimal/libmpdec/mpdecimal.h ++++ b/Modules/_decimal/libmpdec/mpdecimal.h +@@ -135,6 +135,9 @@ const char *mpd_version(void); + #elif defined(__x86_64__) + #define CONFIG_64 + #define ASM ++ #elif defined(__arm64__) ++ #define CONFIG_64 ++ #define ANSI + #else + #error "unknown architecture for universal build." + #endif +-- +2.37.3 + diff --git a/plugins/python-build/share/python-build/patches/3.7.15/Python-3.7.15/0003-bpo-42351-Avoid-error-when-opening-header-with-non-U.patch b/plugins/python-build/share/python-build/patches/3.7.15/Python-3.7.15/0003-bpo-42351-Avoid-error-when-opening-header-with-non-U.patch new file mode 100644 index 00000000..773b69fa --- /dev/null +++ b/plugins/python-build/share/python-build/patches/3.7.15/Python-3.7.15/0003-bpo-42351-Avoid-error-when-opening-header-with-non-U.patch @@ -0,0 +1,30 @@ +From 245427d207ee88a4ba26a66c3de350bcbcc036f2 Mon Sep 17 00:00:00 2001 +From: Ronald Oussoren +Date: Sat, 14 Nov 2020 16:07:47 +0100 +Subject: [PATCH] bpo-42351: Avoid error when opening header with non-UTF8 + encoding (GH-23279) + +grep_headers_for() would error out when a header contained +text that cannot be interpreted as UTF-8. + +cherry-picked from 7a27c7ed4b by Pedro Fonini +--- + setup.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/setup.py b/setup.py +index f211989aac..467362813d 100644 +--- a/setup.py ++++ b/setup.py +@@ -159,7 +159,7 @@ def is_macosx_sdk_path(path): + + def grep_headers_for(function, headers): + for header in headers: +- with open(header, 'r') as f: ++ with open(header, 'r', errors='surrogateescape') as f: + if function in f.read(): + return True + return False +-- +2.34.1 +