Reputation: 6434
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). The header.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:
cffi
docs? Real world examples would be helpful.Upvotes: 3
Views: 3095
Reputation: 12900
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 ...
.
Upvotes: 3