From: Geoffrey Thomas Date: Tue, 14 Apr 2026 15:26:19 +0000 (-0400) Subject: gh-133312: configure: add --enable-static-libpython-for-interpreter (#133313) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c88c27b0c1c09c125fe6a5ad78a4d42cf9c3fcd2;p=thirdparty%2FPython%2Fcpython.git gh-133312: configure: add --enable-static-libpython-for-interpreter (#133313) 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. --- diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index bf25de7cc90c..d5c17560b665 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -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 index 000000000000..3ad2db63907e --- /dev/null +++ b/Misc/NEWS.d/next/Build/2025-05-02-17-06-10.gh-issue-133312.YkO6BI.rst @@ -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. diff --git a/configure b/configure index 07c16a4e3787..8620eb3fbdd3 100755 --- 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 diff --git a/configure.ac b/configure.ac index d6e152d42b76..d73b37327fe5 100644 --- a/configure.ac +++ b/configure.ac @@ -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(