diff --git a/cpython-unix/build-cpython.sh b/cpython-unix/build-cpython.sh index 9c65394e..2080a200 100755 --- a/cpython-unix/build-cpython.sh +++ b/cpython-unix/build-cpython.sh @@ -58,6 +58,14 @@ cat Makefile.extra pushd Python-${PYTHON_VERSION} + +if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_15}" ]; then + # add `--enable-relocatable` + patch -p1 -i ${ROOT}/patch-relocatable-flag.patch + # add native support for rpath + patch -p1 -i ${ROOT}/patch-relocatable-link.patch +fi + # configure doesn't support cross-compiling on Apple. Teach it. if [[ "${PYBUILD_PLATFORM}" = macos* ]]; then if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_13}" ]; then @@ -157,10 +165,12 @@ fi # The default build rule for the macOS dylib doesn't pick up libraries # from modules / makesetup. So patch it accordingly. -if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_13}" ]; then - patch -p1 -i ${ROOT}/patch-macos-link-extension-modules-13.patch -else - patch -p1 -i ${ROOT}/patch-macos-link-extension-modules.patch +if [ -n "${PYTHON_MEETS_MAXIMUM_VERSION_3_14}" ]; then + if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_13}" ]; then + patch -p1 -i ${ROOT}/patch-macos-link-extension-modules-13.patch + else + patch -p1 -i ${ROOT}/patch-macos-link-extension-modules.patch + fi fi # Also on macOS, the `python` executable is linked against libraries defined by statically @@ -369,6 +379,11 @@ if [[ "${PYBUILD_PLATFORM}" = macos* ]]; then LDFLAGS="${LDFLAGS} -Wl,-headerpad,40" fi + +if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_15}" ]; then + EXTRA_CONFIGURE_FLAGS="${EXTRA_CONFIGURE_FLAGS} --enable-relocatable" +fi + CPPFLAGS=$CFLAGS CONFIGURE_FLAGS=" @@ -676,7 +691,8 @@ fi # If we're building a shared library hack some binaries so rpath is set. # This ensures we can run the binary in any location without # LD_LIBRARY_PATH pointing to the directory containing libpython. -if [ "${PYBUILD_SHARED}" = "1" ]; then +# In 3.15+, we've upstreamed this behavior +if [[ "${PYBUILD_SHARED}" = "1" && -n "${PYTHON_MEETS_MAXIMUM_VERSION_3_14}" ]]; then if [[ "${PYBUILD_PLATFORM}" = macos* ]]; then # There's only 1 dylib produced on macOS and it has the binary suffix. LIBPYTHON_SHARED_LIBRARY_BASENAME=libpython${PYTHON_MAJMIN_VERSION}${PYTHON_BINARY_SUFFIX}.dylib @@ -816,6 +832,12 @@ if [ "${PYBUILD_SHARED}" = "1" ]; then fi fi fi +else + # For Python 3.15+ on Linux, we still need to define LIBPYTHON_SHARED_LIBRARY for glibc version detection + if [[ "${PYBUILD_PLATFORM}" != macos* ]]; then + LIBPYTHON_SHARED_LIBRARY_BASENAME=libpython${PYTHON_MAJMIN_VERSION}${PYTHON_BINARY_SUFFIX}.so.1.0 + LIBPYTHON_SHARED_LIBRARY=${ROOT}/out/python/install/lib/${LIBPYTHON_SHARED_LIBRARY_BASENAME} + fi fi # Install setuptools and pip as they are common tools that should be in any diff --git a/cpython-unix/patch-relocatable-flag.patch b/cpython-unix/patch-relocatable-flag.patch new file mode 100644 index 00000000..96688a8a --- /dev/null +++ b/cpython-unix/patch-relocatable-flag.patch @@ -0,0 +1,121 @@ +commit 6187c3916ac1e7e6eb2bff7ca5f976c99cbe273b +Author: Zanie Blue +Date: Sat Nov 15 08:47:20 2025 -0600 + + Add an `--enable-relocatable` configure flag + +diff --git a/Makefile.pre.in b/Makefile.pre.in +index 19423c11545..6c9cba59e27 100644 +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -60,6 +60,7 @@ DSYMUTIL= @DSYMUTIL@ + DSYMUTIL_PATH= @DSYMUTIL_PATH@ + + GNULD= @GNULD@ ++RELOCATABLE= @RELOCATABLE@ + + # Shell used by make (some versions default to the login shell, which is bad) + SHELL= /bin/sh -e +diff --git a/configure b/configure +index 9757b3419d3..38f2d4dfbf2 100755 +--- a/configure ++++ b/configure +@@ -949,6 +949,7 @@ LINK_PYTHON_DEPS + LIBRARY_DEPS + HOSTRUNNER + NODE ++RELOCATABLE + STATIC_LIBPYTHON + GNULD + EXPORTSFROM +@@ -1091,6 +1092,7 @@ with_suffix + enable_shared + with_static_libpython + enable_profiling ++enable_relocatable + enable_gil + with_pydebug + with_trace_refs +@@ -1826,6 +1828,8 @@ Optional Features: + no) + --enable-profiling enable C-level code profiling with gprof (default is + no) ++ --enable-relocatable enable build of a relocatable Python distribution ++ (default is no) + --disable-gil enable support for running without the GIL (default + is no) + --enable-pystats enable internal statistics gathering (default is no) +@@ -7673,6 +7677,31 @@ if test "x$enable_profiling" = xyes; then + LDFLAGS="-pg $LDFLAGS" + fi + ++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-relocatable" >&5 ++printf %s "checking for --enable-relocatable... " >&6; } ++# Check whether --enable-relocatable was given. ++if test ${enable_relocatable+y} ++then : ++ enableval=$enable_relocatable; ++fi ++ ++if test -z "$enable_relocatable" ++then ++ enable_relocatable="no" ++fi ++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_relocatable" >&5 ++printf "%s\n" "$enable_relocatable" >&6; } ++ ++if test "x$enable_relocatable" = xyes; then ++ ++printf "%s\n" "#define Py_ENABLE_RELOCATABLE 1" >>confdefs.h ++ ++ RELOCATABLE=yes ++else ++ RELOCATABLE=no ++fi ++ ++ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking LDLIBRARY" >&5 + printf %s "checking LDLIBRARY... " >&6; } + +diff --git a/configure.ac b/configure.ac +index f244e0b71a6..b1c859071f4 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1523,6 +1523,23 @@ if test "x$enable_profiling" = xyes; then + LDFLAGS="-pg $LDFLAGS" + fi + ++AC_MSG_CHECKING([for --enable-relocatable]) ++AC_ARG_ENABLE([relocatable], ++ AS_HELP_STRING([--enable-relocatable], [enable build of a relocatable Python distribution (default is no)])) ++if test -z "$enable_relocatable" ++then ++ enable_relocatable="no" ++fi ++AC_MSG_RESULT([$enable_relocatable]) ++ ++if test "x$enable_relocatable" = xyes; then ++ AC_DEFINE([Py_ENABLE_RELOCATABLE], [1], [Define if --enable-relocatable is used]) ++ RELOCATABLE=yes ++else ++ RELOCATABLE=no ++fi ++AC_SUBST([RELOCATABLE]) ++ + AC_MSG_CHECKING([LDLIBRARY]) + + # Apple framework builds need more magic. LDLIBRARY is the dynamic +diff --git a/pyconfig.h.in b/pyconfig.h.in +index 72870411bc0..76fe6a9b52c 100644 +--- a/pyconfig.h.in ++++ b/pyconfig.h.in +@@ -1733,6 +1733,9 @@ + /* Define if you want to build an interpreter with many run-time checks. */ + #undef Py_DEBUG + ++/* Define if --enable-relocatable is used */ ++#undef Py_ENABLE_RELOCATABLE ++ + /* Defined if Python is built as a shared library. */ + #undef Py_ENABLE_SHARED + diff --git a/cpython-unix/patch-relocatable-link.patch b/cpython-unix/patch-relocatable-link.patch new file mode 100644 index 00000000..5863d9c2 --- /dev/null +++ b/cpython-unix/patch-relocatable-link.patch @@ -0,0 +1,70 @@ +commit 34915211b42a64082e0470ebb9a8c4f2ebb20512 +Author: Zanie Blue +Date: Fri Nov 21 15:44:42 2025 -0600 + + Set linker arguments when `--enabled-relocatable` is used + +diff --git a/Makefile.pre.in b/Makefile.pre.in +index 6c9cba59e27..6c89690c35e 100644 +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -1025,10 +1025,19 @@ libpython$(LDVERSION).so: $(LIBRARY_OBJS) $(DTRACE_OBJS) + fi + + libpython3.so: libpython$(LDVERSION).so +- $(BLDSHARED) $(NO_AS_NEEDED) -o $@ -Wl,-h$@ $^ ++ if [ "$(RELOCATABLE)" = "yes" ]; then \ ++ $(BLDSHARED) $(NO_AS_NEEDED) -o $@ -Wl,-h$@ -Wl,-rpath,'$$ORIGIN' $^; \ ++ else \ ++ $(BLDSHARED) $(NO_AS_NEEDED) -o $@ -Wl,-h$@ $^; \ ++ fi + + libpython$(LDVERSION).dylib: $(LIBRARY_OBJS) +- $(CC) -dynamiclib $(PY_CORE_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(DTRACE_OBJS) $(SHLIBS) $(LIBC) $(LIBM); \ ++ if [ "$(RELOCATABLE)" = "yes" ]; then \ ++ install_name="@executable_path/../lib/libpython$(LDVERSION).dylib"; \ ++ else \ ++ install_name="$(prefix)/lib/libpython$(LDVERSION).dylib"; \ ++ fi; \ ++ $(CC) -dynamiclib $(PY_CORE_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$$install_name -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(DTRACE_OBJS) $(MODLIBS) $(SHLIBS) $(LIBC) $(LIBM); + + + libpython$(VERSION).sl: $(LIBRARY_OBJS) +diff --git a/configure b/configure +index 38f2d4dfbf2..9991932680e 100755 +--- a/configure ++++ b/configure +@@ -13749,7 +13749,13 @@ then + LINKFORSHARED="-Wl,-E -Wl,+s";; + # LINKFORSHARED="-Wl,-E -Wl,+s -Wl,+b\$(BINLIBDEST)/lib-dynload";; + Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; +- Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; ++ Linux*|GNU*) ++ LINKFORSHARED="-Xlinker -export-dynamic" ++ # Add rpath for relocatable builds ++ if test "x$enable_relocatable" = xyes; then ++ LINKFORSHARED="$LINKFORSHARED -Wl,-rpath=\$ORIGIN/../lib" ++ fi ++ ;; + # -u libsys_s pulls in all symbols in libsys + Darwin/*|iOS/*) + LINKFORSHARED="$extra_undefs -framework CoreFoundation" +diff --git a/configure.ac b/configure.ac +index b1c859071f4..f75f41441e2 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3613,7 +3613,13 @@ then + LINKFORSHARED="-Wl,-E -Wl,+s";; + # LINKFORSHARED="-Wl,-E -Wl,+s -Wl,+b\$(BINLIBDEST)/lib-dynload";; + Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; +- Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; ++ Linux*|GNU*) ++ LINKFORSHARED="-Xlinker -export-dynamic" ++ # Add rpath for relocatable builds ++ if test "x$enable_relocatable" = xyes; then ++ LINKFORSHARED="$LINKFORSHARED -Wl,-rpath=\$ORIGIN/../lib" ++ fi ++ ;; + # -u libsys_s pulls in all symbols in libsys + Darwin/*|iOS/*) + LINKFORSHARED="$extra_undefs -framework CoreFoundation"