簡體   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