From 95d7307eb8f57177da737ec8848eb5417966912e Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 26 Mar 2025 23:19:07 +0000 Subject: [PATCH 1/2] gh-115028: Add support for relocatable installations using $ORIGIN in RPATH This patch adds a new configure option --with-relative-rpath that, when enabled, adds $ORIGIN-based RPATHs to binaries when building Python on Linux. This makes Python installations relocatable so they can be moved to different directories without breaking dynamic library dependencies. Three new variables are introduced to set RPATHs for different components: - PY_RPATH_EXEC: For the Python interpreter binary - PY_RPATH_LIB: For the shared libpython library - PY_RPATH_MOD: For Python extension modules This is a step toward solving the relocatability issues discussed in packaging forums and helps ena --- Makefile.pre.in | 10 +++++++--- Modules/makesetup | 2 +- configure | 48 +++++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 32 +++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 4 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index 9658bfa44b98e4..d3c812f132bfe1 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1,4 +1,4 @@ -# Top-level Makefile for Python +# Top-level Makeile for Python # # As distributed, this file is called Makefile.pre.in; it is processed # into the real Makefile by running the script ./configure, which @@ -58,6 +58,9 @@ DTRACE_HEADERS= @DTRACE_HEADERS@ DTRACE_OBJS= @DTRACE_OBJS@ DSYMUTIL= @DSYMUTIL@ DSYMUTIL_PATH= @DSYMUTIL_PATH@ +PY_RPATH_EXEC= @PY_RPATH_EXEC@ +PY_RPATH_LIB= @PY_RPATH_LIB@ +PY_RPATH_MOD= @PY_RPATH_MOD@ GNULD= @GNULD@ @@ -915,7 +918,8 @@ clinic-tests: check-clean-src $(srcdir)/Lib/test/clinic.test.c # Build the interpreter $(BUILDPYTHON): Programs/python.o $(LINK_PYTHON_DEPS) - $(LINKCC) $(PY_CORE_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/python.o $(LINK_PYTHON_OBJS) $(LIBS) $(MODLIBS) $(SYSLIBS) + $(LINKCC) $(PY_CORE_LDFLAGS) $(LINKFORSHARED) $(PY_RPATH_EXEC) -o $@ Programs/python.o $(LINK_PYTHON_OBJS) $(LIBS) $(MODLIBS) $(SYSLIBS) + platform: $(PYTHON_FOR_BUILD_DEPS) pybuilddir.txt $(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import sys ; from sysconfig import get_platform ; print("%s-%d.%d" % (get_platform(), *sys.version_info[:2]))' >platform @@ -945,7 +949,7 @@ $(LIBRARY): $(LIBRARY_OBJS) $(AR) $(ARFLAGS) $@ $(LIBRARY_OBJS) libpython$(LDVERSION).so: $(LIBRARY_OBJS) $(DTRACE_OBJS) - $(BLDSHARED) -Wl,-h$(INSTSONAME) -o $(INSTSONAME) $(LIBRARY_OBJS) $(MODLIBS) $(SHLIBS) $(LIBC) $(LIBM) + $(BLDSHARED) -Wl,-h$(INSTSONAME) $(PY_RPATH_LIB) -o $(INSTSONAME) $(LIBRARY_OBJS) $(MODLIBS) $(SHLIBS) $(LIBC) $(LIBM) if test $(INSTSONAME) != $@; then \ $(LN) -f $(INSTSONAME) $@; \ fi diff --git a/Modules/makesetup b/Modules/makesetup index 8bb971b152a522..b7e57c2969c198 100755 --- a/Modules/makesetup +++ b/Modules/makesetup @@ -274,7 +274,7 @@ sed -e 's/[ ]*#.*//' -e '/^[ ]*$/d' | ;; esac rule="$file: $objs" - rule="$rule; \$(BLDSHARED) $objs $libs \$(LIBPYTHON) -o $file" + rule="$rule; \$(BLDSHARED) \$(PY_RPATH_MOD) $objs $libs \$(LIBPYTHON) -o $file" echo "$rule" >>$rulesf done done diff --git a/configure b/configure index a058553480ca5a..24cb5ef3dc827b 100755 --- a/configure +++ b/configure @@ -894,6 +894,9 @@ BLDSHARED LDCXXSHARED LDSHARED SHLIB_SUFFIX +PY_RPATH_MOD +PY_RPATH_LIB +PY_RPATH_EXEC DSYMUTIL_PATH DSYMUTIL UNIVERSAL_ARCH_FLAGS @@ -1100,6 +1103,7 @@ with_address_sanitizer with_memory_sanitizer with_undefined_behavior_sanitizer with_thread_sanitizer +with_relative_rpath with_hash_algorithm with_tzpath with_libs @@ -1889,6 +1893,8 @@ Optional Packages: behaviour detector, 'ubsan' (default is no) --with-thread-sanitizer enable ThreadSanitizer data race detector, 'tsan' (default is no) + --with-relative-rpath use relative rpath with $ORIGIN for binaries (Linux + only) --with-hash-algorithm=[fnv|siphash13|siphash24] select hash algorithm for use in Python/pyhash.c (default is SipHash13) @@ -13441,6 +13447,48 @@ esac fi +# Check for --with-relative-rpath +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-relative-rpath" >&5 +printf %s "checking for --with-relative-rpath... " >&6; } + +# Check whether --with-relative-rpath was given. +if test ${with_relative_rpath+y} +then : + withval=$with_relative_rpath; +else case e in #( + e) with_relative_rpath=no ;; +esac +fi + + +# Initialize empty RPATH variables +PY_RPATH_EXEC="" +PY_RPATH_LIB="" +PY_RPATH_MOD="" + +if test "$with_relative_rpath" = "yes"; then + if test "$ac_sys_system" = "Linux"; then + # Define the RPATH settings for each binary type + PY_RPATH_EXEC="-Wl,-rpath,\\\$\$ORIGIN/../\$(PLATLIBDIR)" + PY_RPATH_LIB="-Wl,-rpath,\\\$\$ORIGIN" + PY_RPATH_MOD="-Wl,-rpath,\\\$\$ORIGIN/../../" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no - only supported on Linux" >&5 +printf "%s\n" "no - only supported on Linux" >&6; } + with_relative_rpath=no + fi +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + +# Export these variables for the Makefile + + + + # Set info about shared libraries. diff --git a/configure.ac b/configure.ac index 23bd81ed4431b9..ebaa8c908763ed 100644 --- a/configure.ac +++ b/configure.ac @@ -3356,6 +3356,38 @@ AC_MSG_RESULT([no]) with_tsan="no" ]) +# Check for --with-relative-rpath +AC_MSG_CHECKING([for --with-relative-rpath]) +AC_ARG_WITH([relative-rpath], + [AS_HELP_STRING([--with-relative-rpath], + [use relative rpath with $ORIGIN for binaries (Linux only)])], + [], [with_relative_rpath=no]) + +# Initialize empty RPATH variables +PY_RPATH_EXEC="" +PY_RPATH_LIB="" +PY_RPATH_MOD="" + +if test "$with_relative_rpath" = "yes"; then + if test "$ac_sys_system" = "Linux"; then + # Define the RPATH settings for each binary type + PY_RPATH_EXEC="-Wl,-rpath,\\\$\$ORIGIN/../\$(PLATLIBDIR)" + PY_RPATH_LIB="-Wl,-rpath,\\\$\$ORIGIN" + PY_RPATH_MOD="-Wl,-rpath,\\\$\$ORIGIN/../../" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no - only supported on Linux]) + with_relative_rpath=no + fi +else + AC_MSG_RESULT([no]) +fi + +# Export these variables for the Makefile +AC_SUBST([PY_RPATH_EXEC]) +AC_SUBST([PY_RPATH_LIB]) +AC_SUBST([PY_RPATH_MOD]) + # Set info about shared libraries. AC_SUBST([SHLIB_SUFFIX]) AC_SUBST([LDSHARED]) From 85982dceb42d35409608f4c2be0c894f4f00d394 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 26 Mar 2025 23:34:34 +0000 Subject: [PATCH 2/2] Add NEWS entry --- .../next/Build/2025-03-26-23-34-17.gh-issue-115028.-jEZA-.rst | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Misc/NEWS.d/next/Build/2025-03-26-23-34-17.gh-issue-115028.-jEZA-.rst diff --git a/Misc/NEWS.d/next/Build/2025-03-26-23-34-17.gh-issue-115028.-jEZA-.rst b/Misc/NEWS.d/next/Build/2025-03-26-23-34-17.gh-issue-115028.-jEZA-.rst new file mode 100644 index 00000000000000..3a4d117f87c6d8 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2025-03-26-23-34-17.gh-issue-115028.-jEZA-.rst @@ -0,0 +1,4 @@ +Add a new ``--with-relative-rpath`` configure option that sets $ORIGIN-based +RPATHs for Python binaries when enabled. This is a first step towards making +Python installations more relocatable on Linux by allowing shared libraries +to be found relative to their binary locations. Currently Linux-only.