我有一些cffi定义分布在几个项目子目录中 - 每个cffi文件定义类型和函数,每个文件都编译成要加载的_<package>.py
文件。在最终的应用程序中,我ffi.include()
顶级的(递归ffi.include()
较低级别的)并生成一个编译_<app>.py
文件,以便在应用程序中加载。我使用单个ffi
实例来加载*.so
个文件。然而,我无法看到它如何将传播_<package>.py
文件加载到应用程序中。我收到以下错误(示例):
两个单独的FFI定义文件
root/get/ffi_getA.py
和root/use/ffi_useA.py
哪个C函数都是同一个库的一部分,比如libA.so
。
ffi_getA.py
:
from cffi import FFI
ffi=FFI()
ffi.set_source("getA",None)
ffi.cdef('''
typedef ... A; // type also used in another ffi definition.
const A* get_A();
''')
ffi_useA.py
:
from cffi import FFI
ffi=FFI()
ffi.set_source("useA",None)
from root.get import ffi_getA
ffi.include(ffi_getA.ffi) # makes available type A
ffi.cdef('''
const void* use_A(const A*); // use type A
''')
在申请中:
from root.get import getA # compiled ffi
from root.use import useA # compiled ffi
libAget = getA.ffi.dlopen("libA.so")
libAuse = useA.ffi.dlopen("libA.so")
a = libAget.getA()
libAuse.useA(a) # !!! mixing !!!, a is indeed of type A ...
# ... but from a different ffi instance.
这种混合不起作用,所以问题是:
如何通过公共/单个ffi对象访问/加载遍布各种编译的ffi对象的cdef函数?
答案 0 :(得分:0)
<强>解决方案强>
要从单个ffi实例构建cffi接口,一切都必须以root python cdef构建器脚本开头。在此脚本中,ffi实例将在下一个构建器脚本中导入和扩展,该脚本依赖于上一个构建器脚本中定义的类型。等等。基本上,
在foo.py中:
ffi = cffi.FFI()
ffi.cdef("...")
在bar.py中:
from foo import ffi
ffi.cdef("...")
这样,只有一个FFI实例。 (可能必须避免cffi / cdef文件之间所谓的“钻石导入依赖关系”,以避免重复定义。)
在模块级别导入ffi实例对于装饰器函数访问所定义的类型至关重要。 (回顾这是微不足道的,但起初我在实例构造级别导入并为装饰器使用了一个单独的实例 - 这一直有效,直到我需要自定义类型...)。
最后,在此过程中,您不需要ffi.include(...) - “包含”是通过导入完成的。此外,由于源仅在最终构建器脚本中生成,因此下标中的ffi.set_source(..)语句必须在“if __name __ ==”__ main__“下移动,在ffi.compile(...)之前。(因此,下标将在本地调用时生成源,例如用于测试目的。)