ocaml-ctypes
ocaml-ctypes copied to clipboard
static_funptr should be better documented
The current documentation doesn't make the behaviour clear. For example, how should one build and call a function from a static_funptr?
An indication of common ways to use the type --- e.g. by coercing to Foreign.funptr--- would be a good start.
I wonder if you could give an indication of this? I have converted to static_funptr to make things work with Cstubs, and I can see how to pass a C-callback to a C-function, but I don't understand the coerce thing to allow an OCaml based callback.
Foreign.funptr is defined as a view over static_funptr. The coerce function can convert between a type and a view of that type, so you can turn a Foreign.funptr into a static_funptr by passing both type descriptions to coerce:
# let funptr_of_function fn f =
coerce (Foreign.funptr fn) (static_funptr fn) f;;
val funptr_of_function :
('a -> 'b) fn -> ('a -> 'b) -> ('a -> 'b) static_funptr =
<fun>
# let function_of_funptr fn f =
coerce (static_funptr fn) (Foreign.funptr fn) f;;
val function_of_funptr :
('a -> 'b) fn -> ('a -> 'b) static_funptr -> 'a -> 'b =
<fun>
You can always just use Foreign.funptr with cstubs directly, too, if that's any easier.
Does that help?
Thanks. I think I am getting a bit confused with how the various types map between Foreign and Cstubs, especially with regards to function pointers.
I guess what I am aiming for is a way to describe a C-function that takes a function pointer which can be provided as either some other C-function or an OCaml function. I know how to do this with Foreign but am a bit stuck with Cstubs.
For example; https://github.com/ujamjar/ctypes_of_clang/blob/master/examples/foo/foo.h
This errors out with
File "examples/foo/test_foo.ml", line 14, characters 20-24:
Error: This expression has type
(int -> int Foo_stubs.return) Foo_stubs.result =
int -> int Foo_stubs.return
but an expression was expected of type
(int -> int) Ctypes_static.static_funptr
And here is the code currently generated
module Bindings(F:Cstubs.FOREIGN) =
struct
....
let map_foo_a =
F.foreign "map_foo_a"
(F.(@->) foo_0
(F.(@->)
(Ctypes.static_funptr
(Ctypes.(@->) Ctypes.int (Ctypes.returning Ctypes.int)))
(F.returning foo_0)))
let incr = F.foreign "incr" (F.(@->) Ctypes.int (F.returning Ctypes.int))
end
There are two basic options here
-
pass
coerce (Foreign.funptr (int @-> returning int)) (static_funptr (int @-> returning int)) incrin place of
incr. (This is a lot to type, but can probably be abstracted a bit.) -
Use
Foreign.funptrin place ofCtypes.static_funptrin the Ctypes binding that you generate:let map_foo_a = F.foreign "map_foo_a" (F.(@->) foo_0 (F.(@->) (Foreign.funptr (Ctypes.(@->) Ctypes.int (Ctypes.returning Ctypes.int))) (F.returning foo_0)))in which case you can pass
incrtomap_foo_adirectly.
Thanks. I've updated the example with option 1. and can use both c and ocaml based callbacks.
I will probably add an attribute so you can choose between options 1 and 2 (although perhaps there's no real advantage not to just use 2 always?).
I think the only real advantage in using 2 is avoiding the libffi dependency.
Do you mean 1 avoids the dependency (if you don't need to use a callback)?
On 5 Nov 2016 16:49, "yallop" [email protected] wrote:
I think the only real advantage in using 2 is avoiding the libffi dependency.
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/ocamllabs/ocaml-ctypes/issues/364#issuecomment-258623867, or mute the thread https://github.com/notifications/unsubscribe-auth/AFqzI0WUZonOfWDRh7QZtsM6F0BY5TXVks5q7LOcgaJpZM4H1mW_ .
Yes, sorry -- there's a missing "not" above!
With 1 you avoid the dependency.