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?
Thanks!
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:
try
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
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 ...
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.