Fail to dynamically link cmxs file when using Dynlink

I try to dynamically load a shared object file (a cmxs file) to my main application. This shared object file uses the library Graphic.
Thus, I try to dynamically load graphics.cmxs before loading my shared object file. But an exception is raised with on error message.
Does anybody knows why or how to fix this problem?

What’s the error message - have you also called Dynlink.allow_unsafe_modules true?

there is no message. Only: Dynlink.Error(_)
I called Dynlink.allow_unsafe_modules true, though it seems unnecessary in native code

Oh, indeed - I started in bytecode when checking it and forgot that there’s no requirement for allow_unsafe_modules in native.

You can get the error by catching Dynlink.Error and using Dynlink.error_message to print the error message.

I don’t know how to convert the exception caught from type exn to type Dynlink.error.
I looked into the source code of Dynlink, the exceptions raised by the Dynlink.loadfile may not be of Dynlink.Error

In general, digging into the OCaml sources is a sledgehammer approach to debugging! Indeed, certain file I/O problems may cause Dynlink.loadfile to raise exceptions other than Dynlink.Error, but that doesn’t matter here - you already know that you’re getting a Dynlink.Error exception.

You want to wrap your call to Dynlink.loadfile with something like:

  Dynlink.loadfile "graphics.cmxs"
with Dynlink.Error e -> Printf.eprintf "Dynlink error: %s\n%!" (Dynlink.error_message e)

the error message is :
error loading shared library: /home/harvey/.opam/4.04.0/lib/ocaml/graphics.cmxs: undefined symbol: camlHashtbl

You need to link the program with -linkall

1 Like

It works.

But a new problem emerges. Since I wish to use the websocket and the websocket.cohttp libraries, the -linkall FLAG creates an error:
Files /home/harvey/.opam/4.04.0/lib/websocket/websocket_cohttp_lwt.cmxa and /home/harvey/.opam/4.04.0/lib/websocket/websocket.cmxa both define a module named Rng

Ouch! In which case, you’ll need to make sure that modules Hashtbl, Callback and Printexc are all pulled in so that you can build without -linkall. It’s ugly, but you can do this with things like:

let _ = Hashtbl.find in let _ = Callback.register in let _ = Printexc.to_string in
Dynlink.loadfile ...
1 Like

I am not sure if I get it correctly:

Generally, if I want to dynamically load a plugin, I have to make sure all modules the plugin uses are pulled in unless the module is in a standard library.

That’s right - all the modules required by that plugin must be linked into your program (this includes standard library ones - you don’t link the entire stdlib by default). You do this either with -linkall or by having dummy references to modules you don’t actually use.

1 Like