OCaml在运行时编译和加载

Sas*_*dhi 3 ocaml

我试图eval()在OCaml中实现类似的功能.

我有一个string,我希望从中获得一个OCaml功能.目前我正在做以下事情:

我将字符串转储new.ml并编译文件:

Compile.implementation Format.std_formatter "new.ml" "New"
Run Code Online (Sandbox Code Playgroud)

然后我尝试dynlink文件:

Dynlink.loadfile "new.cmo";
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试这样做New.foo失败了.我不知道为什么我不能在访问之后访问模块New Dynlink.我错过了什么吗?

谢谢!

cam*_*ter 7

评论Dynlink.loadfile说:

没有提供访问设备定义的值名称的工具.因此,单元必须向主程序注册其入口点,例如通过修改函数表.

加载程序无法在没有任何提示的情况下访问dyn-loaded模块的值,因为它不知道从.cmo文件中定义了什么值.动态加载模块必须将其入口点注册到加载程序中定义的某个状态.

这是一个很小的例子.一,入口点模块:

(* entry.ml *)
let f : (unit -> unit) ref = ref (fun () -> assert false)
Run Code Online (Sandbox Code Playgroud)

装载程序:

(* loader.ml *)
let () =
    Dynlink.loadfile "plugin.cmo";
    !Entry.f ()
Run Code Online (Sandbox Code Playgroud)

这个插件是dyn-loaded:

(* plugin.ml *)
let () = Entry.f := (fun () -> prerr_endline "hello world")
Run Code Online (Sandbox Code Playgroud)

在这里,Plugin注册其Entry.f静态链接的功能Loader,以便Loader可以访问该功能.

它们必须编译如下:

$ ocamlc -o loader.exe dynlink.cma entry.ml loader.ml
$ ocamlc -c plugin.ml
Run Code Online (Sandbox Code Playgroud)

执行loader.exe应该演示dyn加载如何工作:

$ ./loader.exe
hello world
Run Code Online (Sandbox Code Playgroud)

需要注意的是EntryLoader必须是不同的模块.否则,你Uninitialized_global在dyn-loading时会遇到异常Plugin.加载Dyn的模块只能访问"已初始化的模块"中的值,并且加载器模块在Dynlink.loadfile调用时认为自己尚未初始化,因为模块的整个评估尚未完成.

Entry.f只有一个入口点是最简单的状态.要动态加载许多值,您可能希望拥有更复杂的数据结构,例如(string, (unit -> unit)) list ref(string, (unit -> unit)) Hashtbl.t.