Static function pointers for stubs and inverted stubs
Use case
Currently it is possible to use foreign to declare C functions that take function arguments via static_funptr. In various places (including issues of this repository) it is shown how to coerce such function pointers from Foreign.funptrs, which add the libffi dependency. And as far as I can find, there's no other way to construct static_funptrs.
However, it might be that in the OCaml code, one might want to pass a (static) function pointer of another C function (be it another foreign or even internal). Since such function's pointer can be statically taken, there should be no need to involve ctypes.foreign. There should just be a way to get an 'a static_funptr from a function name and 'a fn. That would allow passing one C function as an argument to another C function directly.
Furthermore, without discrimination it should equally well be possible to get the function pointer of an inverted stub internal as static_funptr and pass it to other C functions. Although the final implementation is in OCaml, it would avoid the need for ctypes.foreign since there exists a static C function for it.
Current state
As far as I can find, there is currently no way to do so. The closest I could find is foreign_value, which doesn't seem to be described anywhere. When attempting to use foreign_value with a function name and type, there's an undesired extra level of pointer. Namely, that would give 'a static_funptr ptr, which is a pointer to a pointer to a function. Moreover, the generated C stub emits compiler warnings for incompatible pointer types where it assigns a function pointer to a double pointer.
Possible solutions
I'm not intimately familiar with the internals of ctypes, but from I understand I can think of two solutions:
-
Add another function like
foreign_funptr: string -> 'a fn -> 'a static_funptrtoFOREIGN, which is very similar toforeign_value, but handles function pointers correctly and doesn't do use invalid double pointers and provides a function-pointer-specific signature. For inverted stubs, their return type could be changed fromunitto a correspondingstatic_funptrfor the pointer to the inverse stubbed C function. -
In the spirit of modularity of ctypes, it might be possible to provide alternative families of forward and inverted stub generators that for
foreigngive the function pointer (instead of the callable OCaml function) and forinternalgive the function pointer (instead of unit). This would leave all existing interfaces untouched, preserving compatibility, but would require additional C and OCaml stub generators for both directions.
In turn, it would allow joint inverted stubbing and their function pointer taking such that an OCaml function can be passed as static_funptr to some C stubs with no ctypes.foreign involvement. This could cover many uses of inverted stubbing where the OCaml functions are fixed, rather than being arbitrary closures (for which you'd still need ctypes.foreign for).
At the moment I think the easiest way to do this is to add a line of C to create a function pointer to the function you want to bind. For example, if you want to bind a function
int compare (void *, void *);
then you could add an additional line as follows
static int (*compare_pointer) (void *, void *) = &compare;
and then bind compare_pointer using static_funptr and foreign_value like this:
let compare = foreign_value "compare_pointer"
(static_funptr (ptr void @-> ptr void @-> returning int))
When attempting to use
foreign_valuewith a function name and type, there's an undesired extra level of pointer
Returning a pointer from foreign_value is a more general interface than returning the value directly, since it supports both reading and writing (as well as repeated reading of a changing value).