2014-03-14 159 views
2

我试图设置使用Dynlink的OCaml模块的动态加载。我写了一个非常简单的测试程序,但它不起作用。试图用Dynlink动态加载模块

该测试程序由两个模块组成,即Plug和Ext。插头是“主”模块。它知道Ext的文件名并用Dynlink.loadfile加载它。 Ext引用Plug,并在Plug中调用一个函数,通知插入其中的一个函数,以便调用它。在Plug载入Ext后,它会调用Ext应该注册的函数。

如果我编写它,Ext模块将不会成功加载,因此它不会执行任何代码。但是,如果我将包含其扩展功能的部分包含在Plug中,则会出现错误:The module 'Plug' is not yet initialized

我不明白如何插入无法初始化,因为它已经执行。 (实际上我不知道OCaml模块初始化意味着什么。)

我已经将代码降低到几乎不需要重现该问题的程度。我在Linux上使用OCaml 4.01.0。

这里的主要模块:

(* plug.ml *) 

type xfn = string -> unit 

let dummy_func str = 
    print_endline ("Dummy: "^str) 

let ext_func : xfn ref = ref dummy_func 

let register func = 
    ext_func := func 

let call() = 
    (!ext_func) "calling" 

(* load extension *) 

let() = 
    try 
    print_endline "Loading ext."; 
    Dynlink.loadfile "ext.cmo"; 
    print_endline "Loaded ext."; 
    () 
    with 
    | Dynlink.Error e -> 
     print_endline (Dynlink.error_message e); 
    print_endline "Calling registered func."; 
    call() 

这是扩展文件:

(* ext.ml *) 

open Plug 

let myext str = 
    print_endline ("Ext: "^str) 

let() = Plug.register myext 

我用这个shell脚本编译可执行文件:

#!/bin/sh 
ocamlc -c plug.ml && \ 
ocamlc -c ext.ml && \ 
ocamlc -o plug dynlink.cma plug.cmo ext.cmo \ 
    || exit 1 

这是输出我得到:

Loading ext. 
error while linking ext.cmo. 
The module `Plug' is not yet initialized 
Calling registered func. 
Dummy: calling 

回答

1

在这种情况下,我的搜索引擎技能看起来并不像我的球。

一些更多的挖掘发现了一个存档的电子邮件链,它指出在动态加载的模块可以调用它之前,引用的模块(在这种情况下为Plug)必须完全评估。

解决方案是将加载扩展模块的代码和扩展模块调用的代码分离成两个单独的模块(现在总共有三个模块)。