1

我正在尝试按照这些说明编译一个依赖于我创建的另一个模块的模块:https ://ocaml.org/learn/tutorials/modules.html

就我而言,我有一个模块~/courseFiles/chapter5/moduleA.ml和另一个模块~/OCamlCommons/listMethods.ml。我已经编译listMethods.ml使用ocamlopt -c listMethods.ml,这似乎工作,它产生了一个文件listMethods.cmx

该文件moduleA.ml包含open ListMethods;;. 现在我的终端位于~/courseFiles/chapter5我跑ocamlopt -c moduleA.ml但终端返回

错误:未绑定的模块 ListMethods

现在我可以理解它为什么会这样做,但该站点上的说明似乎表明我所做的是你应该如何做到这一点。大概我需要在编译时传递脚本或可执行文件的位置moduleA.ml,但我不确定语法应该是什么。我尝试了一些猜测,并猜测了我如何做到这一点,ocamlfind但我没有成功。我尝试寻找有关编译位于不同目录中的模块的说明,但没有找到任何东西(或者任何我能理解的东西)。

4

1 回答 1

2

首先,OCaml System Distribution 附带的工具包(又名编译器)非常通用,但级别很低,应该被视为构建更高级别构建系统的基础层。因此,学习它非常困难,而且通常只有在您要构建这样的系统时才有意义。学习如何使用duneoasisocamlbuild会容易得多。此外,它会分散你的注意力,而不是真正重要的事情——学习语言。

说了这么多,让我详细回答你的问题。OCaml 实现了一个单独的编译方案,其中每个编译单元可以独立构建,然后链接到单个二进制文件中。这种方案在 C/C++ 语言中很常见,实际上 OCaml 编译器工具链与 C 编译器工具链非常相似。

当您运行时,ocamlopt -c x.ml您正在创建一个编译单元,因此会生成一些文件,即:

  • x.o- 实际上包含已编译的机器代码
  • x.cmx- 包含优化数据和其他编译器特定信息
  • x.cmi- 包含模块的编译接口X

为了编译一个模块,编译器不需要该模块中使用的任何其他模块的代码。但它需要的是类型信息,即,它需要知道List.find函数的类型,或由模块外部的某个模块提供的任何其他函数的类型。此信息存储在 cmi 文件中,C/C++ 中的(编译的)头文件是最接近的对应文件。与在 C/C++ 中一样,编译器在包含搜索路径中搜索它们,默认情况下包括当前目录和标准库的位置,但可以使用-I选项进行扩展(与 C/C++ 中相同)。因此,如果您的模块正在使用文件夹中定义的另一个模块,A您需要告诉编译器在哪里搜索它,例如,

 ocamlopt -I A -c x.ml

生成的目标文件将不包含来自外部模块的任何代码。因此,一旦您到达编译的最后阶段 - 链接阶段,您必须提供实现,例如,如果您的模块X正在使用在具有相对路径的文件中实现的模块A/y.ml,并且您已经在该文件夹中编译了它,那么您需要再次指定编译实现的位置,例如,

 ocamlopt -I A y.cmx x.cmx -o exe

顺序很重要,模块使用的所有模块都应在该模块之前指定,否则,您将收到“未提供实现”错误。

如您所见,这是一个相当复杂的过程,花时间学习它真的不值得。因此,如果您可以选择,请使用更高级别的工具来构建您的程序。如果不确定,请选择沙丘 :)

于 2019-06-27T15:32:23.827 回答