1import cffi 2from cffi import FFI 3 4class PythonFFI(FFI): 5 6 def __init__(self, backend=None): 7 FFI.__init__(self, backend=backend) 8 self._pyexports = {} 9 10 def pyexport(self, signature): 11 tp = self._typeof(signature, consider_function_as_funcptr=True) 12 def decorator(func): 13 name = func.__name__ 14 if name in self._pyexports: 15 raise cffi.CDefError("duplicate pyexport'ed function %r" 16 % (name,)) 17 callback_var = self.getctype(tp, name) 18 self.cdef("%s;" % callback_var) 19 self._pyexports[name] = _PyExport(tp, func) 20 return decorator 21 22 def verify(self, source='', **kwargs): 23 extras = [] 24 pyexports = sorted(self._pyexports.items()) 25 for name, export in pyexports: 26 callback_var = self.getctype(export.tp, name) 27 extras.append("%s;" % callback_var) 28 extras.append(source) 29 source = '\n'.join(extras) 30 lib = FFI.verify(self, source, **kwargs) 31 for name, export in pyexports: 32 cb = self.callback(export.tp, export.func) 33 export.cb = cb 34 setattr(lib, name, cb) 35 return lib 36 37 38class _PyExport(object): 39 def __init__(self, tp, func): 40 self.tp = tp 41 self.func = func 42 43 44if __name__ == '__main__': 45 ffi = PythonFFI() 46 47 @ffi.pyexport("int(int)") 48 def add1(n): 49 print n 50 return n + 1 51 52 ffi.cdef(""" 53 int f(int); 54 """) 55 56 lib = ffi.verify(""" 57 int f(int x) { 58 return add1(add1(x)); 59 } 60 """) 61 62 assert lib.f(5) == 7 63