在不同目录下编译模块
Compiling modules in different directories
我正在尝试按照这些说明编译一个依赖于我创建的另一个模块的模块:https://ocaml.org/learn/tutorials/modules.html
就我而言,我有一个模块 ~/courseFiles/chapter5/moduleA.ml
和 ~/OCamlCommons/listMethods.ml
中的另一个模块。我使用 ocamlopt -c listMethods.ml
编译了 listMethods.ml
,这似乎有效,它生成了一个文件 listMethods.cmx
。
文件 moduleA.ml
包含 open ListMethods;;
。现在我的终端位于 ~/courseFiles/chapter5
我 运行 ocamlopt -c moduleA.ml
但终端 returns
Error: Unbound module ListMethods
现在我可以理解它为什么会这样做了,但是该站点上的说明似乎表明我所做的就是您应该如何做的。大概我需要在编译 moduleA.ml
时传入脚本或可执行文件的位置,但我不确定语法应该是什么。我尝试了一些猜测,并猜测我如何使用 ocamlfind
做到这一点,但我没有成功。我尝试寻找有关编译位于不同目录中的模块的说明,但没有找到任何东西(或任何我能理解的东西)。
首先,OCaml System Distribution(又名编译器)附带的工具包非常通用,但相当low-level,应该被视为构建更多high-level的基础层构建系统。因此,学习它非常困难,而且通常只有在您要构建此类系统时才有意义。学习如何使用 dune or oasis or ocamlbuild 更容易 。此外,它会分散您对真正重要的事情的注意力——学习语言。
综上所述,让我详细回答您的问题。 OCaml 实现了一个单独的编译方案,其中每个编译单元都可以独立构建,然后链接到一个二进制文件中。这种方案在 C/C++ 语言中很常见,事实上,OCaml 编译器工具链与 C 编译器工具链非常相似。
当您 运行 ocamlopt -c x.ml
创建编译单元时,会生成一些文件,即:
x.o
- 实际上包含编译后的机器代码
x.cmx
- 包含优化数据和其他 compiler-specific 信息
x.cmi
- 包含模块 X
. 的已编译接口
为了编译一个模块,编译器不需要该模块中使用的任何其他模块的代码。但它需要的是类型信息,即它需要知道 List.find
函数的类型是什么,或者由模块外部的某个模块提供的任何其他函数的类型。此信息存储在 cmi 文件中,来自 C/C++ 的(已编译)头文件是最接近的对应文件。与在 C/C++ 中一样,编译器在包含搜索路径中搜索它们,默认情况下包含当前目录和标准库的位置,但可以使用 -I
选项(与 C/C++ 中的相同)。因此,如果您的模块正在使用文件夹 A
中定义的另一个模块,您需要告诉编译器在哪里搜索它,例如
ocamlopt -I A -c x.ml
生成的 objective 文件将不包含来自外部模块的任何代码。因此,一旦您到达编译的最后阶段 - 链接阶段,您必须提供实现,例如,如果您的模块 X
正在使用在相对路径 A/y.ml
的文件中实现的模块,并且你已经在该文件夹中编译了它,那么你需要再次指定编译实现的位置,例如
ocamlopt -I A y.cmx x.cmx -o exe
顺序很重要,一个模块使用的所有模块都应该在该模块之前指定,否则,你会得到"No implementations provided"错误。
如您所见,这是一个非常复杂的过程,真的不值得花时间去学习它。因此,如果您有选择,请使用 higher-level 工具来构建您的程序。如果不确定,那就选择 Dune :)
我正在尝试按照这些说明编译一个依赖于我创建的另一个模块的模块:https://ocaml.org/learn/tutorials/modules.html
就我而言,我有一个模块 ~/courseFiles/chapter5/moduleA.ml
和 ~/OCamlCommons/listMethods.ml
中的另一个模块。我使用 ocamlopt -c listMethods.ml
编译了 listMethods.ml
,这似乎有效,它生成了一个文件 listMethods.cmx
。
文件 moduleA.ml
包含 open ListMethods;;
。现在我的终端位于 ~/courseFiles/chapter5
我 运行 ocamlopt -c moduleA.ml
但终端 returns
Error: Unbound module ListMethods
现在我可以理解它为什么会这样做了,但是该站点上的说明似乎表明我所做的就是您应该如何做的。大概我需要在编译 moduleA.ml
时传入脚本或可执行文件的位置,但我不确定语法应该是什么。我尝试了一些猜测,并猜测我如何使用 ocamlfind
做到这一点,但我没有成功。我尝试寻找有关编译位于不同目录中的模块的说明,但没有找到任何东西(或任何我能理解的东西)。
首先,OCaml System Distribution(又名编译器)附带的工具包非常通用,但相当low-level,应该被视为构建更多high-level的基础层构建系统。因此,学习它非常困难,而且通常只有在您要构建此类系统时才有意义。学习如何使用 dune or oasis or ocamlbuild 更容易 。此外,它会分散您对真正重要的事情的注意力——学习语言。
综上所述,让我详细回答您的问题。 OCaml 实现了一个单独的编译方案,其中每个编译单元都可以独立构建,然后链接到一个二进制文件中。这种方案在 C/C++ 语言中很常见,事实上,OCaml 编译器工具链与 C 编译器工具链非常相似。
当您 运行 ocamlopt -c x.ml
创建编译单元时,会生成一些文件,即:
x.o
- 实际上包含编译后的机器代码x.cmx
- 包含优化数据和其他 compiler-specific 信息x.cmi
- 包含模块X
. 的已编译接口
为了编译一个模块,编译器不需要该模块中使用的任何其他模块的代码。但它需要的是类型信息,即它需要知道 List.find
函数的类型是什么,或者由模块外部的某个模块提供的任何其他函数的类型。此信息存储在 cmi 文件中,来自 C/C++ 的(已编译)头文件是最接近的对应文件。与在 C/C++ 中一样,编译器在包含搜索路径中搜索它们,默认情况下包含当前目录和标准库的位置,但可以使用 -I
选项(与 C/C++ 中的相同)。因此,如果您的模块正在使用文件夹 A
中定义的另一个模块,您需要告诉编译器在哪里搜索它,例如
ocamlopt -I A -c x.ml
生成的 objective 文件将不包含来自外部模块的任何代码。因此,一旦您到达编译的最后阶段 - 链接阶段,您必须提供实现,例如,如果您的模块 X
正在使用在相对路径 A/y.ml
的文件中实现的模块,并且你已经在该文件夹中编译了它,那么你需要再次指定编译实现的位置,例如
ocamlopt -I A y.cmx x.cmx -o exe
顺序很重要,一个模块使用的所有模块都应该在该模块之前指定,否则,你会得到"No implementations provided"错误。
如您所见,这是一个非常复杂的过程,真的不值得花时间去学习它。因此,如果您有选择,请使用 higher-level 工具来构建您的程序。如果不确定,那就选择 Dune :)