python - 在 Python cffi 中的库之间传递对象

标签 python python-cffi

如果我使用 cffi.FFI.new 创建一个新结构,如何将其传递给具有相同结构定义的不同 FFI 中的函数?

我有一个基本的 C 结构,我通过 cffi 包在 Python 中使用它,我想将其传递给 cffi 在运行时生成和编译的各种函数。但是,我不知道如何让生成的函数共享相同的结构定义,以便我可以在它们之间传递对象。 cffi 不喜欢使用一个 FFI 构建对象并将其传递给另一个 FFI 的函数。

以下是结构体定义和在 Python 中创建实例的简化可运行示例:

from cffi import FFI

common_header = """
typedef struct {
  int32_t a;
  double b;
} my_struct;
"""

# FFI for building objects
ffibuilder = FFI()
ffibuilder.cdef(common_header)

# Build an object in Python
my_object = ffibuilder.new('my_struct*')
my_object.a = 3
my_object.b = 2.0

我有一个外部库,它生成函数的源代码,这些函数采用指向该结构实例的指针。我目前使用 CFFI 的 API 模式编译它们。这里重要的是,函数可能是在对象构建之后生成的,所以我不能简单地提前将所有函数收集在一起并将它们编译为一个库。

# Builder for functions generated at runtime
def build_library(header: str, source: str):
    from tempfile import TemporaryDirectory

    ffitemp = FFI()

    ffitemp.cdef(common_header + header)

    ffitemp.set_source('_temp', source)

    with TemporaryDirectory() as temp_dir:
        lib_path = ffitemp.compile(tmpdir=temp_dir)

        lib = ffitemp.dlopen(lib_path)

    return lib.func


# Use function
header = """
int func(my_struct *A);
"""

source = """
typedef struct {
  int32_t a;
  double b;
} my_struct;

int func(my_struct *A) {
    return A -> a;
}
"""

func = build_library(header, source)

当我尝试将结构实例传递给函数时,收到一条错误消息,指出我传入的结构与函数接受的结构类型不同。

# Use function
a = func(my_object)
print(a)

TypeError: initializer for ctype 'my_struct *' appears indeed to be 
'my_struct *', the types are different (check that you are not e.g. 
mixing up different ffi instances)

这个错误非常清楚地说明了它为什么不高兴。它不喜欢我使用 ffibuilder 构造了 my_object 并将其传递给在不同的 FFI 中定义的函数,该函数有自己的定义my_struct 类型。

如何编译生成的函数以与中央 FFI 共享结构定义?

最佳答案

您可以使用 FFI.include 将一个 FFI 实例的源代码和定义包含在另一个实例中。使用包含的 FFI 构造的对象可传递给包含它的 FFI 中的函数。

请注意,包含的定义不能在以后的 FFI 中重复。此外,只有在调用了 set_source 后才能包含 FFI。即使您想要的只是标题也是如此;在这种情况下,只需将源设置为空字符串即可。

这里是在主FFI上设置空源:

from cffi import FFI

common_header = """
typedef struct {
  int32_t a;
  double b;
} my_struct;
"""

# FFI for building objects
ffibuilder = FFI()
ffibuilder.cdef(common_header)
ffibuilder.set_source('_main', '')  # <-- Set empty source

这里将主要的 FFI 包含在叶子 FFI 中:

# Builder for functions generated at runtime
def build_library(header: str, source: str):
    from tempfile import TemporaryDirectory

    ffitemp = FFI()

    ffitemp.include(ffibuilder)  # <-- include main FFI

    ffitemp.cdef(header)

    ffitemp.set_source('_temp', source)

    with TemporaryDirectory() as temp_dir:
        lib_path = ffitemp.compile(tmpdir=temp_dir)

        lib = ffitemp.dlopen(lib_path)

    return lib.func

关于python - 在 Python cffi 中的库之间传递对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54986536/

相关文章:

python - 使用 SQLite 了解 PonyORM 中的内存消耗

python - 通过scrapy模拟表单登录

python - 潜在语义索引如何用于特征选择?

python - 干净地卸载共享库并使用 Python CFFI 重新开始

Python CFFI 不会将 typedef 从 cdef() 复制到生成的 C 文件中

python - 无法在 fedora23 工作站上安装 cffi

python - 使用报纸时如何按类别过滤文章?

python - 在python中随机选择图像内的200x200正方形

python - 在 Python CFFI 中声明包含 time_t 字段的结构