diff --git a/build.sh b/build.sh index df75a264e2..ba2a43a267 100755 --- a/build.sh +++ b/build.sh @@ -576,15 +576,23 @@ setup_cgo_env() { # with "local: *", which hides Go's runtime type symbols and breaks # the PIE absolute relocations). No --whole-archive, so GNU ld's # archive-level GC drops any ORT kernel/EP object nothing references. - local ort_dynamic_list - ort_dynamic_list="$(mktemp "${TMPDIR:-/tmp}/ort_dynamic.XXXXXX.txt")" + # + # The dynamic list is written to a STABLE, project-scoped path (not + # mktemp) so CGO_LDFLAGS is reproducible across builds and survives + # across invocations; its content never changes, so overwriting is + # safe and nothing leaks in /tmp. .cache/ is gitignored. + local ort_dynamic_list="${PROJECT_ROOT}/.cache/ort_dynamic_list.txt" + mkdir -p "$(dirname "$ort_dynamic_list")" printf '{\n OrtGetApiBase;\n};\n' > "$ort_dynamic_list" # --undefined=OrtGetApiBase force-pulls the archive member that # defines OrtGetApiBase (the Go binding reaches ORT only via # dlsym("OrtGetApiBase"), so nothing references it at link time and # it would otherwise be GC'd). From there the minimal build's CPU-EP # registration call chain pulls in the operators the models use. - export CGO_LDFLAGS="$CGO_LDFLAGS -Wl,--undefined=OrtGetApiBase -Wl,--dynamic-list=$ort_dynamic_list$ort_a -lstdc++" + # The explicit space between $ort_dynamic_list and $ort_a keeps the + # two as separate linker arguments regardless of $ort_a's leading + # space. + export CGO_LDFLAGS="$CGO_LDFLAGS -Wl,--undefined=OrtGetApiBase -Wl,--dynamic-list=$ort_dynamic_list $ort_a -lstdc++" echo " onnxruntime (static) → $ONNXRUNTIME_STATIC_PREFIX" # The re2 regex-library collision between onnxruntime.a and # librag_tokenizer_c_api.a is fixed at the .a level in build_cpp(): diff --git a/go.mod b/go.mod index 33ba926ede..d382b52dd1 100644 --- a/go.mod +++ b/go.mod @@ -262,7 +262,7 @@ replace github.com/AkmalOt/gomsg => github.com/xugangqiang/gomsg v0.0.0-20260407 // onnxruntime_go is mirrored to github.com/infiniflow/onnxruntime_go (org-owned // fork of yalue/onnxruntime_go at v1.23.0) so the in-process DeepDoc backend no // longer depends on a personal fork or the upstream repo directly. ONNX Runtime is -// linked statically (no --whole-archive, so kernels nothing references are +// linked statically (no --whole-archive, so unreferenced kernels are // dropped; only OrtGetApiBase is exported, via --dynamic-list), and OrtGetApiBase // is then resolved at runtime via dlopen(NULL) from the running binary, so no // libonnxruntime.so is required. The module path matches the import path, so no diff --git a/internal/development.md b/internal/development.md index 5d7eb734f0..6c3ea216a5 100644 --- a/internal/development.md +++ b/internal/development.md @@ -70,8 +70,10 @@ uv run python3 ragflow_deps/download_deps.py > # OrtGetApiBase is the only symbol that must be visible process-wide. Export > # just it — not via a "local: *" version script, which hides Go's runtime type > # symbols and breaks PIE absolute relocations. There is deliberately no -> # --whole-archive, so unreferenced kernels are dropped. -> printf '{\n OrtGetApiBase;\n};\n' > /tmp/ort_dynamic.txt +> # --whole-archive, so unreferenced kernels are dropped. Write the dynamic +> # list to .cache/ (gitignored), matching build.sh. +> mkdir -p .cache +> printf '{\n OrtGetApiBase;\n};\n' > .cache/ort_dynamic_list.txt > > export CGO_CFLAGS="-I${RAGFLOW_DEPS}/office_oxide/include/office_oxide_c" > export CGO_LDFLAGS="\ @@ -80,7 +82,7 @@ uv run python3 ragflow_deps/download_deps.py > ${RAGFLOW_DEPS}/pdfium-static/lib/libc++.a \ > ${RAGFLOW_DEPS}/pdfium-static/lib/libc++abi.a \ > ${RAGFLOW_DEPS}/pdf_oxide/lib/${PLATFORM}/libpdf_oxide.a \ -> -Wl,--undefined=OrtGetApiBase -Wl,--dynamic-list=/tmp/ort_dynamic.txt ${ORT_A} -lstdc++ \ +> -Wl,--undefined=OrtGetApiBase -Wl,--dynamic-list=.cache/ort_dynamic_list.txt ${ORT_A} -lstdc++ \ > -fuse-ld=lld \ > -lm -lpthread -ldl -lrt -lgcc_s -lutil -lc" > ``` diff --git a/ragflow_deps/download_deps.py b/ragflow_deps/download_deps.py index ec53f9dfa6..cbe4271ed6 100644 --- a/ragflow_deps/download_deps.py +++ b/ragflow_deps/download_deps.py @@ -86,8 +86,8 @@ def get_urls(use_china_mirrors=False) -> list[str | list[str]]: ["https://github.com/yfedoseev/office_oxide/releases/download/v0.1.9/native-linux-x86_64.tar.gz", "office_oxide-linux-x86_64.tar.gz"], # ONNX Runtime static archives for the Go in-process (DeepDoc) # backend. Statically linked into the server binary (see build.sh: - # ONNXRUNTIME_STATIC_PREFIX — no --whole-archive, so kernels nothing - # references are dropped; only OrtGetApiBase is exported, via + # ONNXRUNTIME_STATIC_PREFIX — no --whole-archive, so unreferenced + # kernels are dropped; only OrtGetApiBase is exported, via # --dynamic-list), so no libonnxruntime.so is needed at runtime — # OrtGetApiBase is resolved via dlopen(NULL) (the process-global # symbol table, not the executable's own path). csukuangfj's @@ -135,8 +135,8 @@ def get_urls(use_china_mirrors=False) -> list[str | list[str]]: ["https://github.com/yfedoseev/office_oxide/releases/download/v0.1.9/native-linux-x86_64.tar.gz", "office_oxide-linux-x86_64.tar.gz"], # ONNX Runtime static archives for the Go in-process (DeepDoc) # backend. Statically linked into the server binary (see build.sh: - # ONNXRUNTIME_STATIC_PREFIX — no --whole-archive, so kernels nothing - # references are dropped; only OrtGetApiBase is exported, via + # ONNXRUNTIME_STATIC_PREFIX — no --whole-archive, so unreferenced + # kernels are dropped; only OrtGetApiBase is exported, via # --dynamic-list), so no libonnxruntime.so is needed at runtime — # OrtGetApiBase is resolved via dlopen(NULL) (the process-global # symbol table, not the executable's own path). csukuangfj's