Saswat Padhi
Saswat Padhi

Reputation: 6532

OCaml compile & load during run-time

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!

Upvotes: 4

Views: 830

Answers (1)

camlspotter
camlspotter

Reputation: 9030

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.

Upvotes: 8

Related Questions