繁体   English   中英

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

[英]Pass objects between libraries in Python cffi

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

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

这是结构定义和在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定义的函数,而FFI具有自己的my_struct类型定义。

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

您可以使用FFI.include将一个FFI实例的源和定义包含在另一个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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM