Foreign Function Interface

Structs, pointers, callbacks, and stub generation (ctypes.stubs) for performance and portability.

39.1 external declarations with C stubs

(* math.ml *)
external c_add : int -> int -> int = "caml_c_add"
/* stubs.c */
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/alloc.h>

CAMLprim value caml_c_add(value a, value b) {
  CAMLparam2(a, b);
  CAMLreturn(Val_int(Int_val(a) + Int_val(b)));
}
(library (name math) (foreign_stubs (language c) (names stubs)))

39.2 Key rules for C stubs

Use CAMLparam, CAMLlocal, CAMLreturn to register roots with the GC.

Conversions: Int_val/Val_int, Double_val/caml_copy_double, String_val/caml_copy_string, Bool_val/Val_bool, Field(v, i), Store_field.

Allocation: caml_alloc, caml_alloc_tuple, custom blocks (caml_alloc_custom) for C resources with finalizers.

Raising: caml_failwith, caml_invalid_argument, caml_raise_not_found.

Release the runtime lock around long blocking calls: caml_release_runtime_system() / caml_acquire_runtime_system() (formerly caml_enter/leave_blocking_section).

[@@noalloc], [@unboxed], [@untagged] for zero-overhead calls on floats/ints.

More than 5 args → need separate bytecode and native stubs.

39.3 ctypes — FFI without writing C

Structs, pointers, callbacks, and stub generation (ctypes.stubs) for performance and portability.

open Ctypes
open Foreign

let puts = foreign "puts" (string @-> returning int)
let strlen = foreign "strlen" (string @-> returning size_t)

let () = ignore (puts "Hello from C!")

39.4 Calling OCaml from C

caml_named_value, caml_callback, Callback.register "name" f; build with -output-obj to embed OCaml in a C application.

39.5 Other interop

Rust: ocaml-rs, ocaml-interop.

Python: pyml.

JavaScript: js_of_ocaml / Melange (§45).