Error when binding C enums with Ctypes stubs Api

I want to use the Ctypes stubs Api like described in the following discussion :
Ctypes enum, how to make it work to bind my enums (previously, I used the easier way which is to use a view)

Here is the C enum declaration:

typedef enum
{
  GI_INFO_TYPE_INVALID,
  GI_INFO_TYPE_FUNCTION,
  GI_INFO_TYPE_CALLBACK,
  GI_INFO_TYPE_STRUCT,
  GI_INFO_TYPE_BOXED,
  GI_INFO_TYPE_ENUM,         /*  5 */
  GI_INFO_TYPE_FLAGS,
  GI_INFO_TYPE_OBJECT,
  GI_INFO_TYPE_INTERFACE,
  GI_INFO_TYPE_CONSTANT,
  GI_INFO_TYPE_INVALID_0,    /* 10 */
  GI_INFO_TYPE_UNION,
  GI_INFO_TYPE_VALUE,
  GI_INFO_TYPE_SIGNAL,
  GI_INFO_TYPE_VFUNC,
  GI_INFO_TYPE_PROPERTY,     /* 15 */
  GI_INFO_TYPE_FIELD,
  GI_INFO_TYPE_ARG,
  GI_INFO_TYPE_TYPE,
  GI_INFO_TYPE_UNRESOLVED
} GIInfoType;

I have the following bindings.ml file:

type baseinfo_type =
  | Invalid (** invalid type *)
  | Function (** function, see Function_info *)
  | Callback (** callback, see Function_info *)
  | Struct (** struct, see Struct_info *)
  | Boxed (** boxed, see Struct_info or Union_info *)
  | Enum (** enum, see Enum_info *)
  | Flags (** flags, see Enum_info *)
  | Object (** object, see Object_info *)
  | Interface (** interface, see Interface_info *)
  | Constant (** contant, see Constant_info *)
  | Invalid_0 (** deleted, used to be GI_INFO_TYPE_ERROR_DOMAIN. *)
  | Union (** union, see Union_info *)
  | Value (** enum value, see Value_info *)
  | Signal (** signal, see Signal_info *)
  | Vfunc (** virtual function, see VFunc_info *)
  | Property (** GObject property, see Property_info *)
  | Field (** struct or union field, see Field_info *)
  | Arg (** argument of a function or callback, see Arg_info *)
  | Type (** type information, see Type_info *)
  | Unresolved (** unresolved type, a type which is not present in the typelib, or any of its dependencies. *)

module Enums = functor (T : Cstubs.Types.TYPE) -> struct
  let gi_info_type_invalid = T.constant "GI_INFO_TYPE_INVALID" T.int64_t
  let gi_info_type_function = T.constant "GI_INFO_TYPE_FUNCTION" T.int64_t
  let gi_info_type_callback = T.constant "GI_INFO_TYPE_CALLBACK" T.int64_t
  let gi_info_type_struct = T.constant "GI_INFO_TYPE_STRUCT" T.int64_t
  let gi_info_type_boxed = T.constant "GI_INFO_TYPE_BOXED" T.int64_t
  let gi_info_type_enum = T.constant "GI_INFO_TYPE_ENUM" T.int64_t
  let gi_info_type_flags = T.constant "GI_INFO_TYPE_FLAGS" T.int64_t
  let gi_info_type_object = T.constant "GI_INFO_TYPE_OBJECT" T.int64_t
  let gi_info_type_interface = T.constant "GI_INFO_TYPE_INTERFACE" T.int64_t
  let gi_info_type_constant = T.constant "GI_INFO_TYPE_CONSTANT" T.int64_t
  let gi_info_type_invalid_0 = T.constant "GI_INFO_TYPE_INVALID_0" T.int64_t
  let gi_info_type_union = T.constant "GI_INFO_TYPE_UNION" T.int64_t
  let gi_info_type_value = T.constant "GI_INFO_TYPE_VALUE" T.int64_t
  let gi_info_type_signal = T.constant "GI_INFO_TYPE_SIGNAL" T.int64_t
  let gi_info_type_vfunc = T.constant "GI_INFO_TYPE_VFUNC" T.int64_t
  let gi_info_type_property = T.constant "GI_INFO_TYPE_PROPERTY" T.int64_t
  let gi_info_type_field = T.constant "GI_INFO_TYPE_FIELD" T.int64_t
  let gi_info_type_arg = T.constant "GI_INFO_TYPE_ARG" T.int64_t
  let gi_info_type_type = T.constant "GI_INFO_TYPE_TYPE" T.int64_t
  let gi_info_type_unresolved = T.constant "GI_INFO_TYPE_UNRESOLVED" T.int64_t

  let baseinfo_type = T.enum "baseinfo_type" [
      Invalid, gi_info_type_invalid;
      Function, gi_info_type_function;
      Callback, gi_info_type_callback;
      Struct, gi_info_type_struct;
      Boxed, gi_info_type_boxed;
      Enum, gi_info_type_enum;
      Flags, gi_info_type_flags;
      Object, gi_info_type_object;
      Interface, gi_info_type_interface;
      Constant, gi_info_type_constant;
      Invalid_0, gi_info_type_invalid_0;
      Union, gi_info_type_union;
      Value, gi_info_type_value;
      Signal, gi_info_type_signal;
      Vfunc, gi_info_type_vfunc;
      Property, gi_info_type_property;
      Field, gi_info_type_field;
      Arg, gi_info_type_arg;
      Type, gi_info_type_type;
      Unresolved, gi_info_type_unresolved;
    ]
      ~unexpected:(fun _x -> assert false)
end

And a bindings_c_gen.ml file :

let c_headers = "#include <girepository.h>"

let main () =
  let stubs_out = open_out "bindings_stubs_gen.c" in
  let stubs_fmt = Format.formatter_of_out_channel stubs_out in
  Format.fprintf stubs_fmt "%s@\n" c_headers;
  Cstubs.Types.write_c stubs_fmt (module Bindings.Enums);
  Format.pp_print_flush stubs_fmt ();
  close_out stubs_out

let () = main ()

Which generates a bindings_stubs_gen.c file. The problem comes when I try to compile it, I have the following error:

LANG=en_EN-UTF-8 dune build bin/main.exe                                                    
        bash stubgen/bindings_stubs_gen.exe (exit 1)                                                                                                  
(cd _build/default/stubgen && /usr/bin/bash -e -u -o pipefail -c 'gcc -O2 -fno-strict-aliasing -fwrapv -fPIC bindings_stubs_gen.c -I `dirname /home/ce
dlemo/.opam/default/lib/ctypes/ctypes_cstubs_internals.h` -I /home/cedlemo/.opam/default/lib/ocaml -o bindings_stubs_gen.exe $(< gi-ccopt) $(< gi-ccli
b)')                                                                                                                                                  
In file included from /home/cedlemo/.opam/default/lib/ctypes/ctypes_cstubs_internals.h:13,                                                            
                 from bindings_stubs_gen.c:8:                                                                                                         
bindings_stubs_gen.c: In function 'main':                                                                                                             
bindings_stubs_gen.c:180:74: error: conversion to incomplete type                                                                                     
         ctypes_arithmetic_type_name(CTYPES_CLASSIFY_ARITHMETIC_TYPE(enum baseinfo_type)));                                                           
                                                                          ^~~~~~~~~~~~~                                                               
/home/cedlemo/.opam/default/lib/ctypes/ctypes_primitives.h:143:17: note: in definition of macro 'CTYPES_CHECK_FLOATING'                               
   ((unsigned)(((TYPENAME) 0.5) != 0) << CTYPES_FLOATING_FLAG_BIT)
                 ^~~~~~~~
/home/cedlemo/.opam/default/lib/ctypes/ctypes_primitives.h:148:47: note: in expansion of macro 'CTYPES_CLASSIFY'                                     
 #define CTYPES_ARITHMETIC_TYPEINFO(TYPENAME) (CTYPES_CLASSIFY(TYPENAME) \
                                               ^~~~~~~~~~~~~~~
/home/cedlemo/.opam/default/lib/ctypes/ctypes_primitives.h:151:35: note: in expansion of macro 'CTYPES_ARITHMETIC_TYPEINFO'                          
   ctypes_classify_arithmetic_type(CTYPES_ARITHMETIC_TYPEINFO(TYPENAME))
                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~
bindings_stubs_gen.c:180:37: note: in expansion of macro 'CTYPES_CLASSIFY_ARITHMETIC_TYPE'                                                           
         ctypes_arithmetic_type_name(CTYPES_CLASSIFY_ARITHMETIC_TYPE(enum baseinfo_type)));                                                          
                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bindings_stubs_gen.c:180:74: error: conversion to incomplete type
         ctypes_arithmetic_type_name(CTYPES_CLASSIFY_ARITHMETIC_TYPE(enum baseinfo_type)));                                                          
                                                                          ^~~~~~~~~~~~~                                                              
/home/cedlemo/.opam/default/lib/ctypes/ctypes_primitives.h:145:17: note: in definition of macro 'CTYPES_CHECK_UNSIGNED'                              
   ((unsigned)(((TYPENAME) -1) > 0) << CTYPES_UNSIGNED_FLAG_BIT)
                 ^~~~~~~~
/home/cedlemo/.opam/default/lib/ctypes/ctypes_primitives.h:148:47: note: in expansion of macro 'CTYPES_CLASSIFY'                                     
 #define CTYPES_ARITHMETIC_TYPEINFO(TYPENAME) (CTYPES_CLASSIFY(TYPENAME) \
                                               ^~~~~~~~~~~~~~~
/home/cedlemo/.opam/default/lib/ctypes/ctypes_primitives.h:151:35: note: in expansion of macro 'CTYPES_ARITHMETIC_TYPEINFO'
   ctypes_classify_arithmetic_type(CTYPES_ARITHMETIC_TYPEINFO(TYPENAME))
                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~
bindings_stubs_gen.c:180:37: note: in expansion of macro 'CTYPES_CLASSIFY_ARITHMETIC_TYPE'
         ctypes_arithmetic_type_name(CTYPES_CLASSIFY_ARITHMETIC_TYPE(enum baseinfo_type)));
                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bindings_stubs_gen.c:180:69: error: invalid application of 'sizeof' to incomplete type 'enum baseinfo_type'
         ctypes_arithmetic_type_name(CTYPES_CLASSIFY_ARITHMETIC_TYPE(enum baseinfo_type)));
                                                                     ^~~~
/home/cedlemo/.opam/default/lib/ctypes/ctypes_primitives.h:149:54: note: in definition of macro 'CTYPES_ARITHMETIC_TYPEINFO'
                                             | sizeof(TYPENAME))
                                                      ^~~~~~~~
bindings_stubs_gen.c:180:37: note: in expansion of macro 'CTYPES_CLASSIFY_ARITHMETIC_TYPE'
         ctypes_arithmetic_type_name(CTYPES_CLASSIFY_ARITHMETIC_TYPE(enum baseinfo_type)));
                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The part of bindings_stubs_gen.c that fails, is the following:

  printf("  | \"baseinfo_type\" -> \n    Cstubs_internals.build_enum_type \"baseinfo_type\" Ctypes_static.%s ?typedef ?unexpected alist\n",
        ctypes_arithmetic_type_name(CTYPES_CLASSIFY_ARITHMETIC_TYPE(enum baseinfo_type)));
  puts("  | s ->");
  puts("    failwith (\"unmatched enum: \"^ s)");

I don’t know how to fix this.

As currently written the binding code

let baseinfo_type = T.enum "baseinfo_type" [

is suitable for binding an enum with a tag baseinfo_type:

enum baseinfo_type { ... };

However, the C enum doesn’t have a tag, only a typedef name:

typedef enum { ... } GIInfoType;

so it should be bound like this instead:

let baseinfo_type = T.enum "GIInfoType" ~typedef:true [
2 Likes