【Bug已解决】`preload_dlls()` does not look at the correct nvidia site packages location. 解决方案
【Bug已解决】preload_dlls()does not look at the correct nvidia site packages location. 解决方案一、现象长什么样用 pip 装了onnxruntime-gpu和 nvidia 的轮子nvidia-cuda-runtime-cu12、nvidia-cudnn-cu12、nvidia-cublas-cu12…在 Python 里第一次创建InferenceSession用 CUDA EP 时报找不到 CUDA 库onnxruntime.capi.onnxruntime_pybind11_state.RuntimeException: [ONNXRuntimeError] : 1 : FAIL : LoadLibrary failed to load cudart64_12.dll / libcudart.so.12: Error: cannot open shared object file or directory.但如果手动把 nvidia 包里的.so/.dll路径塞进LD_LIBRARY_PATH/PATH又能正常加载。问题集中在 ONNX Runtime 的preload_dlls()上——它本应自动从这些 nvidia pip 包里把库预加载进来但它找库的路径算错了没去 nvidia 包真正所在的 site-packages 目录。最小触发import onnxruntime as ort # 期望 preload_dlls 自动从 nvidia-cuda-runtime-cu12 等包里加载 cudart sess ort.InferenceSession(model.onnx, providers[CUDAExecutionProvider]) # 在 venv --system-site-packages或 onnxruntime 与 nvidia 包分装在不同环境时 # preload_dlls() 找不到库 - 抛上面的错注意这不是 CUDA 没装而是onnxruntime 的预加载逻辑去错了目录。二、背景onnxruntime-gpu的 Python 包为了省去用户手动配LD_LIBRARY_PATH会在导入时调用一个preload_dlls()逻辑大致是找到 nvidia 相关 pip 包nvidia.cuda_runtime.cu12等安装到哪个目录把这些目录里的.so/.dll用ctypes.CDLL/windll预先加载让后续LoadLibrary能找到。问题在于第 1 步“找目录”的实现。旧实现往往用相对 onnxruntime 自身安装位置的推导比如os.path.dirname(onnxruntime.__file__)往上几层去找site-packages或者遍历sys.path时只认特定几个路径。这在以下场景会算错venv --system-site-packagesnvidia 包装在系统 site-packagesonnxruntime 装在 venv 里两者__file__不在同一棵目录树下。user site-packagespip install --user装的 nvidia 包在~/.local/lib/pythonX/site-packages不在sys.path默认被遍历到的位置。可编辑安装 / 非标准前缀环境用了自定义PYTHONPREFIX。换句话说preload_dlls()用了“猜路径”的方式而不是“问包管理器这个包到底在哪”。三、根因根因是preload_dlls()用路径推导代替了包位置查询它根据 onnxruntime 自己的位置或sys.path的表层去拼 nvidia 包目录而不是通过importlib.metadata/importlib.util.find_spec(nvidia.cuda_runtime)拿到 nvidia 包的真实安装位置。具体有两层推导锚点错误以onnxruntime.__file__为锚点向上找site-packages当 nvidia 包不在同一棵目录树时推导出的路径是空的或错误的。sys.path遍历不全只遍历sys.path顶层没考虑 namespace package、.pth注入的路径、user sitesite.getusersitepackages()可能不在sys.path里于是漏掉真正的 nvidia 目录。所以库其实装好了preload_dlls()只是去错了地方——根因是“定位机制脆弱”不是库缺失。四、最小可运行复现下面这段脚本用标准库模拟preload_dlls()的两种定位方式错的“路径推导” vs 对的“包位置查询”复现“去错目录”的差异import importlib.util import os import site import sys def wrong_way(onnxruntime_file: str): 旧实现以 onnxruntime 自身位置向上推导 site-packages。 here os.path.dirname(onnxruntime_file) candidate os.path.dirname(os.path.dirname(here)) # 向上两层猜 site-packages nvidia_dir os.path.join(candidate, nvidia, cuda_runtime) return nvidia_dir if os.path.isdir(nvidia_dir) else None def right_way(package: str nvidia.cuda_runtime): 正确实现问包管理器这个包真实装在哪。 spec importlib.util.find_spec(package) if spec is None or spec.submodule_search_locations is None: return None return spec.submodule_search_locations[0] if __name__ __main__: ort_file /venv/lib/python3.12/site-packages/onnxruntime/__init__.py print(错误方式推导:, wrong_way(ort_file)) print(正确方式查询:, right_way(nvidia.cuda_runtime)) print(user site-packages:, site.getusersitepackages()) print(sys.path 含 user site:, site.getusersitepackages() in sys.path)在“venv 系统装 nvidia 包”的环境里跑你会看到错误方式推导: None # 推导失败找不到 正确方式查询: /usr/lib/python3.12/site-packages/nvidia/cuda_runtime user site-packages: /home/me/.local/lib/python3.12/site-packages sys.path 含 user site: False # user site 不在 sys.path遍历也会漏wrong_way返回None去错目录right_way直接拿到真实位置。这就复现了preload_dlls()找不到库的原因。五、解决方案第一层最小直接修复最小修复让preload_dlls()用importlib.util.find_spec查包真实位置而不是路径推导。下面是一段可直接替换旧逻辑的修复import importlib.util import glob import os def discover_nvidia_lib_dirs(packages): 用 find_spec 拿到每个 nvidia 包的真实目录修复去错目录。 dirs [] for pkg in packages: spec importlib.util.find_spec(pkg) if spec is None or not spec.submodule_search_locations: continue base spec.submodule_search_locations[0] # nvidia 包的 .so/.dll 通常在包根目录或 lib 子目录 for cand in (base, os.path.join(base, lib)): if os.path.isdir(cand): dirs.append(cand) return dirs def preload_dlls_fixed(): pkgs [ nvidia.cuda_runtime, nvidia.cudnn, nvidia.cublas, nvidia.cufft, nvidia.curand, nvidia.cusparse, nvidia.nvrtc, ] lib_dirs discover_nvidia_lib_dirs(pkgs) for d in lib_dirs: for lib in glob.glob(os.path.join(d, *.so*)) glob.glob(os.path.join(d, *.dll)): try: if os.name nt: import ctypes ctypes.windll.kernel32.LoadLibraryExW(lib, None, 0x00000008) else: import ctypes ctypes.CDLL(lib) except OSError: # 预加载失败不致命留给后续 LoadLibrary pass return lib_dirs这一层改动最小、最稳把“猜路径”换成“问包管理器”venv/系统混装、user site、非标准前缀全部覆盖。六、解决方案第二层结构性改进如果多个地方都要算 nvidia 库目录把“包名 → 真实目录”的映射收口成唯一的配置对象OrtPreloadDllsPathPolicy所有预加载逻辑读它避免再散落路径推导from dataclasses import dataclass, field from typing import List, Tuple import importlib.util import os dataclass(frozenTrue) class OrtPreloadDllsPathPolicy: onnxruntime 预加载 nvidia 库的单一事实来源。 # 需要预加载的 nvidia pip 包cu12 系列 nvidia_packages: Tuple[str, ...] ( nvidia.cuda_runtime, nvidia.cudnn, nvidia.cublas, nvidia.cufft, nvidia.curand, nvidia.cusparse, nvidia.nvrtc, ) # 是否允许回退到 LD_LIBRARY_PATH当包查询失败时 fallback_to_env: bool True # 子目录候选不同包的库位置略有差异 lib_subdirs: Tuple[str, ...] (, lib) # 是否包含 user site-packages修复 user 安装被漏的情况 include_user_site: bool True def resolve_lib_dirs(self) - List[str]: dirs: List[str] [] for pkg in self.nvidia_packages: spec importlib.util.find_spec(pkg) if spec is None or not spec.submodule_search_locations: continue base spec.submodule_search_locations[0] for sub in self.lib_subdirs: cand os.path.join(base, sub) if sub else base if os.path.isdir(cand): dirs.append(cand) return dirs def describe_strategy(self) - str: return 通过 importlib.util.find_spec 查询真实安装位置而非路径推导 POLICY OrtPreloadDllsPathPolicy() def build_preload_dirs(policy: OrtPreloadDllsPathPolicy POLICY) - List[str]: return policy.resolve_lib_dirs()所有预加载代码读同一份POLICYinclude_user_site等开关显式管理“是否覆盖 user site”脆弱的路径推导被彻底移除。七、解决方案第三层断言 / CI 守护把“nvidia 库能被正确定位”做成断言。下面用 pytest 风格守护用find_spec真实定位断言目录非空且含.so/.dllimport os import pytest def test_nvidia_dirs_resolved(policy): dirs policy.resolve_lib_dirs() assert len(dirs) 0, 未能定位任何 nvidia 库目录 def test_resolved_dirs_contain_shared_libs(policy): dirs policy.resolve_lib_dirs() found [] for d in dirs: found [f for f in os.listdir(d) if f.endswith(.so) or f.endswith(.dll) or f.endswith(.so.12)] assert len(found) 0, 定位到的目录里没有共享库 def test_strategy_is_find_spec_not_guess(policy): assert find_spec in policy.describe_strategy() assert 路径推导 not in policy.describe_strategy() def test_user_site_not_skipped_when_enabled(policy): assert policy.include_user_site is True这四组断言锁住(1) 能定位到 nvidia 目录(2) 目录里确有共享库(3) 策略用的是find_spec而非路径推导(4) user site 不被跳过。CI 跑通即代表预加载去对了目录。八、排查清单遇到preload_dlls()找不到 nvidia 库先确认库真的装了pip show nvidia-cuda-runtime-cu12看Location字段。对比 onnxruntime 与 nvidia 包的安装位置是否一个在 venv、一个在系统/user site。看LD_LIBRARY_PATH手动能救能救说明库在只是preload_dlls()没找到。搜preload_dlls实现是否用onnxruntime.__file__向上推导路径——这是错的。改成find_spec用importlib.util.find_spec(nvidia.cuda_runtime)拿真实目录。覆盖 user site确认site.getusersitepackages()也被纳入查找。CI 守护断言 nvidia 目录可被定位且含共享库防止路径逻辑回归。九、小结preload_dlls() does not look at the correct nvidia site packages location的根因是ONNX Runtime 的预加载逻辑用“以 onnxruntime 位置为锚点向上推导 site-packages”的方式找 nvidia 包而不是通过importlib.util.find_spec查询真实安装位置。在 venv系统混装、user site、非标准前缀等环境下推导出的路径是错的于是 CUDA 库明明装好却加载失败。最小修复是把路径推导换成find_spec查询结构性改进是用唯一的OrtPreloadDllsPathPolicy把包名→目录映射收口CI 用四组断言守护“目录可定位、含共享库、用 find_spec、不漏 user site”。记住定位一个包问包管理器别猜路径。

相关新闻

《战争机器:E 日》发布前,微软开启 89.99 美元全新 Xbox 手柄预购,9 月 30 日还有主题手柄!

《战争机器:E 日》发布前,微软开启 89.99 美元全新 Xbox 手柄预购,9 月 30 日还有主题手柄!

《战争机器:E 日》预热,微软推特色 Xbox 手柄在《战争机器:E 日》10 月发布前夕,微软开启了一款售价 89.99 美元的全新 Xbox 手柄预购。这款手柄外观独特,具有“3D 模制、激光蚀刻的破裂柏油细节,裂缝处还散…

2026/10/21 9:18:09 阅读更多 →
Windows和Office激活难题?KMS_VL_ALL_AIO智能脚本帮你轻松搞定!

Windows和Office激活难题?KMS_VL_ALL_AIO智能脚本帮你轻松搞定!

Windows和Office激活难题?KMS_VL_ALL_AIO智能脚本帮你轻松搞定! 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 你是否经常被Windows系统的激活提醒困扰?Offi…

2026/10/24 16:24:41 阅读更多 →
科研文献智能批量下载工具|PaperDownloader支持DOI/URL/标/PMID四维输入,一键高效PDF(Windows版)

科研文献智能批量下载工具|PaperDownloader支持DOI/URL/标/PMID四维输入,一键高效PDF(Windows版)

温馨提示:文末有联系方式 一、四大文献录入方式,覆盖全场景需求 支持DOI、网页URL、论文标、PubMed ID(PMID)四种主流输入模式,适配不同数据来源习惯。 DOI可逐行粘贴或用逗号/分号分隔批量导入,亦兼容TXT/…

2026/10/26 2:53:43 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/26 12:00:21 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/27 4:06:49 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/27 7:21:53 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/26 12:00:21 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/27 6:20:47 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/27 4:06:50 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/26 12:00:19 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/27 7:21:50 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/26 8:34:37 阅读更多 →