diff --git a/cpython-unix/build-cpython.sh b/cpython-unix/build-cpython.sh index 2dbf09081..2b7929695 100755 --- a/cpython-unix/build-cpython.sh +++ b/cpython-unix/build-cpython.sh @@ -589,6 +589,27 @@ if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_14}" ]; then CONFIGURE_FLAGS="${CONFIGURE_FLAGS} ac_cv_func_explicit_bzero=no" fi +# The modern UAPI overlay provides the memfd constants, but some glibc sysroots +# predate the memfd_create() wrapper. Force the configure check on and weak-link +# the wrapper so the function is exposed only when runtime glibc provides it. +# This workaround is specific to glibc builds; the UAPI overlay itself can also +# be used with other Linux libcs. +if [[ -n "${LINUX_UAPI_INCLUDE_ARCH:-}" && "${TARGET_TRIPLE}" == *-linux-gnu* ]]; then + if [[ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_14}" ]]; then + patch -p1 -i "${ROOT}/patch-posixmodule-memfd-create-weak.patch" + else + patch -p1 -i "${ROOT}/patch-posixmodule-memfd-create-weak-3.13.patch" + fi + + # Python 3.10 checks for memfd_create with a custom compile test instead + # of the cached ac_cv_func_memfd_create check used by newer versions. + if [[ -n "${PYTHON_MEETS_MAXIMUM_VERSION_3_10}" ]]; then + patch -p1 -i "${ROOT}/patch-configure-memfd-create-3.10.patch" + fi + + CONFIGURE_FLAGS="${CONFIGURE_FLAGS} ac_cv_func_memfd_create=yes" +fi + # Define the base PGO profiling task, which we'll extend below with ignores export PROFILE_TASK='-m test --pgo' diff --git a/cpython-unix/patch-configure-memfd-create-3.10.patch b/cpython-unix/patch-configure-memfd-create-3.10.patch new file mode 100644 index 000000000..0b27ad583 --- /dev/null +++ b/cpython-unix/patch-configure-memfd-create-3.10.patch @@ -0,0 +1,22 @@ +diff --git a/configure.ac b/configure.ac +--- a/configure.ac ++++ b/configure.ac +@@ -3822,6 +3822,10 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[void *x=_dyl + ]) + + AC_MSG_CHECKING(for memfd_create) ++if test "$ac_cv_func_memfd_create" = yes; then ++ AC_DEFINE(HAVE_MEMFD_CREATE, 1, Define if you have the 'memfd_create' function.) ++ AC_MSG_RESULT(yes) ++else + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #ifdef HAVE_SYS_MMAN_H + #include +@@ -3834,6 +3838,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no) + ]) ++fi + + AC_MSG_CHECKING(for eventfd) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ diff --git a/cpython-unix/patch-posixmodule-memfd-create-weak-3.13.patch b/cpython-unix/patch-posixmodule-memfd-create-weak-3.13.patch new file mode 100644 index 000000000..7e115b101 --- /dev/null +++ b/cpython-unix/patch-posixmodule-memfd-create-weak-3.13.patch @@ -0,0 +1,35 @@ +diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c +--- a/Modules/posixmodule.c ++++ b/Modules/posixmodule.c +@@ -528,6 +528,12 @@ extern char *ctermid_r(char *); + # include + #endif + ++#ifdef HAVE_MEMFD_CREATE ++/* Weak references. */ ++__attribute__((weak)) ++int memfd_create(const char *name, unsigned int flags); ++#endif ++ + /* eventfd() */ + #ifdef HAVE_SYS_EVENTFD_H + # include +@@ -15718,6 +15724,18 @@ posixmodule_exec(PyObject *m) + { + _posixstate *state = get_posix_state(m); + ++#ifdef HAVE_MEMFD_CREATE ++ if (memfd_create == NULL) { ++ PyObject *dict = PyModule_GetDict(m); ++ if (dict == NULL) { ++ return -1; ++ } ++ if (PyDict_DelItemString(dict, "memfd_create") < 0) { ++ return -1; ++ } ++ } ++#endif ++ + #if defined(HAVE_PWRITEV) + if (HAVE_PWRITEV_RUNTIME) {} else { + PyObject* dct = PyModule_GetDict(m); diff --git a/cpython-unix/patch-posixmodule-memfd-create-weak.patch b/cpython-unix/patch-posixmodule-memfd-create-weak.patch new file mode 100644 index 000000000..229f14ea9 --- /dev/null +++ b/cpython-unix/patch-posixmodule-memfd-create-weak.patch @@ -0,0 +1,35 @@ +diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c +--- a/Modules/posixmodule.c ++++ b/Modules/posixmodule.c +@@ -192,6 +192,12 @@ + # include // memfd_create(), MFD_CLOEXEC + #endif + ++#ifdef HAVE_MEMFD_CREATE ++/* Weak references. */ ++__attribute__((weak)) ++int memfd_create(const char *name, unsigned int flags); ++#endif ++ + #ifdef HAVE_SYS_EVENTFD_H + # include // eventfd() + #endif +@@ -18128,6 +18134,18 @@ posixmodule_exec(PyObject *m) + { + _posixstate *state = get_posix_state(m); + ++#ifdef HAVE_MEMFD_CREATE ++ if (memfd_create == NULL) { ++ PyObject *dict = PyModule_GetDict(m); ++ if (dict == NULL) { ++ return -1; ++ } ++ if (PyDict_PopString(dict, "memfd_create", NULL) < 0) { ++ return -1; ++ } ++ } ++#endif ++ + #if defined(HAVE_PWRITEV) + if (HAVE_PWRITEV_RUNTIME) {} else { + PyObject* dct = PyModule_GetDict(m); diff --git a/pythonbuild/disttests/__init__.py b/pythonbuild/disttests/__init__.py index 14f670629..7314fc3a0 100644 --- a/pythonbuild/disttests/__init__.py +++ b/pythonbuild/disttests/__init__.py @@ -359,6 +359,35 @@ def test_socket_af_vsock(self): def test_os_pidfd_open(self): self.assertTrue(hasattr(os, "pidfd_open")) + @unittest.skipUnless( + "-linux-gnu" in os.environ["TARGET_TRIPLE"], + "memfd_create weak linking is enabled for Linux GNU targets", + ) + def test_os_memfd_create(self): + import ctypes + import errno + + libc = ctypes.CDLL(None) + libc_has_memfd_create = hasattr(libc, "memfd_create") + self.assertEqual(hasattr(os, "memfd_create"), libc_has_memfd_create) + + if not libc_has_memfd_create: + return + + try: + fd = os.memfd_create("python-build-standalone-test") + except OSError as exc: + if exc.errno == errno.ENOSYS: + self.skipTest("the runtime kernel does not support memfd_create") + raise + + try: + os.write(fd, b"memfd_create") + os.lseek(fd, 0, os.SEEK_SET) + self.assertEqual(os.read(fd, 12), b"memfd_create") + finally: + os.close(fd) + def test_linux_uapi_not_in_sysconfig(self): import sysconfig