![](/img/trans.png)
[英]How to implement a C interface in Python and pass objects using 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.