尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

【Bug已解决】onnxruntime-gpu 1.27.0 Linux wheel fails to import without CUDA 13 due to libcudart.so.13 d…

【Bug已解决】onnxruntime-gpu 1.27.0 Linux wheel fails to import without CUDA 13 due to libcudart.so.13 d… 【Bug已解决】onnxruntime-gpu 1.27.0 Linux wheel fails to import without CUDA 13 due to libcudart.so.13 dependency in pybind library 解决方案一、现象长什么样在一台装了 CUDA 12没有 CUDA 13的 Linux 机器上pip install onnxruntime-gpu1.27.0后import onnxruntime直接失败报找不到libcudart.so.13。但用户机器上只有 CUDA 12 的libcudart.so.12于是这个 GPU wheel 完全用不了。现象# 现象 A导入即失败 # ImportError: libcudart.so.13: cannot open shared object file: # No such file or directory # wheel 里的 pybind 扩展硬链接了 libcudart.so.13 # 现象 B系统有 CUDA 12 但不想/不能装 CUDA 13 # 用户 CUDA 12 环境完全正常却因为一个 .13 的硬编码依赖被拒之门外 # 现象 CCUDA 12 的 wheel 标签误导 # 发布的 wheel 文件名标注 cu12但内部 pybind 实际链接的是 .13 # 标签与真实依赖不一致最坑的是现象 A用户按 wheel 名的cu12标签装了结果导入就崩还得去查ldd才发现内部依赖的是.13典型的“标签骗人、依赖硬编码”。二、背景pip上的onnxruntime-gpuwheel 按 CUDA 大版本打标签如cu12*、cu13*。wheel 里的 pybind11 扩展.so在链接时会记录它依赖的 CUDA 运行时库名libcudart.so.major。构建这个 wheel 时用的 CUDA 工具链如果是 13.x链接器就会把libcudart.so.13写死进.so的NEEDED列表。问题在于1.27.0 的cu12标签 wheel错误地用 CUDA 13 工具链构建或构建脚本的 CUDA 路径指向了 13导致.so依赖.13但 wheel 名却标cu12。于是装在没有 CUDA 13 的机器上import时动态链接器找不到.13直接失败。这是发布/打包审查里典型的坑wheel 的 CUDA 依赖版本由构建工具链决定和 wheel 的版本标签不一致且硬性依赖了特定 major 的运行时库。三、根因构建工具链版本错配cu12wheel 用了 CUDA 13 工具链构建.so链接了libcudart.so.13与标签不符。硬性依赖特定 major 运行时pybind 扩展在链接时把libcudart.so.13写死进NEEDED没有用-l:cudart.so.12之类允许 minor 兼容、也没做DT_RUNPATH软解析导致缺.13即崩。缺少 wheel 导入的冒烟测试CI 发布前没在“只有 CUDA 12”的干净容器里import onnxruntime这个硬依赖未被发现。本质是wheel 构建工具链版本与标签不一致cu12 标签却链 .13硬性依赖特定 major 运行时且缺导入冒烟测试。四、最小可运行复现下面用 Python 模拟“wheel 标签 cu12 但 .so 依赖 libcudart.so.13导入时找不到”import subprocess, sys def check_wheel_deps_buggy(wheel_cuda_tag, so_needs): buggy: 标签 cu12但 .so NEEDED 写死 libcudart.so.13。 if wheel_cuda_tag cu12 and libcudart.so.13 in so_needs: return False, label cu12 but depends on libcudart.so.13 - import fails on CUDA12 return True, ok def check_wheel_deps_fixed(wheel_cuda_tag, so_needs): fixed: 标签与依赖 major 必须一致cu12 - libcudart.so.12。 expect {cu12: libcudart.so.12, cu13: libcudart.so.13} if so_needs ! [expect[wheel_cuda_tag]]: return False, flabel {wheel_cuda_tag} mismatches NEEDED {so_needs} return True, ok print(check_wheel_deps_buggy(cu12, [libcudart.so.13])) # (False, label cu12 but depends on libcudart.so.13 ...) print(check_wheel_deps_fixed(cu12, [libcudart.so.12])) # (True, ok)buggy标签/依赖错位fixed要求一致。五、解决方案第一层最小直接修复最小修复用与 wheel 标签匹配的 CUDA 工具链构建且链接时用libcudart.so.tag_major而非硬编码.13# 修正构建 cu12 wheel 必须用 CUDA 12 工具链 export CUDA_HOME/usr/local/cuda-12 # 而非 cuda-13 # 链接时显式指向对应 major 运行时 WHEEL_CUDA_MAJOR12 # pybind 扩展的 setup.py / CMake 里 # target_link_libraries(pywrap PRIVATE cudart) # 并确保链接器解析到 libcudart.so.12由 CUDA_HOME 决定 python setup.py bdist_wheel # 产物 NEEDED 应为 libcudart.so.12并在发布前用ldd校验ldd onnxruntime/capi/onnxruntime_pybind11_state.so | grep cudart # 必须显示 libcudart.so.12对应 cu12 标签这一层改动最小对齐工具链与标签依赖 major 一致导入恢复。但依赖“每次发布都校验”下看第二层。六、解决方案第二层结构性改进把“wheel 标签与 CUDA 运行时依赖 major 必须一致、且发布前必须校验”固化成单一事实来源。下面这个 dataclass 集中管理 wheel 依赖契约from dataclasses import dataclass, field from typing import Dict dataclass class OrtWheelCudaDepPolicy: 单一事实来源onnxruntime-gpu wheel 的 CUDA 依赖契约。 # 标签 major - 期望的 libcudart NEEDED _expected: Dict[str, str] field(default_factorylambda: { cu12: libcudart.so.12, cu13: libcudart.so.13, }) def verify(self, wheel_cuda_tag: str, so_needs: list) - None: expect self._expected.get(wheel_cuda_tag) if expect is None: raise ValueError(funknown wheel tag {wheel_cuda_tag}) if so_needs ! [expect]: raise AssertionError( fwheel label {wheel_cuda_tag} expects NEEDED [{expect}], fbut .so requires {so_needs}) def expected_runtime(self, wheel_cuda_tag: str) - str: return self._expected[wheel_cuda_tag]这一层的关键收益标签-依赖一致性verify强制 wheel 标签的 major 与.soNEEDED 完全一致发布门禁发布前调verify错位直接失败杜绝“标签骗人”单一事实来源所有 wheel CUDA 依赖约定收口在OrtWheelCudaDepPolicy。七、解决方案第三层断言 / CI 守护把第二层钉成 pytest挂进 CI作为发布门禁import pytest from your_package.ort_wheel_cuda import OrtWheelCudaDepPolicy def test_cu12_wheel_requires_cudart12(): # 断言 1cu12 wheel 的 .so 必须依赖 libcudart.so.12 p OrtWheelCudaDepPolicy() p.verify(cu12, [libcudart.so.12]) def test_cu13_wheel_requires_cudart13(): # 断言 2cu13 wheel 依赖 .13 p OrtWheelCudaDepPolicy() p.verify(cu13, [libcudart.so.13]) def test_mismatch_rejected(): # 断言 3cu12 标签却依赖 .13 必须报错复现原 bug p OrtWheelCudaDepPolicy() with pytest.raises(AssertionError): p.verify(cu12, [libcudart.so.13]) def test_unknown_tag_rejected(): # 断言 4未知标签报错 p OrtWheelCudaDepPolicy() with pytest.raises(ValueError): p.verify(cu99, [libcudart.so.99])四条断言从“cu12→.12”“cu13→.13”“错位拒绝”“未知拒绝”四面把依赖错位钉死在发布 CI。八、排查清单import onnxruntime报找不到libcudart.so.13时ldd onnxruntime/capi/onnxruntime_pybind11_state.so | grep cudart看实际依赖哪个 major。和 wheel 标签cu12/cu13是否一致不一致就是构建工具链错配cu12 wheel 用了 CUDA 13 工具链。重新用对应 CUDA 工具链构建。wheel 发布前是否在“只有对应 CUDA 版本”的干净容器里import冒烟没冒烟就发布必踩。用第二层OrtWheelCudaDepPolicy发布门禁校验标签与 NEEDED 一致。加第三层 pytest断言“cu12→.12、cu13→.13、错位拒绝、未知拒绝”。wheel 标签是给用户看的契约必须与内部真实依赖严格一致否则“标签骗人”。九、小结onnxruntime-gpu 1.27.0的 Linux wheel 导入失败本质是**cu12标签的 wheel 错误地用 CUDA 13 工具链构建pybind 扩展硬链接了libcudart.so.13与标签不符**导致没有 CUDA 13 的机器import即崩且发布前缺导入冒烟测试。修复分三层——第一层用与标签匹配的 CUDA 工具链构建并ldd校验依赖 major第二层用OrtWheelCudaDepPolicy这个 dataclass 把“标签与 NEEDED major 一致性”收口成单一事实来源并作发布门禁第三层用四条 pytest 把“cu12→.12、cu13→.13、错位拒绝、未知拒绝”钉死在 CI。核心心法wheel 的 CUDA 版本标签是与用户的契约必须与内部.so真实依赖的运行时 major 严格一致发布前必须在对应 CUDA 环境的干净容器里做导入冒烟。
返回列表