]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-133312: configure: add --enable-static-libpython-for-interpreter (#133313)
authorGeoffrey Thomas <geofft@ldpreload.com>
Tue, 14 Apr 2026 15:26:19 +0000 (11:26 -0400)
committerGitHub <noreply@github.com>
Tue, 14 Apr 2026 15:26:19 +0000 (16:26 +0100)
This option changes the behavior of --enable-shared to continue to build
the libpython3.x.so shared library, but not use it for linking the
python3 interpreter executable. Instead, the executable is linked
directly against the libpython .o files as it would be with
--disable-shared.

There are two benefits of this change. First, libpython uses
thread-local storage, which is noticeably slower when used in a loaded
module instead of in the main program, because the main program can take
advantage of constant offsets from the thread state pointer but loaded
modules have to dynamically call a function __tls_get_addr() to
potentially allocate their thread-local storage area. (There is another
thread-local storage model for dynamic libraries which mitigates most of
this performance hit, but it comes at the cost of preventing
dlopen("libpython3.x.so"), which is a use case we want to preserve.)

Second, this improves the user experience around relocatable Python a
little bit, in that we don't need to use an $ORIGIN-relative path to
locate libpython3.x.so, which has some mild benefits around musl (which
does not support $ORIGIN-relative DT_NEEDED, only $ORIGIN-relative
DT_RPATH/DT_RUNPATH), users who want to make the interpreter setuid or
setcap (which prevents processing $ORIGIN), etc.

Doc/using/configure.rst
Misc/NEWS.d/next/Build/2025-05-02-17-06-10.gh-issue-133312.YkO6BI.rst [new file with mode: 0644]
configure
configure.ac

index bf25de7cc90c6c081f9ee6b5f32d8add2dadb870..d5c17560b6658a67434a06bab3b6824b49f839d6 100644 (file)
@@ -1012,6 +1012,21 @@ Linker options
 
    .. versionadded:: 3.10
 
+.. option:: --enable-static-libpython-for-interpreter
+
+   Do not link the Python interpreter binary (``python3``) against the
+   shared Python library; instead, statically link the interpreter
+   against ``libpython`` as if ``--enable-shared`` had not been used,
+   but continue to build the shared ``libpython`` (for use by other
+   programs).
+
+   This option does nothing if ``--enable-shared`` is not used.
+
+   The default (when ``-enable-shared`` is used) is to link the Python
+   interpreter against the built shared library.
+
+   .. versionadded:: next
+
 
 Libraries options
 -----------------
diff --git a/Misc/NEWS.d/next/Build/2025-05-02-17-06-10.gh-issue-133312.YkO6BI.rst b/Misc/NEWS.d/next/Build/2025-05-02-17-06-10.gh-issue-133312.YkO6BI.rst
new file mode 100644 (file)
index 0000000..3ad2db6
--- /dev/null
@@ -0,0 +1,8 @@
+Add a new ``./configure`` option
+:option:`--enable-static-libpython-for-interpreter` which, when used
+with :option:`--enable-shared`, continues to build the shared library
+but does not use it for the interpreter. Instead, libpython is
+statically linked into the interpreter, as if :option:`--enable-shared`
+had not been used. This allows you to do a single build and get a Python
+interpreter binary that does not use a shared library but also get a
+shared library for use by other programs.
index 07c16a4e37874e42e7c722bf1f8565cedae51eb1..8620eb3fbdd36beda05e6506da82d982ca6a4d0b 100755 (executable)
--- a/configure
+++ b/configure
@@ -1100,6 +1100,7 @@ enable_wasm_pthreads
 with_suffix
 enable_shared
 with_static_libpython
+enable_static_libpython_for_interpreter
 enable_profiling
 enable_gil
 with_pydebug
@@ -1837,6 +1838,10 @@ Optional Features:
                           no)
   --enable-shared         enable building a shared Python library (default is
                           no)
+  --enable-static-libpython-for-interpreter
+                          even with --enable-shared, statically link libpython
+                          into the interpreter (default is to use the shared
+                          library)
   --enable-profiling      enable C-level code profiling with gprof (default is
                           no)
   --disable-gil           enable support for running without the GIL (default
@@ -7688,6 +7693,22 @@ fi
 
 
 
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-static-libpython-for-interpreter" >&5
+printf %s "checking for --enable-static-libpython-for-interpreter... " >&6; }
+# Check whether --enable-static-libpython-for-interpreter was given.
+if test ${enable_static_libpython_for_interpreter+y}
+then :
+  enableval=$enable_static_libpython_for_interpreter;
+fi
+
+
+if test -z "$enable_static_libpython_for_interpreter"
+then
+  enable_static_libpython_for_interpreter="no"
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_static_libpython_for_interpreter" >&5
+printf "%s\n" "$enable_static_libpython_for_interpreter" >&6; }
+
 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-profiling" >&5
 printf %s "checking for --enable-profiling... " >&6; }
 # Check whether --enable-profiling was given.
@@ -7977,7 +7998,11 @@ if test "$PY_ENABLE_SHARED" = 1 || test "$enable_framework" ; then
         LIBRARY_DEPS="\$(LIBRARY) $LIBRARY_DEPS"
     fi
     # Link Python program to the shared library
-    LINK_PYTHON_OBJS='$(BLDLIBRARY)'
+    if test "$enable_static_libpython_for_interpreter" = "yes"; then
+        LINK_PYTHON_OBJS='$(LIBRARY_OBJS)'
+    else
+        LINK_PYTHON_OBJS='$(BLDLIBRARY)'
+    fi
 else
     if test "$STATIC_LIBPYTHON" = 0; then
         # Build Python needs object files but don't need to build
@@ -9473,7 +9498,12 @@ BOLT_BINARIES='$(BUILDPYTHON)'
 if test "x$enable_shared" = xyes
 then :
 
-  BOLT_BINARIES="${BOLT_BINARIES} \$(INSTSONAME)"
+  if test "x$enable_static_libpython_for_interpreter" = xno
+then :
+
+    BOLT_BINARIES="${BOLT_BINARIES} \$(INSTSONAME)"
+
+fi
 
 fi
 
index d6e152d42b765e297c43302be96291a318786649..d73b37327fe5849f160c703376c06cb65e57bf2c 100644 (file)
@@ -1526,6 +1526,17 @@ fi],
 [AC_MSG_RESULT([yes])])
 AC_SUBST([STATIC_LIBPYTHON])
 
+AC_MSG_CHECKING([for --enable-static-libpython-for-interpreter])
+AC_ARG_ENABLE([static-libpython-for-interpreter],
+   AS_HELP_STRING([--enable-static-libpython-for-interpreter],
+                  [even with --enable-shared, statically link libpython into the interpreter (default is to use the shared library)]))
+
+if test -z "$enable_static_libpython_for_interpreter"
+then
+  enable_static_libpython_for_interpreter="no"
+fi
+AC_MSG_RESULT([$enable_static_libpython_for_interpreter])
+
 AC_MSG_CHECKING([for --enable-profiling])
 AC_ARG_ENABLE([profiling],
               AS_HELP_STRING([--enable-profiling], [enable C-level code profiling with gprof (default is no)]))
@@ -1679,7 +1690,11 @@ if test "$PY_ENABLE_SHARED" = 1 || test "$enable_framework" ; then
         LIBRARY_DEPS="\$(LIBRARY) $LIBRARY_DEPS"
     fi
     # Link Python program to the shared library
-    LINK_PYTHON_OBJS='$(BLDLIBRARY)'
+    if test "$enable_static_libpython_for_interpreter" = "yes"; then
+        LINK_PYTHON_OBJS='$(LIBRARY_OBJS)'
+    else
+        LINK_PYTHON_OBJS='$(BLDLIBRARY)'
+    fi
 else
     if test "$STATIC_LIBPYTHON" = 0; then
         # Build Python needs object files but don't need to build
@@ -2161,11 +2176,14 @@ if test "$Py_BOLT" = 'true' ; then
   fi
 fi
 
-dnl Enable BOLT of libpython if built.
+dnl Enable BOLT of libpython if built and used by the python3 binary.
+dnl (If it is built but not used, we cannot profile it.)
 AC_SUBST([BOLT_BINARIES])
 BOLT_BINARIES='$(BUILDPYTHON)'
 AS_VAR_IF([enable_shared], [yes], [
-  BOLT_BINARIES="${BOLT_BINARIES} \$(INSTSONAME)"
+  AS_VAR_IF([enable_static_libpython_for_interpreter], [no], [
+    BOLT_BINARIES="${BOLT_BINARIES} \$(INSTSONAME)"
+  ])
 ])
 
 AC_ARG_VAR(