ocaml-ctypes icon indicating copy to clipboard operation
ocaml-ctypes copied to clipboard

static_funptr should be better documented

Open yallop opened this issue 9 years ago • 8 comments

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.

yallop avatar Mar 21 '16 21:03 yallop

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.

andrewray avatar Nov 03 '16 20:11 andrewray

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?

yallop avatar Nov 05 '16 13:11 yallop

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

andrewray avatar Nov 05 '16 14:11 andrewray

There are two basic options here

  1. pass

     coerce
      (Foreign.funptr (int @-> returning int))
      (static_funptr (int @-> returning int))
      incr
    

    in place of incr. (This is a lot to type, but can probably be abstracted a bit.)

  2. Use Foreign.funptr in place of Ctypes.static_funptr in 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 incr to map_foo_a directly.

yallop avatar Nov 05 '16 14:11 yallop

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?).

andrewray avatar Nov 05 '16 16:11 andrewray

I think the only real advantage in using 2 is avoiding the libffi dependency.

yallop avatar Nov 05 '16 16:11 yallop

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_ .

andrewray avatar Nov 05 '16 17:11 andrewray

Yes, sorry -- there's a missing "not" above!

With 1 you avoid the dependency.

yallop avatar Nov 05 '16 17:11 yallop