Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OCaml compile & load during run-time

Tags:

ocaml

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!

like image 341
Saswat Padhi Avatar asked Feb 12 '23 09:02

Saswat Padhi


1 Answers

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.

like image 142
camlspotter Avatar answered Feb 13 '23 23:02

camlspotter