Вспомогательные хитрости для описания биндингов к C функциям

Если сишная функция имеет в аргументах и возвращаемом результате базовые типы, то достаточно описать только external в .ml (пример неудачный):

value add(value a, value b) {
   return Val_int(Int_val(a) + Int_val(b));
}

external add : int -> int -> int = "add" "noalloc"

Здесь флагом “noalloc” мы помечаем, что функция не нуждается в работе с хипом OCaml (не будет резервировать память в хипе или модифицировать что-либо в хипе или отпускать runtime лок) и на этом можно сэкономить работу с gc (не занимайтесь преждевременной оптимизацией если не уверены - noalloc можно и имеет смысл использовать только в очень ограниченном числе случаев).

Если предполагается, что мы биндим функцию 1:1, то есть внутри биндинга данной функции не требуется проводить какой-либо специальной обработки, то лучше всего применять нижеследующие дефайны, поскольку это позволяет избегать большинство опечаток.

#define Unit(x) ((x), Val_unit)

#define ML_1(name, conv, retval)                                        \
  CAMLprim value ml_##name(value v) {return retval (name(conv(v)));}

#define ML_2(name, conv1, conv2, retval)              \
  CAMLprim value ml_##name(value v1, value v2) { \
    return retval (name(conv1(v1), conv2(v2))); }

#define ML_3(name, conv1, conv2, conv3, retval)                 \
  CAMLprim value ml_##name(value v1, value v2, value v3) { \
    return retval (name(conv1(v1), conv2(v2), conv3(v3))); }

В caml/alloc.h упоминается полезная функция caml\_convert\_flag\_list. Ее применяют для удобной работы со списком флагов, которые в С обычно представляются битами переменной типа int. Ее использование:

type open_flag =
  | O_RDONLY
  | O_WRONLY
  | O_RDWR;

external open : string -> open_flag list -> int = "ml_open"

static int tbl_flag[] = {
  O_RDONLY,
  O_WRONLY,
  O_RDWR
};

static int myflags(value flags) {
   return caml_conver_flag_list(flags, tbl_flags));
}

ML_2(open, String_val, myflags, Val_int)

2011-03-26 13:08