4

I am trying to achieve something similar to eval() in OCaml.

I have a string and I want to get an OCaml function out of it. Currently I am doing the following:

I dump the string to new.ml and compile the file:

Compile.implementation Format.std_formatter "new.ml" "New"

Then I try to dynlink the file:

Dynlink.loadfile "new.cmo";

But if I try to do New.foo it fails. I am not sure why I cannot access the module New after Dynlinking. Am I missing something?

Thanks!

Saswat Padhi
  • 6,044
  • 4
  • 20
  • 25

1 Answers1

8

The comment of Dynlink.loadfile says:

No facilities are provided to access value names defined by the unit. Therefore, the unit must register itself its entry points with the main program, e.g. by modifying tables of functions.

The loader program cannot access values of dyn-loaded module without any hint, since it has no idea what values are defined in it just from the .cmo file. The dynamic loaded module must register its entry point to some state defined in the loader program.

Here is such a minimal example. First, the module for the entry points:

(* entry.ml *)
let f : (unit -> unit) ref = ref (fun () -> assert false)

The loader program:

(* loader.ml *)
let () =
    Dynlink.loadfile "plugin.cmo";
    !Entry.f ()

The plugin to be dyn-loaded:

(* plugin.ml *)
let () = Entry.f := (fun () -> prerr_endline "hello world")

Here, Plugin registers its function to Entry.f which is statically linked to Loader, so that Loader can access the function.

They must be compiled as follows:

$ ocamlc -o loader.exe dynlink.cma entry.ml loader.ml
$ ocamlc -c plugin.ml

Execution of loader.exe should demonstrate how the dyn loading works:

$ ./loader.exe
hello world

Note that Entry and Loader must be different modules. Otherwise, you get Uninitialized_global exception at dyn-loading Plugin. Dyn-loaded modules can only access values in "already initialized modules", and the loader module thinks itself not yet initialized when Dynlink.loadfile is called, since the entire evaluation of the module is not finished yet.

Entry.f is the simplest state to have only one entry point. To dyn-load many values, you may want to have more complicated data structure, such as (string, (unit -> unit)) list ref or (string, (unit -> unit)) Hashtbl.t.

camlspotter
  • 8,990
  • 23
  • 27
  • Thanks @camlspotter, for the quick reply. Now I see why I wasn't being able to access the module. But I still have one question - if I do not know the module to be `dynlinked` at compile time (as I mentioned, I am creating it at runtime); how do I access it? – Saswat Padhi Dec 10 '14 at 10:56
  • I am not sure what you are asking here, but your program creates new modules therefore the program should know what values are available in plugins. All you need is a proper "protocol" between the loader and plugins, like value `X.x` is registered with a key "X.x" in the entry point hashtbl. – camlspotter Dec 10 '14 at 11:14