在运行时为 ctypes 更改 LD_LIBRARY_PATH

Posted

技术标签:

【中文标题】在运行时为 ctypes 更改 LD_LIBRARY_PATH【英文标题】:Changing LD_LIBRARY_PATH at runtime for ctypes 【发布时间】:2010-10-25 18:16:39 【问题描述】:

如何在运行时更新此环境变量,以便 ctypes 可以在任何地方加载库?我尝试了以下方法,但似乎都不起作用。

from ctypes import *
os.environ['LD_LIBRARY_PATH'] = "/home/starlon/Projects/pyCFA635/lib"  
os.putenv('LD_LIBRARY_PATH', "/home/starlon/Projects/pyCFA635/lib")  
lib = CDLL("libevaluator.so")

【问题讨论】:

【参考方案1】:

当诸如 Python 之类的程序运行时,动态加载器(ld.so.1 或类似的东西)已经读取了 LD_LIBRARY_PATH,之后不会注意到任何变化。因此,除非 Python 软件本身评估 LD_LIBRARY_PATH 并使用它为 dlopen() 或要使用的等效函数构建库的可能路径名,否则在脚本中设置变量将无效。

鉴于您说它不起作用,假设 Python 没有构建并尝试所有可能的库名称似乎是合理的;它可能仅依赖于 LD_LIBRARY_PATH。

【讨论】:

【参考方案2】:

即使您提供了 CDLL 或 cdll.LoadLibrary() 的完全限定路径,您可能仍需要在调用 Python 之前设置 LD_LIBRARY_PATH。如果您加载的共享库显式引用另一个共享库,并且没有在 .so 中为该库设置“rpath”,那么即使它已经加载,也不会找到它。库中的 rpath 指定用于搜索该库所需的其他库的搜索路径

例如,我有一组相互依赖的第三方库不是我制作的案例。 b.so 引用 a.so。即使我提前加载了 a.so:

ctypes.cdll.LoadLibrary('/abs/path/to/a.so')
ctypes.cdll.LoadLibrary('/abs/path/to/b.so')

我在第二次加载时遇到错误,因为 b.so 仅指“a.so”,没有 rpath,因此 b.so 不知道这是正确的 a.so。所以我必须提前设置 LD_LIBRARY_PATH 以包含'/abs/path/to'。

为避免必须设置 LD_LIBRARY_PATH,请修改 .so 文件中的 rpath 条目。在 Linux 上,我发现有两个实用程序可以执行此操作:chrpath 和 patchelf。 chrpath 可从 Ubuntu 存储库中获得。它不能改变 .so 上从未有过的 rpath。 patchelf 更灵活。

【讨论】:

关于使用 patchelf 的重要提示。 patchelf --set-rpath ./ somelib.so 解决了 somelib.so 的问题,它加载了位于同一路径中的另一个 lib.so。 如果您在 Linux 上运行并且可以链接 b.so,为我解决此问题的一个选项是添加 -Wl,--enable-new-dtags -Wl,-rpath=\ $ORIGIN 到您的链接器行,这样 readelf -d b.so | grep RUNPATH 显示 (RUNPATH) 库运行路径:[$ORIGIN]。这允许首先搜索 LD_LIBRARY_PATH,否则应该“正常工作”以解决 b.so 文件路径中缺少的依赖项。 或者,您可以设置 LD_LIBRARY_PATH 并使用相同的命令行参数重新启动 Python 解释器。详情请见***.com/a/25457751/603136。【参考方案3】:

CDLL 可以传递一个完全限定的路径名​​,例如,我在我的一个脚本中使用以下内容,其中 .so 与 python 脚本位于同一目录中。

import os
path = os.path.dirname(os.path.realpath(__file__))
dll = CDLL("%s/iface.so"%path)

在你的情况下,以下就足够了。

from ctypes import *
lib = CDLL("/home/starlon/Projects/pyCFA635/lib/libevaluator.so")

【讨论】:

【参考方案4】:

使用相对于当前工作目录的 rpath 编译您的二进制文件,例如:

gcc -shared -o yourbinary.so yoursource.c otherbinary.so \
    -Wl,-rpath='.',-rpath='./another/relative/rpath' -fpic

然后,您可以在运行时更改 python 中的工作目录:

import os
os.chdir('/path/to/your/binaries')

像这样,加载器还会找到其他动态库,例如 otherbinary.so

【讨论】:

只有当加载库的进程的工作目录是库的目录时才有效。否则,相对运行时路径找不到依赖,其目录是相对于库的。【参考方案5】:

将 LD_LIBRARY_PATH 设置为放置库的路径在此处不起作用,并且 ctypes 不会注意到任何更改。因此,您需要在源代码中设置它并在脚本之前运行 ldconfig 以考虑到这一点。此外,在脚本中设置 os 环境或任何 PATH 变量都将不起作用。

我遇到了类似的问题,花了大约一天的时间来解决这个问题。

mkdir -p /etc/ld.so.conf.d/
echo "/home/starlon/Projects/pyCFA635/lib" > /etc/ld.so.conf.d/mycustomPath.conf

ldconfig

然后验证路径是否设置为:

ldconfig -v | less

完成后,尝试运行您的脚本。这对我有用,也应该对你有用。

你可以看到下面的 URL 帮助我解决了这个问题:

https://www.cyberciti.biz/faq/linux-setting-changing-library-path/

注意:我意识到这个问题很老,但是我想为此做出贡献,因为仅接受的答案并不能真正解决我的问题。

【讨论】:

您提出的方法需要root权限。但是运行想要的程序的用户不需要root.... @lg53 基本上 ldconfig 需要知道路径,所以如果你使用非标准的自定义路径,则需要进行必要的更改来解决这个问题。

以上是关于在运行时为 ctypes 更改 LD_LIBRARY_PATH的主要内容,如果未能解决你的问题,请参考以下文章

在方向更改时为 UICollectionView 设置动画

使用 ctypes 更改共享库中的值

在编辑节点 (C#) 时为 TreeView 提交更改很热?

属性 Visibility 更改时为 StackPanel 设置动画

Xcode 在更改时为每个应用程序目标编译情节提要

如何使用 ctypes 在 python 中查看指针值的变化