使用ffi.include(...)

时间:2016-04-29 15:24:50

标签: python-cffi

我有一些cffi定义分布在几个项目子目录中 - 每个cffi文件定义类型和函数,每个文件都编译成要加载的_<package>.py文件。在最终的应用程序中,我ffi.include()顶级的(递归ffi.include()较低级别的)并生成一个编译_<app>.py文件,以便在应用程序中加载。我使用单个ffi实例来加载*.so个文件。然而,我无法看到它如何将传播_<package>.py文件加载到应用程序中。我收到以下错误(示例):

  

两个单独的FFI定义文件root/get/ffi_getA.pyroot/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函数?

1 个答案:

答案 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(...)之前。(因此,下标将在本地调用时生成源,例如用于测试目的。)