fix(CRITICAL): bridge build delayed binding + Docker tolerance + improved preload

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
This commit is contained in:
Claude
2026-08-11 09:33:21 +00:00
parent 1d5856f4a9
commit 97d9842180
3 changed files with 37 additions and 7 deletions

View File

@@ -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

View File

@@ -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" \

View File

@@ -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: