使用ocamlc独立编译库

Using ocamlc to compile libraries independently

我有三个文件:

$ ls
lib.ml  desk.ml  test.ml

$ cat lib.ml
let myfunction () = print_endline "Hello world"

$ cat desk.ml
module Liberty = Lib

$ cat test.ml
Desk.Liberty.myfunction ()

我想编译一个 desk.cma 公开模块 Lib,但能够使用它。例如,我试过:

$ ocamlc -a lib.ml -o lib.cma
$ ocamlc -a lib.cma desk.ml -o desk.cma
$ ocamlc desk.cma test.ml -o test.byte

不幸的是,如果您将 test.ml 更改为 Lib.myfunction (),相同的编译步骤就可以正常工作。我想要它,这样 Lib 就不会暴露给 test.ml 而只暴露给 desk.ml。有谁知道如何做到这一点?非常感谢!

您要求 Lib 成为 Desk 可以使用的 desk.cma 的模块,但不能使用其他模块。我很确定 cma 文件的结构不提供这种控制。

如果您在 Desk 中定义 Lib,您可以将其设为隐藏细节。

$ ls
desk.ml  desk.mli test1.ml test2.ml test3.ml

$ cat desk.ml
module Lib = struct
    let myfunction () = print_endline "Hello world"
end
module Liberty = Lib

$ cat desk.mli
module Liberty : sig
val myfunction : unit -> unit
end

$ cat test1.ml
Desk.Liberty.myfunction ()

$ cat test2.ml
Lib.myfunction ()

$ cat test3.ml
Desk.Lib.myfunction ()

Liberty 模块对测试程序可见,但 Lib 模块不可见:

$ ocamlc -c desk.mli
$ ocamlc -a desk.ml -o desk.cma
$ ocamlc desk.cma test1.ml -o test1.byte
$ ./test1.byte
Hello world
$ ocamlc desk.cma test2.ml -o test2.byte
File "test2.ml", line 1, characters 0-14:
Error: Unbound module Lib
$ ocamlc desk.cma test3.ml -o test3.byte
File "test3.ml", line 1, characters 0-19:
Error: Unbound module Desk.Lib

您可以在单独的文件中实现 Lib,然后 include 将其放入 Desk.Lib 模块的定义中。

我怀疑这不是一个完全令人满意的答案,但我希望它有所帮助。

您似乎在寻找 OCaml 的 -pack 机制。这允许您从多个编译单元(如 pack.cma 库)创建 pack.cmo(或 pack.cmx 用于本机编译),但具有额外的优势,您可以拥有相应的 pack.mli 界面,您可以使用该界面隐藏本应属于 pack 的部分。在你的例子中,你可以有:

--lib.ml--

let myfunction () = print_endline "Hello world"

--liberty.ml--

include Lib

--desk.mli--

(* No module Lib: Lib will not be seen outside of the pack. *)

module Liberty: sig
  val myfunction: unit -> unit
end

然后你可以用

编译它
ocamlc -for-pack Desk -c lib.ml
ocamlc -for-pack Desk -c liberty.ml
ocamlc desk.mli
ocamlc -pack -o desk.cmo lib.cmo liberty.cmo

这将为您提供一个模块 Desk,其中仅包含 Liberty 个 sub-module。当然,desk.mli 可以用来获得更多的 fine-grained 限制,例如与

module Lib: sig end

module Liberty: sig val myfunction: unit -> unit end 

你用空签名导出 Lib,从而隐藏了 Lib.

中的一个(尽管是示例中唯一的一个 ;-P)函数