python使用CDLL加载c库,在python路径中看不到库

时间:2012-02-04 18:46:48

标签: python ctypes lammps

我正在尝试使用一些开源学术代码(项目主页为here)。它是一个很大的C ++代码库,有一个(非常)瘦的python包装器,它使用CDLL加载C ++并调用一些可用的C函数来允许代码的原始python脚本。

但是,初始导入代码崩溃是因为它无法在site-packages中找到它旁边的.so文件:

在已安装的文件中:

from ctypes import *

try:
  self.lib = CDLL("_lammps.so")
except:
  try:
    self.lib = CDLL("_lammps_serial.so")
  except:
    raise OSError,"Could not load LAMMPS dynamic library"

并在脚本或解释器中:

from lammps import lammps
l = lammps()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "lammps.py", line 42, in __init__
    raise OSError,"Could not load LAMMPS dynamic library"
OSError: Could not load LAMMPS dynamic library

其他答案might seem to have this covered,但只有在实际调用的脚本(或运行解释器的提示的工作目录)中调用CDLL()时才有效 - 即如果'相对路径'是在用户空间,而不是python-library-space。

我们如何可靠地安装导入我们自己构建的C / C ++库?没有污染像/usr/lib这样的系统库位置,这不是一个非常pythonic,我看不到一个简单的解决方案。

(编辑:更正的功能名称,不明确的重构无益!抱歉!)

5 个答案:

答案 0 :(得分:3)

我在linux上,我所做的一切都是为了解决这个问题,它是从os模块的绝对路径中进行的,并且可以正常工作

from ctypes import *
import os

xss = cdll.LoadLibrary(os.path.abspath("libxss.so.1"))
print xss.xss_test_1()

这也是python 2.7。

答案 1 :(得分:1)

在strace -eopen下运行,你会看到如下内容:

open("tls/x86_64/_lammps.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("tls/_lammps.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("x86_64/_lammps.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("_lammps.so", O_RDONLY|O_CLOEXEC)  = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
open("/lib/_lammps.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib/_lammps.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

其中显示了python ctypes查找库的所有位置。 到目前为止,我无法找到运行时环境变量tweak以使其在我的系统上添加搜索位置,也许你必须使用绝对路径。

答案 2 :(得分:1)

您可以在执行导入的包中使用__file__变量。只需使用os.path的各种函数从__file__中提取完整的绝对目录路径,然后将其连接到库文件名。类似的东西:

temp = os.path.abspath(__file__)
temp = os.path.realpath(temp)
temp = os.path.dirname(temp)
temp = os.path.join(temp, "_lammps.so")
lib = CDLL(path)

您可能还想尝试使用核心文件名的各种变体(即使用.dll.dylib代替.so,并使用和不使用lib前缀,如果你想要独立于平台,你的构建系统可能会产生这样的东西,甚至可能附加版本号。然后,您可以尝试多个版本,或者只使用glob.glob来帮助您找到可接受的版本。

我必须说,我认为标准库中不存在这样的函数是很奇怪的。 ctypes.util.find_library对于这种用途(我认为很普遍)来说不够灵活(或彻底)。即使只是通过PYTHONPATH搜索文件的函数也会非常有用(虽然不难写)。

然后,似乎如果您只是将正确的目录添加到LD_LIBRARY_PATH,则should be able to load it

答案 3 :(得分:0)

您必须指定绝对路径。请尝试以下操作:

import os
from ctypes import *

try:
  slib = os.getcwd() + '/' +'_lammps.so'
  hlibc = CDLL(slib)
  hilbc.FunctionName()
except:
  try:
    slib = os.getcwd() + '/' +'_lammps_serial.so'
    hlibc = CDLL(slib)
  except:
    raise OSError,"Could not load LAMMPS dynamic library"

答案 4 :(得分:0)

在通过ctypes导入相关库之前,将相关文件夹放入PATH变量 中。

例如,如果libs(dll,...)与.py文件位于同一文件夹中,则:

import os
os.environ["PATH"] += os.pathsep + os.path.dirname(os.path.abspath(__file__))

这不会将任何内容写入系统PATH。它将为此实例设置它。