Dune makes it very easy to build shared objects (*.so) so that OCaml libraries can be used from C. You can see a minimal example here. To give you an overview of this example, here is the dune file for the shared library:
(library
(name lib)
(public_name binding-example)
(modules lib))
(executable
(name CAPI)
(libraries binding-example)
(foreign_stubs (language c) (names cstub))
(flags :standard -linkall)
(modes (native shared_object))
(modules CAPI))
(install
(section lib)
(files
(CAPI.so as libbinding-example.so)
(cstub.h as binding-example.h)))
The OCaml functions that we want to make visible from C are registered in CAPI.ml:
let () = Callback.register "hello" Lib.hello
And cstub.c provides a wrapper to call the hello: string -> string
function from C:
#include <caml/mlvalues.h>
#include <caml/callback.h>
#include <caml/alloc.h>
char* hello (char* name) {
static const value* closure = NULL;
if (closure == NULL)
closure = caml_named_value("hello");
value result = caml_callback_exn(*closure, caml_copy_string(name));
return (char*) result;
}
void initialize_example (char** argv) {
caml_startup(argv);
}
Dune then produces a *.so file that can be linked with a C client program. To see how this works in more details, you can download the full example and use make
.
This worked great for me when linking a single OCaml library produced this way.
However, when I use dune to produce two *.so files for two different ocaml libraries and link them both to a client program, I have a problem. Indeed, the code in CAPI.ml
that registers OCaml names is only run for the first library and not for the second one (first being defined by the order in which the libraries are linked). Therefore, functions from the second library segfault as caml_named_value
returns a null pointer.
Can anyone explain what is happening and does anyone have a workaround?
6 posts - 3 participants