使用Python的CFFI并排除系统头

我正在尝试使用Python的CFFI开发Python绑定到用C编写的科学模型.CFFI文档有点稀疏,我陷入了cdef阶段。

到目前为止,我的流程遵循以下步骤:

  1. 预处理头文件:

    gcc -E -gcc -std=c99 -E -P src/my_c_interface.c -I./include/ -I../shared/include/ > header.txt

    这将生成一个文本文件,其中包含include/目录中头文件中包含的所有C声明。 它还包括标准库的声明(我很确定这是我的问题所在)。 header.txt看起来像这样(完整的header.txt在这里 ):

    从系统标题开始:

     typedef float float_t; typedef double double_t; extern int __math_errhandling(void); extern int __fpclassifyf(float); extern int __fpclassifyd(double); extern int __fpclassifyl(long double); extern __inline __attribute__((__gnu_inline__)) __attribute__ ((__always_inline__)) int __inline_isfinitef(float); extern __inline __attribute__((__gnu_inline__)) __attribute__ 

    并以我的标题中定义的片段结束:

     FILE *LOG_DEST; void finalize_logging(void); void get_current_datetime(char *cdt); void get_logname(const char *path, int id, char *filename); 
  2. 使用cffi解析预处理的头文件:

     import cffi ffi = cffi.FFI() with open('drivers/python/header.txt') as f_headers: ffi.cdef(f_headers.read()) # error is raised here ffi.compile() 

    这将返回以下错误(完整的回溯在这里 ):

     /Users/me/anaconda/lib/python3.4/site-packages/cffi/cparser.py in convert_pycparser_error(self, e, csource) 157 else: 158 msg = 'parse error\n%s' % (msg,) --> 159 raise api.CDefError(msg) 160 161 def parse(self, csource, override=False, packed=False): CDefError: cannot parse "extern __inline __attribute__((__gnu_inline__)) __attribute__ ((__always_inline__)) int __inline_isfinitef(float);" :10:17: before: __attribute_ 

鉴于我在哪里,对于那些比我更熟悉cffi的人,我有几个问题:

  1. 是否可以让预处理器排除系统头?
  2. 是否有人知道任何比cffi文档中显示的更复杂的cffi ? 真实世界的例子会有所帮助。
  3. 看看上面显示的例子,我错过了一些重要的东西吗?

这是一个通用的答案:

虽然可以使用gcc -E方法并手动“修剪”结果,但不建议使用CFFI。 相反,cdef()代码通常是以递增方式(根据需要添加函数)或从.h文件的编辑副本批量生成的。 从手册页复制时,第一种方法效果最好; 第二种方法适用于我们希望完全访问单个第三方库的情况。

在所有情况下,您很可能无论如何都需要编辑.h文件:建议的方法是使用ffi.set_source(),并从cdef()中删除任何多余的声明,将它们替换为... 。 例如,实际的.h文件可能包含声明#define FOOBAR 42 ,但不应依赖值42(例如,它可能在将来发生变化),因此cdef()应该接收#define FOOBAR ...