使用Python的CFFI和排除系统头 [英] Using Python's CFFI and excluding system headers
问题描述
我试图使用 Python的CFFI 开发Python绑定到C.写的CFFI文档中科学模型是有点稀疏,我被困在 CDEF
阶段。
我的过程到现在一直遵循下列步骤进行:
-
preprocess的头文件:
gcc的-E -gcc -std = C99 -E -P的src / my_c_interface.c -I./include/ -I ../共享/有/> header.txt
这会产生一个包括所有包含在头文件在我的
包含/
目录C声明的文本文件。它还包括标准库声明(我是pretty肯定这是我的问题的根源)。在header.txt
看起来像这样(完整header.txt是的这里):与系统头的东西开始:
的typedef浮动则float_t;
双的typedef DOUBLE_T;
EXTERN INT __math_errhandling(无效);
EXTERN INT __fpclassifyf(浮动);
EXTERN INT __fpclassifyd(双);
EXTERN INT __fpclassifyl(长双);
的extern __inline __attribute __((__ gnu_inline__))__attribute__((__always_inline__))INT __inline_isfinitef(浮动);
的extern __inline __attribute __((__ gnu_inline__))__attribute__和在我的头文件中定义片结尾:
FILE * LOG_DEST;
无效finalize_logging(无效);
无效get_current_datetime(字符* CDT);
无效get_logname(为const char *路径,INT ID,字符*文件名); -
使用
CFFI
来解析preprocessed头文件:进口CFFIFFI = cffi.FFI()开放('司机/蟒蛇/ header.txt')为f_headers:
ffi.cdef(f_headers.read())#错误在这里提出ffi.compile()这将返回以下错误(全回溯是这里):
/Users/me/anaconda/lib/python3.4/site-packages/cffi/cparser.py在convert_pycparser_error(个体经营,电子,csource)
157其他:
158味精='解析错误。\\ n%s'的%(味精,)
- > 159升api.CDefError(MSG)
160
161高清解析(个体经营,csource,倍率=假,装= FALSE):CDefError:无法解析外部__inline __attribute __((__ gnu_inline__))__attribute__((__always_inline__))INT __inline_isfinitef(浮动);
:10:17:前:__attribute_
- 是否有可能有preprocessor排除系统头?
- 是任何人都意识到这是比较复杂的,然后那些在
CFFI
文档表现出任何的例子吗?现实世界中的例子将是有益的。 - 看着我的例子如上图所示,我失去了什么专业?
这是一个有些通用的答案:
虽然可以使用的gcc -E
办法和手动调整的结果,所以不推荐的方式来使用CFFI。相反,CDEF()code通常是从.h文件的编辑副本或者做增量(根据需要添加的功能),或散装。从手册页复印时,第一种方法效果最好;第二种方法是,我们要到一个第三方库的完全访问权限的情况下。
在所有的情况下,它很可能,你需要反正编辑.h文件中:建议的方法是使用ffi.set_source(),并从CDEF删除()来说是多余的任何声明,以取代他们 ...
。例如,实际的.h文件中可能包含的声明的#define FOOBAR 42
,但应该42不能依赖值(例如,它可能会在未来改变),因此,在CDEF()而应接受的#define FOOBAR ...
。
I'm trying to use Python's CFFI to develop Python bindings to a scientific model written in C. The CFFI documentation is a little sparse and I'm stuck at the cdef
stage.
My process up to now has followed these steps:
Preprocess the header files:
gcc -E -gcc -std=c99 -E -P src/my_c_interface.c -I./include/ -I../shared/include/ > header.txt
This produces a text file that includes all the C declarations included in the header files in my
include/
directories. It also includes declarations for standard libraries (I'm pretty sure this is where my problem is coming from). Theheader.txt
looks something like this (the full header.txt is here):Beginning with system header stuff:
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__
and ending with pieces defined in my headers:
FILE *LOG_DEST; void finalize_logging(void); void get_current_datetime(char *cdt); void get_logname(const char *path, int id, char *filename);
Use
cffi
to parse the preprocessed header files: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()
This returns the following error (full traceback is here):
/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_
Given where I'm at, I have a few questions for those more familiar with cffi than I:
- Is it possible to have the preprocessor exclude system headers?
- Is anyone aware of any examples that are more complex then those shown in the
cffi
docs? Real world examples would be helpful. - Looking at my example shown above, am I missing something major?
This is a somewhat generic answer:
While it is possible to use the gcc -E
approach and manually "trim" the result, it is not the recommended way to use CFFI. Instead, the cdef() code is usually made either incrementally (adding functions as needed) or in bulk from an edited copy of the .h file. The first approach works best when copying from man pages; the second approach is for the case where we want complete access to a single 3rd-party library.
In all cases, it is very likely that you need to edit the .h file anyway: the recommended approach is to use ffi.set_source(), and remove from the cdef() any declarations that are superfluous, replacing them with ...
. For example, the actual .h file may contain the declaration #define FOOBAR 42
, but the value 42 should not be relied upon (e.g. it could change in the future), so the cdef() should rather receive #define FOOBAR ...
.
这篇关于使用Python的CFFI和排除系统头的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!