我试图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.我错过了什么吗?
谢谢!
评论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)
需要注意的是Entry和Loader必须是不同的模块.否则,你Uninitialized_global在dyn-loading时会遇到异常Plugin.加载Dyn的模块只能访问"已初始化的模块"中的值,并且加载器模块在Dynlink.loadfile调用时认为自己尚未初始化,因为模块的整个评估尚未完成.
Entry.f只有一个入口点是最简单的状态.要动态加载许多值,您可能希望拥有更复杂的数据结构,例如(string, (unit -> unit)) list ref或(string, (unit -> unit)) Hashtbl.t.