我正在尝试按照以下说明来编译依赖于我创建的另一个模块的模块: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
可以做到这一点,但是我没有成功。我尝试查找有关编译位于不同目录中的模块的说明,但没有找到任何内容(或任何我可以理解的内容)。
答案 0 :(得分:2)
首先,OCaml System Distribution(又名编译器)附带的工具包功能非常丰富,但级别很低,应该被视为构建更多高级构建系统的基础层。因此,学习它非常困难,并且通常只有在要构建这样的系统时才有意义。学习如何使用dune或oasis或ocamlbuild来容易得多。此外,它将使您的注意力从真正重要的部分上分散下来-学习语言。
话虽如此,让我详细回答您的问题。 OCaml实现了一个单独的编译方案,其中每个编译单元可以独立构建,然后链接到单个二进制文件中。这种方案在C / C ++语言中很常见,实际上,OCaml编译器工具链与C编译器工具链非常相似。
运行ocamlopt -c x.ml
时,您正在创建一个编译单元,因此产生了一些文件,即:
x.o
-实际上包含已编译的机器代码x.cmx
-包含优化数据和其他特定于编译器的信息x.cmi
-包含模块X
的编译接口。为了编译模块,编译器不需要该模块中使用的任何其他模块的代码。但是它需要的是类型信息,即它需要知道List.find
函数的类型是什么,或者模块外部某个模块提供的任何其他函数的类型。此信息存储在cmi文件中,对于这些文件,来自C / C ++的(已编译)头文件是最接近的对应文件。与在C / C ++中一样,编译器在include搜索路径中搜索它们,默认情况下,该路径包括当前目录和标准库的位置,但是可以使用-I
选项进行扩展(与C语言中的相同) / C ++)。因此,如果您的模块正在使用在文件夹A
中定义的另一个模块,则需要告诉编译器在哪里搜索,例如,
ocamlopt -I A -c x.ml
产生的目标文件将不包含来自外部模块的任何代码。因此,一旦到达编译的最后阶段-链接阶段,就必须提供实现,例如,如果模块X
使用的是在相对路径为A/y.ml
的文件中实现的模块,并且已经在该文件夹中对其进行了编译,那么您需要再次指定已编译实现的位置,例如
ocamlopt -I A y.cmx x.cmx -o exe
顺序很重要,一个模块使用的所有模块都应在该模块之前指定,否则,将出现“未提供实现”错误。
如您所见,这是一个非常复杂的过程,花时间去学习它确实不值得。因此,如果有选择,请使用更高级别的工具来构建程序。如果不确定,请选择Dune:)