diff --git a/packaging/aix/sitecustomize.py b/packaging/aix/sitecustomize.py index e5d18554f9b..1f7d1ba4e2c 100644 --- a/packaging/aix/sitecustomize.py +++ b/packaging/aix/sitecustomize.py @@ -1,21 +1,22 @@ -# AIX: preload libc++abi.a so that __xlcxx_personality_v0 is available -# when pydantic_core's libunwind.a(libunwind.so.1) dependency is resolved. +# AIX: best-effort preload of libc++abi.a with RTLD_GLOBAL. # # Background: -# pydantic_core is a Rust extension module compiled against AIX's libunwind.a. -# libunwind.so.1 declares __xlcxx_personality_v0 as an undefined symbol, -# expecting the IBM XLC++ C++ ABI runtime (libc++abi.a) to provide it. -# Python is compiled with GCC, so libc++abi.a is not loaded at Python startup. -# Without this preload, "import pydantic" raises: -# ImportError: rtld: 0712-001 Symbol __xlcxx_personality_v0 was referenced -# from module /usr/lib/libunwind.a(libunwind.so.1), but a runtime definition -# of the symbol was not found. +# Some C++ extensions compiled with IBM XLC++ declare __xlcxx_personality_v0 +# as an undefined symbol, expecting the IBM XLC++ ABI runtime (libc++abi.a) +# to provide it. Python is compiled with GCC and does not load libc++abi.a +# automatically, so those extensions fail to import without this preload. # -# Fix: load libc++abi.a with RTLD_GLOBAL before any checks run so the symbol -# is available to all subsequently loaded shared modules. +# pydantic_core previously triggered this via a dependency on the IBM-provided +# /usr/lib/libunwind.a(libunwind.so.1), which needs __xlcxx_personality_v0. +# pydantic_core now uses a bundled libunwind derived from the GCC runtime +# (libgcc_s.a), which has no libc++abi.a dependency, so pydantic_core no +# longer requires this preload. It is kept as a best-effort safety net for +# any other XLC++-compiled extension that might be loaded at runtime. # -# AIX 7.2 TL5+ / AIX 7.3: /usr/lib/libc++abi.a(libc++abi.so.1) ships with the OS. -# AIX 7.2 TL4 and earlier: this file is absent; the except clause silently continues. +# Outcome: either the load succeeds (libc++abi.a is present, RTLD_GLOBAL makes +# __xlcxx_personality_v0 available to all subsequent modules) or the except +# clause silently continues (file absent — AIX 7.2 TL4 and earlier — and no +# extension that needs it is present, so nothing breaks). import ctypes as _ctypes try: diff --git a/packaging/aix/stages/01-native-libs.sh b/packaging/aix/stages/01-native-libs.sh index 230436323bf..fd9dc19b4b4 100644 --- a/packaging/aix/stages/01-native-libs.sh +++ b/packaging/aix/stages/01-native-libs.sh @@ -76,6 +76,7 @@ READLINE_VERSION="8.2" # yum install readline-devel SQLITE_VERSION="3.53.0" # built from source (amalgamation) GDBM_VERSION="1.23" # yum install gdbm-devel LIBICONV_VERSION="1.17" # yum install libiconv +LIBUNWIND_VERSION="1.0" # derived from /opt/freeware/lib/libgcc_s.a (GCC runtime) # ─── Helpers ────────────────────────────────────────────────────────────────── @@ -521,6 +522,35 @@ done stage_toolbox_lib libiconv "$LIBICONV_VERSION" \ /opt/freeware/lib/libiconv.a +# ── libunwind (derived from GCC runtime libgcc_s.a) ────────────────────────── +# +# pydantic_core links against libunwind.a(libunwind.so.1). We build this +# archive by extracting the shared object from the GCC runtime libgcc_s.a +# (which contains all _Unwind_* symbols) and re-packaging it under the +# libunwind.so.1 member name that pydantic_core expects. +# +# This avoids the IBM XL C++ Runtime version (/usr/lib/libunwind.a) which +# needs __xlcxx_personality_v0 from libc++abi.a — absent on AIX 7.2 TL2-TL4. +# The GCC-derived version only depends on libc.a, making it fully portable. +if lib_done libunwind "$LIBUNWIND_VERSION"; then + log "libunwind ${LIBUNWIND_VERSION} already staged — skipping" +else + log "Staging libunwind ${LIBUNWIND_VERSION} (from libgcc_s.a)" + GCC_LIBGCC_S=/opt/freeware/lib/libgcc_s.a + if [ ! -f "$GCC_LIBGCC_S" ]; then + log "ERROR: $GCC_LIBGCC_S not found — install GCC from the AIX Toolbox" + exit 1 + fi + _tmpdir="$BUILD_DIR/build/libunwind-tmp" + rm -rf "$_tmpdir" && mkdir -p "$_tmpdir" + (cd "$_tmpdir" && ar -X64 -x "$GCC_LIBGCC_S" shr.o) + cp "$_tmpdir/shr.o" "$_tmpdir/libunwind.so.1" + ar -X64 -rcs "$EMBEDDED_DESTDIR/lib/libunwind.a" "$_tmpdir/libunwind.so.1" + rm -rf "$_tmpdir" + lib_mark libunwind "$LIBUNWIND_VERSION" + log "libunwind ${LIBUNWIND_VERSION} staged" +fi + # ─── Ensure standard directories exist ──────────────────────────────────────── log "Ensuring standard embedded directories exist"