The function constant
and enum
are part of the cstub interface of Ctypes and they are not available in the dynamic mode of Ctypes.
To bind enums in the dynamic mode, the easiest (if unsafe) way is to write an integer view:
type abc = A | B | C
let of_int = function 0 -> A | 1 -> B | 2 -> C | _ -> raise (Invalid_argument "Unexpected C enum")
let to_int = function A -> 0 | B -> 1 | C -> 2
let abc = Ctypes.view ~read:of_int ~write:to_int Ctypes.int
Then the view abc
can be used like any other Ctype
's view. For instance, binding a function f:abc -> unit
can be done with
let f = Foreign.foreign "f" Ctypes.( abc @-> returning void)
If you want to use Ctypes cstubs API, the process is a little more involved.
First, you need to write an ocaml-side type binding generator:
type abc = A | B | C
module Types(T:Cstubs.Types.TYPE) = struct
let a = T.constant "A" T.int64_t
let b = T.constant "B" T.int64_t
let c = T.constant "C" T.int64_t
let abc = T.enum "letter" [A, a; B, b; C, c]
~unexpected:(fun x -> assert false)
end
let () = (* generate the c-side type bindings : *)
let f = Format.formatter_of_out_channel @@ open_out "types_gen.c" in
Format.fprintf f {|#include "enum.h"@.|};
Cstubs.Types.write_c f (module Types)
Executing this ocaml-side generator will generate a C-side type binding generaror (here types_gen.c
). This C-side generator can then be executed to generate ocaml bindings to the C type definitions and constants.
At this point, it is possible to use this type bindings to write ctype cstub generator. For instance,
if the generated type bindings was mapped to types_with_abc
:
module Tb = Type_bindings
module T = Tb.Types(Types_with_abc)
module P(F:Cstubs.FOREIGN) = struct
open F
let f = foreign "f" T.(abc @-> returning Ctypes.void)
end
let () = (* the generation itself is done here: *)
let cstub = Format.formatter_of_out_channel @@ open_out "cstub_abc.c" in
let bindings = Format.formatter_of_out_channel @@ open_out "abc_bindings.ml" in
Cstubs.write_c cstub "abc" (module P);
Cstubs.write_ml bindings "abc" (module P)
Once executed, this generator will create both cstubs and a new foreign
module that can be used to instance the bindings P
on the OCaml side:
module Abc = Binding.P(Abc_bindings)
let () =
Abc.f A