0

我有一些 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 函数?

4

1 回答 1

0

解决方案

要从单个 ffi 实例构建 cffi 接口,一切都必须从根 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(...) 之前。(因此,下标将在本地调用时生成源代码,例如用于测试目的。)

于 2016-05-12T21:22:10.047 回答