2014-03-14 64 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)必須完全評估。

解決方案是將加載擴展模塊的代碼和擴展模塊調用的代碼分離成兩個單獨的模塊(現在總共有三個模塊)。