运行时更改ctypes的LD_LIBRARY_PATH
我该如何在运行时更新这个环境变量,以便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")
5 个回答
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")
即使你给了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的库中获取,但它不能改变那些从来没有rpath的.so文件。patchelf则更灵活。
当像Python这样的程序正在运行时,动态加载器(比如ld.so.1或类似的东西)已经读取了LD_LIBRARY_PATH这个环境变量,并且之后不会再注意到任何变化。所以,除非Python软件本身去检查LD_LIBRARY_PATH,并利用它来构建库的可能路径名,像dlopen()
这样的函数才会使用这个路径,否则在脚本中设置这个变量是没有任何效果的。
既然你说它不工作,那就很有可能Python并不会尝试构建和检查所有可能的库名称;它可能只是依赖于LD_LIBRARY_PATH这个变量。