您如何在运行时更新此环境变量,以便 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")
当诸如 Python 之类的程序运行时,动态加载器(ld.so.1 或类似的东西)已经读取了 LD_LIBRARY_PATH 并且此后不会注意到任何更改。因此,除非 Python 软件本身评估 LD_LIBRARY_PATH 并使用它来构建库的可能路径名dlopen()
或要使用的等效函数,否则在脚本中设置变量将无效。
鉴于您说它不起作用,假设 Python 没有构建并尝试所有可能的库名称似乎是合理的;它可能仅依赖于 LD_LIBRARY_PATH 。
即使您提供了 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 更灵活。
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")
使用相对于当前工作目录的 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
将 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-changeing-library-path/
注意:我意识到这个问题很老,但是我想为此做出贡献,因为仅接受的答案并不能真正解决我的问题。