| import cffi | |
| from cffi import FFI | |
| class PythonFFI(FFI): | |
| def __init__(self, backend=None): | |
| FFI.__init__(self, backend=backend) | |
| self._pyexports = {} | |
| def pyexport(self, signature): | |
| tp = self._typeof(signature, consider_function_as_funcptr=True) | |
| def decorator(func): | |
| name = func.__name__ | |
| if name in self._pyexports: | |
| raise cffi.CDefError("duplicate pyexport'ed function %r" | |
| % (name,)) | |
| callback_var = self.getctype(tp, name) | |
| self.cdef("%s;" % callback_var) | |
| self._pyexports[name] = _PyExport(tp, func) | |
| return decorator | |
| def verify(self, source='', **kwargs): | |
| extras = [] | |
| pyexports = sorted(self._pyexports.items()) | |
| for name, export in pyexports: | |
| callback_var = self.getctype(export.tp, name) | |
| extras.append("%s;" % callback_var) | |
| extras.append(source) | |
| source = '\n'.join(extras) | |
| lib = FFI.verify(self, source, **kwargs) | |
| for name, export in pyexports: | |
| cb = self.callback(export.tp, export.func) | |
| export.cb = cb | |
| setattr(lib, name, cb) | |
| return lib | |
| class _PyExport(object): | |
| def __init__(self, tp, func): | |
| self.tp = tp | |
| self.func = func | |
| if __name__ == '__main__': | |
| ffi = PythonFFI() | |
| @ffi.pyexport("int(int)") | |
| def add1(n): | |
| print n | |
| return n + 1 | |
| ffi.cdef(""" | |
| int f(int); | |
| """) | |
| lib = ffi.verify(""" | |
| int f(int x) { | |
| return add1(add1(x)); | |
| } | |
| """) | |
| assert lib.f(5) == 7 |