@@ -688,105 +688,45 @@ if [ "${PYBUILD_SHARED}" = "1" ]; then
688
688
-change /install/lib/${LIBPYTHON_SHARED_LIBRARY_BASENAME} @executable_path/../lib/${LIBPYTHON_SHARED_LIBRARY_BASENAME} \
689
689
${ROOT} /out/python/install/bin/python${PYTHON_MAJMIN_VERSION}${PYTHON_BINARY_SUFFIX}
690
690
fi
691
- else # (not macos)
691
+ else
692
692
LIBPYTHON_SHARED_LIBRARY_BASENAME=libpython${PYTHON_MAJMIN_VERSION}${PYTHON_BINARY_SUFFIX} .so.1.0
693
693
LIBPYTHON_SHARED_LIBRARY=${ROOT} /out/python/install/lib/${LIBPYTHON_SHARED_LIBRARY_BASENAME}
694
694
695
- # Although we are statically linking libpython, some extension
696
- # modules link against libpython.so even though they are not
697
- # supposed to do that. If you try to import them on an
698
- # interpreter statically linking libpython, all the symbols they
699
- # need are resolved from the main program (because neither glibc
700
- # nor musl has two-level namespaces), so there is hopefully no
701
- # correctness risk, but they need to be able to successfully
702
- # find libpython.so in order to load the module. To allow such
703
- # extensions to load, we set an rpath to point at our lib
704
- # directory, so that if anyone ever tries to find a libpython,
705
- # they successfully find one. See
706
- # https://github.com/astral-sh/python-build-standalone/issues/619
707
- # for some reports of extensions that need this workaround.
708
- #
709
- # Note that this matches the behavior of Debian/Ubuntu/etc.'s
710
- # interpreter (if package libpython3.x is installed, which it
711
- # usually is thanks to gdb, vim, etc.), because libpython is in
712
- # the system lib directory, as well as the behavior in practice
713
- # on conda-forge miniconda and probably other Conda-family
714
- # Python distributions, which too set an rpath.
715
- #
716
- # There is a downside of making this libpython locatable: some user
717
- # code might do e.g.
718
- # ctypes.CDLL(f"libpython3.{sys.version_info.minor}.so.1.0")
719
- # to get at things in the CPython API not exposed to pure
720
- # Python. This code may _silently misbehave_ on a
721
- # static-libpython interpreter, because you are actually using
722
- # the second copy of libpython. For loading static data or using
723
- # accessors, you might get lucky and things will work, with the
724
- # full set of dangers of C undefined behavior being possible.
725
- # However, there are a few reasons we think this risk is
726
- # tolerable. First, we can't actually fix it by not setting the
727
- # rpath - user code may well find a system libpython3.x.so or
728
- # something which is even more likely to break. Second, this
729
- # exact problem happens with Debian, Conda, etc., so it is very
730
- # unlikely (compared to the extension modules case above) that
731
- # any widely-used code has this problem; the risk is largely
732
- # backwards incompatibility of our own builds. Also, it's quite
733
- # easy for users to fix: simply do
734
- # ctypes.CDLL(None)
735
- # (i.e., dlopen(NULL)), to use symbols already in the process;
736
- # this will work reliably on all interpreters regardless of
737
- # whether they statically or dynamically link libpython. Finally,
738
- # we can (and should, at some point) add a warning, error, or
739
- # silent fix to ctypes for user code that does this, which will
740
- # also cover the case of other libpython3.x.so files on the
741
- # library search path that we cannot suppress.
742
- #
743
- # In the past, when we dynamically linked libpython, we avoided
744
- # using an rpath and instead used a DT_NEEDED entry with
745
- # $ORIGIN/../lib/libpython.so, because LD_LIBRARY_PATH takes
746
- # precedence over DT_RUNPATH, and it's not uncommon to have an
747
- # LD_LIBRARY_PATH that points to some sort of unwanted libpython
748
- # (e.g., actions/setup-python does this as of May 2025).
749
- # Now, though, because we're not actually using code from the
750
- # libpython that's loaded and just need _any_ file of that name
751
- # to satisfy the link, that's not a problem. (This also implies
752
- # another approach to the problem: ensure that libraries find an
753
- # empty dummy libpython.so, which allows the link to succeed but
754
- # ensures they do not use any unwanted symbols. That might be
755
- # worth doing at some point.)
756
- patchelf --set-rpath " \$ ORIGIN/../lib" \
757
- ${ROOT} /out/python/install/bin/python${PYTHON_MAJMIN_VERSION}
758
-
759
- if [ -n " ${PYTHON_BINARY_SUFFIX} " ]; then
695
+ if [ " ${CC} " == " musl-clang" ]; then
696
+ # musl does not support $ORIGIN in DT_NEEDED, so we use RPATH instead. This could be
697
+ # problematic, i.e., we could load the shared library from the wrong location if
698
+ # `LD_LIBRARY_PATH` is set, but there's not a clear alternative at this time. The
699
+ # long term solution is probably to statically link to libpython instead.
760
700
patchelf --set-rpath " \$ ORIGIN/../lib" \
761
- ${ROOT} /out/python/install/bin/python${PYTHON_MAJMIN_VERSION}${PYTHON_BINARY_SUFFIX}
762
- fi
701
+ ${ROOT} /out/python/install/bin/python${PYTHON_MAJMIN_VERSION}
763
702
764
- # For libpython3.so (the ABI3 library for embedders), we do
765
- # still dynamically link libpython3.x.so.1.0 (the
766
- # version-specific library), because there is no particular
767
- # speedup/benefit in statically linking libpython into
768
- # libpython3.so, and we'd just be shipping a third copy of the
769
- # libpython code. Therefore we use the old logic for that and
770
- # set an $ORIGIN-relative DT_NEEDED, at least for glibc.
771
- # Unfortunately, musl does not (as of May 2025) support $ORIGIN
772
- # in DT_NEEDED, only in DT_RUNPATH/RPATH, so we did set an rpath
773
- # for bin/python3, and still do for libpython3.so. In both
774
- # cases, we have no concerns/need no workarounds for code
775
- # referencing libpython3.x.so.1.0, because we are actually
776
- # dynamically linking it and so all code will get the real
777
- # libpython3.x.so.1.0 that they want.
778
- if [ " ${CC} " == " musl-clang" ]; then
779
703
# libpython3.so isn't present in debug builds.
780
704
if [ -z " ${CPYTHON_DEBUG} " ]; then
781
705
patchelf --set-rpath " \$ ORIGIN/../lib" \
782
706
${ROOT} /out/python/install/lib/libpython3.so
783
707
fi
708
+
709
+ if [ -n " ${PYTHON_BINARY_SUFFIX} " ]; then
710
+ patchelf --set-rpath " \$ ORIGIN/../lib" \
711
+ ${ROOT} /out/python/install/bin/python${PYTHON_MAJMIN_VERSION}${PYTHON_BINARY_SUFFIX}
712
+ fi
784
713
else
714
+ # If we simply set DT_RUNPATH via --set-rpath, LD_LIBRARY_PATH would be used before
715
+ # DT_RUNPATH, which could result in confusion at run-time. But if DT_NEEDED contains a
716
+ # slash, the explicit path is used.
717
+ patchelf --replace-needed ${LIBPYTHON_SHARED_LIBRARY_BASENAME} " \$ ORIGIN/../lib/${LIBPYTHON_SHARED_LIBRARY_BASENAME} " \
718
+ ${ROOT} /out/python/install/bin/python${PYTHON_MAJMIN_VERSION}
719
+
785
720
# libpython3.so isn't present in debug builds.
786
721
if [ -z " ${CPYTHON_DEBUG} " ]; then
787
722
patchelf --replace-needed ${LIBPYTHON_SHARED_LIBRARY_BASENAME} " \$ ORIGIN/../lib/${LIBPYTHON_SHARED_LIBRARY_BASENAME} " \
788
723
${ROOT} /out/python/install/lib/libpython3.so
789
724
fi
725
+
726
+ if [ -n " ${PYTHON_BINARY_SUFFIX} " ]; then
727
+ patchelf --replace-needed ${LIBPYTHON_SHARED_LIBRARY_BASENAME} " \$ ORIGIN/../lib/${LIBPYTHON_SHARED_LIBRARY_BASENAME} " \
728
+ ${ROOT} /out/python/install/bin/python${PYTHON_MAJMIN_VERSION}${PYTHON_BINARY_SUFFIX}
729
+ fi
790
730
fi
791
731
fi
792
732
fi
0 commit comments