Python 绑定的 RPATH 传播失败

ajc*_*ajc 5 c++ linux rpath dlopen python-bindings

onnxruntime我正在构建一个在底层使用的库(Ubuntu 22) 。反过来,onnxruntime使用 CUDA,动态加载一些专用的“后端”。我构建了除 CUDA 库之外的整个代码堆栈,并且没有一个库具有其RPATHRUNPATH设置(使用 进行双重检查readelf -d)。

我构建了两个应用程序,一个是 C++,并直接链接到我的库。该应用程序有其RPATH设置,一切正常。如果我运行它,LD_DEBUG=libs我会看到类似这样的内容(请注意,路径已被编辑,并且我仅显示调试输出的一小部分):

    158834:     calling init: .../install/bin/../lib/libonnxruntime_providers_cuda.so
    158834:
    158834:     find library=libcudnn_ops_infer.so.8 [0]; searching
    158834:      search path=.../install/bin/../lib         (RPATH from file .../install/bin/test)
    158834:       trying file=.../install/bin/../lib/libcudnn_ops_infer.so.8
    158834:
    158834:
    158834:     calling init: .../install/bin/../lib/libcudnn_ops_infer.so.8
    158834:
Run Code Online (Sandbox Code Playgroud)

这就是我所期待的,我很高兴。

但是,我还需要通过一些链接到它的 python 绑定来使用相同的库。为了让它工作,我需要在这种情况下设置RPATHpython 绑定(至少在我看来,它只是一个在运行时加载的共享库)。请注意,Python 可执行文件既没有RPATH也没有RUNPATH设置。这仅部分有效。也就是说,RPATH传播似乎在沿着依赖关系树向下移动时起作用,直到开始搜索 CUDA 库,此时它不再起作用。这是以相同的方式、相同的构建运行完全相同的 onnxruntime API,并在与上面相同的文件夹中使用相同的文件。唯一的区别是 python 扩展层。输出LD_DEBUG如下所示:

    159602:     find library=libonnxruntime.so.1.15.1 [0]; searching
    159602:      search path=.../install/lib/../lib         (RPATH from file .../install/lib/pyext.cpython-310-x86_64-linux-gnu.so)
    159602:       trying file=.../install/lib/../lib/libonnxruntime.so.1.15.1

[...]

    159602:     calling init: .../install/lib/pyext.cpython-310-x86_64-linux-gnu.so
    159602:
    159602:     find library=libonnxruntime_providers_shared.so [0]; searching
    159602:      search path=.../install/lib/../lib         (RPATH from file .../install/lib/pyext.cpython-310-x86_64-linux-gnu.so)
    159602:       trying file=.../install/lib/../lib/libonnxruntime_providers_shared.so
    159602:
    159602:
    159602:     calling init: .../install/lib/../lib/libonnxruntime_providers_shared.so
    159602:
    159602:     find library=libonnxruntime_providers_cuda.so [0]; searching
    159602:      search path=.../install/lib/../lib         (RPATH from file .../install/lib/pyext.cpython-310-x86_64-linux-gnu.so)
    159602:       trying file=.../install/lib/../lib/libonnxruntime_providers_cuda.so
    159602:
    159602:     find library=libcublas.so.11 [0]; searching
    159602:      search cache=/etc/ld.so.cache
    159602:      search path=/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3:/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2:/lib/x86_64-linux-gnu/tls/haswell/x86_64:/lib/x
86_64-linux-gnu/tls/haswell:/lib/x86_64-linux-gnu/tls/x86_64:/lib/x86_64-linux-gnu/tls:/lib/x86_64-linux-gnu/haswell/x86_64:/lib/x86_64-linux-gnu/haswell:/lib/x86_64-
linux-gnu/x86_64:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3:/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2:/usr/lib/x86_64-linux-gnu/tls
/haswell/x86_64:/usr/lib/x86_64-linux-gnu/tls/haswell:/usr/lib/x86_64-linux-gnu/tls/x86_64:/usr/lib/x86_64-linux-gnu/tls:/usr/lib/x86_64-linux-gnu/haswell/x86_64:/usr
/lib/x86_64-linux-gnu/haswell:/usr/lib/x86_64-linux-gnu/x86_64:/usr/lib/x86_64-linux-gnu:/lib/glibc-hwcaps/x86-64-v3:/lib/glibc-hwcaps/x86-64-v2:/lib/tls/haswell/x86_
64:/lib/tls/haswell:/lib/tls/x86_64:/lib/tls:/lib/haswell/x86_64:/lib/haswell:/lib/x86_64:/lib:/usr/lib/glibc-hwcaps/x86-64-v3:/usr/lib/glibc-hwcaps/x86-64-v2:/usr/li
b/tls/haswell/x86_64:/usr/lib/tls/haswell:/usr/lib/tls/x86_64:/usr/lib/tls:/usr/lib/haswell/x86_64:/usr/lib/haswell:/usr/lib/x86_64:/usr/lib            (system search
 path)
    159602:       trying file=/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/libcublas.so.11
    159602:       trying file=/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/libcublas.so.11
    159602:       trying file=/lib/x86_64-linux-gnu/tls/haswell/x86_64/libcublas.so.11

 [...]

    159602:     calling fini: .../install/lib/../lib/libonnxruntime_providers_shared.so [0]

Run Code Online (Sandbox Code Playgroud)

所以基本上libcublas找不到(也没有找到任何其他 CUDA 库),从而触发onnxruntime避免使用 CUDA 的回退机制。

为什么RPATH传播适用于 C++ 应用程序但不适用于 Python 扩展?我是否遗漏了一些愚蠢的东西,或者它与如何在 python 会话上下文中加载库密切相关?这可能是 bug 的奇怪表现onnxruntime,也许是做错了什么dlopen

请注意,Python 版本本身似乎也存在同样的问题onnxruntime:它们setup.py确保所有依赖项都已预先加载,使用ctypes.CDLLwith RTLD_GLOBAL

sou*_*uch 1

点击此链接: https: //wiki.debian.org/RpathIssue。动态链接器ld将在以下位置寻找匹配的库:

  1. 导致查找的库的 DT_RPATH 动态节属性
  2. 可执行文件的 DT_RPATH 动态节属性
  3. LD_LIBRARY_PATH 环境变量,除非可执行文件是 setuid/setgid。
  4. 可执行文件的 DT_RUNPATH 动态节属性
  5. /etc/ld.so.cache
  6. 基本库目录(/lib 和 /usr/lib)

所以在你的情况下:

  • 当您使用设置了 RPATH 的 C++ 应用程序时,它会成功,因为规则 2 适用。对于每个子或子子库 ld 都使用应用程序 RPATH。
  • 当您使用 python 解释器(没有 RPATH)时,当 ld 尝试从绑定库(有 RPATH)加载 libonnxruntime 时,它​​会成功,因为规则 1 适用
  • 当 libonnxruntime (没有 RPATH)中的 ld 尝试加载另一个库(例如 libcublas)时,它会失败,因为没有规则适用。

因此,要使 libonnxruntime 加载 libcublas,您也必须在 libonnxruntime 上设置 RPATH(以便规则 1 适用)。

为了帮助调试,可以使用lddtree工具 ( apt install pax-utils) 来获取 lib 依赖项的分层视图。