Generates .h files from 'external' declarations in .ml or .cmt files. Can be used to spot mismatches in number of arguments between C primitive declared in OCaml and its implementation in the .c file.
Published: 11 Sep 2023
Lintcstubs_arity — check consistency between OCaml primitive declarations and implementation
These are a suite of tools and libraries for finding mismatches between the number of arguments declared in a
.ml file for a C primitive and its implementation in the corresponding
lintcstubs_arityis a tool that generates a C header file from an OCaml
.mlfile that contains
lintcstubs_arity_cmtgenerates the header file from a
lintcstubs-arity.primitives_of_cmtis an OCaml library that can be used to iterate over all primitive declarations in a
Their only dependency is
compiler-libs which is shipped with the compiler distribution. Requires OCaml 4.10+.
opam install lintcstubs-arity
If you do not use
dune it is still possible to use this tool, see example/minimal for details.
If the number or type of arguments doesn't match between the declaration in the
.ml file or its implementation in
.c then this can result in undefined behaviour at runtime. Neither the C nor OCaml compiler is aware of the requirements of the other module, and the linker only checks the presence of the
symbol, but not its type. By generating a
.h file such mismatches can be detected at build time by the C compiler.
The paper contains concrete examples of how such mismatches can occur in practice as software evolves.
Bytecode & native code stubs
lintcstubs_arity_cmt ocamlfile.cmt >primitives.h
primitives.h can be included at the top of the
.c file implementing the OCaml primitives.
ocamlfile.cmt is a
-bin-annot file for
ocamlfile.ml. Your build system should've produced one, check that it is using the
-bin-annot flag if not. You can also create one manually (add include and
ocamlfind flags as necessary):
ocamlc -bin-annot -c ocamlfile.ml
For more details see the build-system integration examples:
You can also commit the generated file to source control, thus requiring the tool to be present only when changing the
.ml file (or in a CI). This can be useful when the OCaml module is part of a larger system predominantly written in another language.
This is the recommended version of the tool if you meet the OCaml version requirements and can integrate header generation into the package's build system. The generated header contains both byte-code and native-code prototypes, and supports unboxed annotations.
lintcstubs_arity ocamlfile.ml >primitives.h
ocamlfile.ml is an OCaml file that declares a C primitive as defined in the manual.
primitives.h is generated, you can include it in the
.c files that implement the OCaml primitives defined in
This can help detect simple mismatches between the number of arguments declared in the
.ml file and implemented in the
This version of the tool doesn't support unboxed arguments, and therefore it doesn't generate prototypes for native code versions of the stubs. It only requires a source file and doesn't require setting up build paths or integrating into a build system, it is suitable to use on an unpacked source tarball directly.
How it works
If there is interest, its integration could be proposed into a future version of the compiler.
All of these tools adhere to these principles:
No external dependencies (
compiler-libsis available by default) to make it easy to reuse in other build systems
Optional dependencies for ecosystem integration (e.g.,
Use the minimum version of Dune that has the features we require (e.g.,
Both of these tools rely on unstable compiler APIs. They use just the minimum information from the Parse- and Typed-trees to ensure the tool works on a wide range of OCaml compiler versions (and is easy to adapt if it breaks). Shape-analysis is out-of-scope.
Contains Cram tests to check for correct behaviour.