linux Python绑定的RPATH传播失败

kcwpcxri  于 2023-10-16  发布在  Linux
关注(0)|答案(1)|浏览(101)

我正在构建一个使用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:

这就是我所期待的,我很高兴。
然而,我还需要通过一些链接到它的python绑定来使用同一个库。为了让它工作,我需要在本例中设置python绑定的RPATH(至少在我的理解中,它只是一个在运行时加载的共享库)。请注意,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]

所以基本上找不到libcublas(也找不到任何其他CUDA库),从而触发了onnxruntime中的回退机制,以避免使用CUDA。
为什么RPATH传播适用于C++应用程序,而不适用于Python扩展?是我遗漏了一些愚蠢的东西,还是与如何在python会话的上下文中加载库有很深的关系?这可能是onnxruntime中的bug的奇怪表现,也许是dlopen做错了什么?
请注意,在onnxruntime本身的Python版本中似乎存在相同的问题:他们的setup.py确保所有依赖项都是预加载的,使用ctypes.CDLLRTLD_GLOBAL

ddrv8njm

ddrv8njm1#

点击此链接:https://wiki.debian.org/RpathIssue。动态链接器ld将在以下位置查找匹配的库:
1.导致查找的库的DT_RPATH动态节属性
1.可执行文件的DT_RPATH动态节属性

  1. LD_LIBRARY_PATH环境变量,除非可执行文件是setuid/setgid。
    1.可执行文件的DT_RUNPATH动态节属性
    1./etc/ld.so.cache
    1.基本库目录(/lib和/usr/lib)
    在你的例子中:
  • 当你使用一个设置了RPATH的C++应用程序时,它会成功,因为规则2适用。对于每个子库或子库,ld使用应用程序RPATH。
  • 当你使用python解释器(没有RPATH)时,当ld试图从你的绑定库(有RPATH)加载libonnxruntime时,它会成功,因为规则1适用
  • 当ld from libonnxruntime(没有RPATH)试图加载另一个lib(比如libcubrint)时,它会失败,因为没有规则适用。

因此,要使libonnxruntime加载libcu,您还必须在libonnxruntime上设置RPATH(以便应用规则1)。
为了帮助调试,可以使用lddtree工具(apt install pax-utils)来获得lib依赖关系的层次视图。

相关问题