我正在尝试在OCaml中实现与eval()
类似的功能。
我有一个string
,我希望从中获得一个OCaml功能。
目前我正在做以下事情:
我将字符串转储到new.ml
并编译文件:
Compile.implementation Format.std_formatter "new.ml" "New"
然后我尝试dynlink
文件:
Dynlink.loadfile "new.cmo";
但如果我尝试New.foo
,它就会失败。我不确定为什么在Dynlink
之后我无法访问模块New。我错过了什么吗?
谢谢!
答案 0 :(得分:6)
Dynlink.loadfile
的评论说:
没有提供任何设施 访问单元定义的值名称。因此,单位 必须在主程序中注册自己的入口点, 例如通过修改函数表。
加载程序无法在没有任何提示的情况下访问dyn-loaded模块的值,因为它不知道仅从.cmo
文件中定义了哪些值。动态加载模块必须将其入口点注册到加载程序中定义的某个状态。
这是一个很小的例子。首先,入口点的模块:
(* entry.ml *)
let f : (unit -> unit) ref = ref (fun () -> assert false)
加载程序:
(* loader.ml *)
let () =
Dynlink.loadfile "plugin.cmo";
!Entry.f ()
要加载dyn的插件:
(* plugin.ml *)
let () = Entry.f := (fun () -> prerr_endline "hello world")
此处,Plugin
将其功能注册到与Entry.f
静态链接的Loader
,以便Loader
可以访问该功能。
必须按如下方式编译:
$ ocamlc -o loader.exe dynlink.cma entry.ml loader.ml
$ ocamlc -c plugin.ml
执行loader.exe
应该演示dyn加载的工作原理:
$ ./loader.exe
hello world
请注意,Entry
和Loader
必须是不同的模块。否则,您在dyn-loading Uninitialized_global
处获得Plugin
异常。加载Dyn的模块只能访问“已初始化的模块”中的值,并且加载器模块在调用Dynlink.loadfile
时认为自己尚未初始化,因为模块的整个评估尚未完成。
Entry.f
是最简单的状态,只有一个入口点。要对dyn加载许多值,您可能希望拥有更复杂的数据结构,例如(string, (unit -> unit)) list ref
或(string, (unit -> unit)) Hashtbl.t
。