cffi
¶
This example interacts with the shared object
file fortran/example.so
. Similar to ctypes
, the cffi
library
enables the creation of a foreign function interface (FFI) via dlopen
:
>>> import cffi
>>> ffi = cffi.FFI()
>>> so_file = "fortran/example.so"
>>> lib_example = ffi.dlopen(so_file)
>>> lib_example
<cffi.api._make_ffi_library.<locals>.FFILibrary object at 0x7fdd0e364ba8>
After dynamically loading the path, we need to manually define each member of the ABI that we’ll use (both the functions and the structs):
ffi.cdef("void foo(double bar, double baz, double *quux);")
ffi.cdef(
"typedef struct UserDefined {\n"
" double buzz;\n"
" double broken;\n"
" int how_many;\n"
"} UserDefined;"
)
ffi.cdef(
"void make_udf(double *buzz, double *broken,\n"
" int *how_many, UserDefined *quux);"
)
ffi.cdef("void foo_array(int *size, double *val, double *two_val);")
ffi.cdef("void udf_ptr(intptr_t *ptr_as_int);")
ffi.cdef("void just_print();")
ffi.cdef("int __example_MOD_view_knob(void);")
ffi.cdef("void turn_knob(int *new_value);")
In order to convert a NumPy array to a type that can be used with cffi
,
we use the existing ctypes
interface:
def numpy_pointer(array, ffi):
if array.dtype != np.float64:
raise TypeError("Unexpected data type", array.dtype)
return ffi.cast("double *", array.ctypes.data)
Output¶
$ python python/check_cffi.py
------------------------------------------------------------
quux = foo(1.0, 16.0) = 61.0
------------------------------------------------------------
quuz = make_udf(1.25, 5.0, 1337)
= UserDefined(1.25, 5.0, 1337)
------------------------------------------------------------
val =
[[ 3. 4.5 ]
[ 1. 1.25]
[ 9. 0. ]
[-1. 4. ]]
two_val = foo_array(4, val)
two_val =
[[ 6. 9. ]
[ 2. 2.5]
[18. 0. ]
[-2. 8. ]]
------------------------------------------------------------
ptr_as_int = address(made_it) # intptr_t / ssize_t / long
ptr_as_int = 14735136 # 0xe0d720
udf_ptr(ptr_as_int) # Set memory in ``made_it``
made_it = UserDefined(3.125, -10.5, 101)
------------------------------------------------------------
just_print()
======== BEGIN FORTRAN ========
just_print() was called
======== END FORTRAN ========
------------------------------------------------------------
view_knob() = 1337
turn_knob(42)
view_knob() = 42