OCaml 编译 &运行时加载 [英] OCaml compile & load during run-time
问题描述
我正在尝试在 OCaml 中实现类似于 eval()
的东西.
I am trying to achieve something similar to eval()
in OCaml.
我有一个 string
并且我想从中得到一个 OCaml 函数.目前我正在做以下事情:
I have a string
and I want to get an OCaml function out of it.
Currently I am doing the following:
我将字符串转储到 new.ml
并编译文件:
I dump the string to new.ml
and compile the file:
Compile.implementation Format.std_formatter "new.ml" "New"
然后我尝试dynlink
文件:
Dynlink.loadfile "new.cmo";
但是如果我尝试执行 New.foo
它会失败.我不知道为什么在 Dynlink
ing 之后我无法访问模块 New.我错过了什么吗?
But if I try to do New.foo
it fails. I am not sure why I cannot access the module New after Dynlink
ing. Am I missing something?
谢谢!
推荐答案
Dynlink.loadfile
的注释说:
不提供任何设施访问单元定义的值名称.因此,单位必须在主程序中注册自己的入口点,例如通过修改函数表.
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.
加载程序无法在没有任何提示的情况下访问动态加载模块的值,因为它不知道仅从 .cmo
文件中定义了哪些值.动态加载的模块必须将其入口点注册到加载程序中定义的某个状态.
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)
加载程序:
(* loader.ml *)
let () =
Dynlink.loadfile "plugin.cmo";
!Entry.f ()
要动态加载的插件:
(* plugin.ml *)
let () = Entry.f := (fun () -> prerr_endline "hello world")
这里,Plugin
将其函数注册到 Entry.f
中,Entry.f
静态链接到 Loader
,这样 Loader
> 可以访问该功能.
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
loader.exe
的执行应该演示 dyn 加载是如何工作的:
Execution of loader.exe
should demonstrate how the dyn loading works:
$ ./loader.exe
hello world
注意Entry
和Loader
必须是不同的模块.否则,在动态加载 Plugin
时会出现 Uninitialized_global
异常.动态加载的模块只能访问已经初始化的模块"中的值,当调用 Dynlink.loadfile
时,加载器模块认为自己尚未初始化,因为模块的整个评估还没有完成.
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
是只有一个入口点的最简单状态.要动态加载许多值,您可能需要更复杂的数据结构,例如 (string, (unit -> unit)) list ref
或 (string, (unit ->; unit)) Hashtbl.t
.
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
.
这篇关于OCaml 编译 &运行时加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!