的评论Dynlink.loadfile
says:
没有提供任何设施
访问由单元定义的值名称。因此,单位
必须向主程序注册其入口点,
例如通过修改函数表。
加载程序无法在没有任何提示的情况下访问 dyn 加载模块的值,因为它不知道仅从.cmo
文件。动态加载的模块必须将其入口点注册到加载程序中定义的某种状态。
这是一个最小的例子。首先,模块的入口点:
(* entry.ml *)
let f : (unit -> unit) ref = ref (fun () -> assert false)
加载程序:
(* loader.ml *)
let () =
Dynlink.loadfile "plugin.cmo";
!Entry.f ()
要动态加载的插件:
(* plugin.ml *)
let () = Entry.f := (fun () -> prerr_endline "hello world")
Here, 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
and Loader
必须是不同的模块。否则,你会得到Uninitialized_global
动态加载异常Plugin
。动态加载的模块只能访问“已初始化模块”中的值,并且加载器模块在以下情况下认为自己尚未初始化:Dynlink.loadfile
被调用,因为模块的整个评估尚未完成。
Entry.f
是只有一个入口点的最简单状态。要动态加载许多值,您可能需要更复杂的数据结构,例如(string, (unit -> unit)) list ref
or (string, (unit -> unit)) Hashtbl.t
.