From 97d98421800bc11479570b567626bfae034b53e7 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 11 Aug 2026 09:33:21 +0000 Subject: [PATCH] fix(CRITICAL): bridge build delayed binding + Docker tolerance + improved preload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit build_unified_bridge.sh: - set -euo → set -eo (avoid unbound var failures) - Drop -ltorch_cuda -lc10_cuda (unavailable at Docker build time) - Add -Wl,--unresolved-symbols=ignore-in-shared-libs ixformer::infer symbols resolved at runtime via RTLD_GLOBAL preload Dockerfile Step 6: - Wrap in (... || echo non-fatal) so Docker build continues if bridge fails ix_unified.py: - 3-phase preload: lib*.so → _ixformer_torch*.so → remaining .so - All loaded with ctypes.RTLD_GLOBAL so symbols visible to bridge - Added /workspace and /home/dylan search paths Verified on real machine: bridge compiles (272K), undefined symbols expected until ixformer .so preloaded at runtime by ix_unified.py --- Dockerfile | 5 +++-- ex_engine/build_unified_bridge.sh | 5 +++-- ex_engine/python/ix_unified.py | 34 ++++++++++++++++++++++++++++--- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index b8e78b9c..fc6e8a2f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -52,9 +52,10 @@ RUN chmod +x /workspace/qwen3_6_scripts/patch_ops.sh && \ bash ./patch_ops.sh 2>&1 | tee /workspace/patch_ops.log ; \ echo "[Dockerfile] patch_ops exit code: $?" -# Step 6: Build ix_unified_bridge.so (links against base image ixformer at runtime) +# Step 6: Build ix_unified_bridge.so (ixformer::infer symbols resolved at runtime via RTLD_GLOBAL preload) +# Tolerant: bridge is optional — corex_moe.py has ixformer.functions fallback RUN chmod +x /workspace/ex_engine/build_unified_bridge.sh && \ - bash /workspace/ex_engine/build_unified_bridge.sh 2>&1 | tee -a /workspace/ex_build.log ; \ + (bash /workspace/ex_engine/build_unified_bridge.sh 2>&1 || echo "[Dockerfile] bridge build FAILED (non-fatal)") | tee -a /workspace/ex_build.log ; \ echo "[Dockerfile] ix_unified_bridge build exit code: $?" # Step 7: Deploy ix_unified and ex_engine Python modules to vllm path diff --git a/ex_engine/build_unified_bridge.sh b/ex_engine/build_unified_bridge.sh index 34026787..cc2d463c 100755 --- a/ex_engine/build_unified_bridge.sh +++ b/ex_engine/build_unified_bridge.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # build_unified_bridge.sh — Compile ix_unified_bridge.so on BI-V100 # Uses manual compiler flags since torch.utils.cpp_extension is stripped from corex torch. -set -euo pipefail +set -eo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SRC_DIR="${SCRIPT_DIR}/csrc/ilu" @@ -34,8 +34,9 @@ $CXX -shared -fPIC -O2 -std=c++17 \ -I"$TORCH_INC" \ -I"$TORCH_INC2" \ -L"$TORCH_LIB" \ - -ltorch -ltorch_cpu -ltorch_cuda -lc10 -lc10_cuda \ + -ltorch -ltorch_cpu -lc10 \ -Wl,--no-as-needed,-rpath,"$TORCH_LIB" \ + -Wl,--unresolved-symbols=ignore-in-shared-libs \ -D_GLIBCXX_USE_CXX11_ABI=0 \ -DTORCH_EXTENSION_NAME=ix_unified_bridge \ "$SRC_DIR/ix_unified_bridge.cpp" \ diff --git a/ex_engine/python/ix_unified.py b/ex_engine/python/ix_unified.py index 960bd2e8..2be65462 100644 --- a/ex_engine/python/ix_unified.py +++ b/ex_engine/python/ix_unified.py @@ -30,12 +30,36 @@ def _load_bridge(): if _bridge is not None: return _bridge - # Pre-load ixformer .so symbols (bridge links against them at runtime) + # Pre-load ixformer .so symbols into GLOBAL symbol table. + # ix_unified_bridge.so has undefined ixformer::infer::* symbols that get + # resolved at runtime. Python default import uses RTLD_LOCAL, so we must + # force RTLD_GLOBAL on the ixformer .so files BEFORE loading our bridge. try: import ctypes, glob as _glob + for _base in ["/usr/local/corex/lib64/python3/dist-packages/ixformer", - "/usr/local/corex/lib/python3/dist-packages/ixformer"]: - for _so in _glob.glob(os.path.join(_base, "**/*.so"), recursive=True): + "/usr/local/corex/lib/python3/dist-packages/ixformer", + "/usr/local/corex/lib64"]: + if not os.path.isdir(_base): + continue + # Phase 1: lib*.so (libixformer.so, libixattn.so — dependencies first) + for _so in sorted(_glob.glob(os.path.join(_base, "lib*.so*"))): + try: + ctypes.CDLL(_so, mode=ctypes.RTLD_GLOBAL) + except Exception: + pass + # Phase 2: _ixformer_torch*.so (contains ixformer::infer::* symbols) + for _so in sorted(_glob.glob(os.path.join(_base, "_ixformer_torch*.so"))): + try: + ctypes.CDLL(_so, mode=ctypes.RTLD_GLOBAL) + logger.info("Preloaded ixformer: %s", _so) + except Exception: + pass + # Phase 3: any remaining .so in subdirs + for _so in sorted(_glob.glob(os.path.join(_base, "**/*.so"), recursive=True)): + bn = os.path.basename(_so) + if bn.startswith("lib") or "_ixformer" in bn: + continue try: ctypes.CDLL(_so, mode=ctypes.RTLD_GLOBAL) except Exception: @@ -50,6 +74,10 @@ def _load_bridge(): search_paths.append(os.path.join(here, "..", "build")) search_paths.append(here) + # 2. Workspace build dirs (Docker / real machine) + search_paths.append("/workspace/ex_engine/build") + search_paths.append("/home/dylan/project_6/ex_engine/build") + # 2. vllm install root (where prebuilt .so are deployed) for p in sys.path: if "vllm" in p or "dist-packages" in p: