我目前正在尝试学习 OCaml 的基础知识(通过进行 2022 年代码挑战)。我的目标是仅使用 OCaml 标准库并编写自己的 make 文件,而不是使用包管理器,而是直接运行
ocamlopt
和 ocamlc
等命令来编译和链接程序。
我已经抽象出足够的程序逻辑,这对我来说开始编写模块并弹出到它们自己的 .ml 文件中以包含在我编译的程序的主 .ml 文件中是有意义的。但是,我无法弄清楚如何正确发出命令行命令来执行此命令而不出错。
我需要从某个(共享)目录中提取一些源文件,这些文件定义了一些辅助函数和模块,然后与来自不同目录的 .ml 文件结合在一起,将这些方法组装成一个程序来解决问题。
问题是,如果我尝试从另一个文件中提取模块,我会收到错误
Error: Unbound module <module name>
,我无法解决。为了说明我的问题和我的尝试,我建立了一个玩具示例项目来具体封装问题。这是一个简单的“Hello World”,使用模块分成两个文件:
module ModuleA = struct
let a = fun () -> print_endline "Hello World";;
end
ModuleA.a();;
make:
ocamlc -i ../A/sourcea.ml > ../Output/sourcea.mli # construct the .mli file for sourcea
(cd ../Output && ocamlopt -o sourcea ../A/sourcea.ml) #compile sourcea.ml
(cd ../Output && ocamlopt -o program ../Output/sourcea.cmx ../Output/sourcea.mli ../B/sourceb.ml -I ../A ../B ../Output) # Attempt to compile the progtam using sourcea as a dependency for sourceb This line is where the error happens
我正在尝试编译为本机。我收到错误了
File "../B/sourceb.ml", line 1, characters 0-9:
1 | ModuleA.a();;
^^^^^^^^^
Error: Unbound module ModuleA
我查阅了
ocamlopt
和ocamlc
的文档,我当前的思维模型是我需要编译sourcea并生成其相应的接口文件,然后将它们用作与sourceb.ml
一起编译的输入以生成可执行文件。问题是我不知道如何正确地命令这种情况发生 - 我已经尝试了许多命令和选项的排列,我认为“应该”是命令编译的正确方法,但似乎没有一个起作用。我什至尝试过使用 -for-pack 和 -pack 但似乎也不起作用。
寻找解决方案(在这里和一般的互联网上),人们会发现有类似的基本困难。然而,他们总是使用第三方构建系统(通常是 Dune)或寻求为 opam 制作软件包,而我想(至少暂时)学习如何直接编译 Ocaml 项目。
我能找到的最接近的其他问题是
here,它提供了-I
-ing目录的解决方案来搜索我尝试过但无济于事的包含文件。
.ml
文件编译在一起,其中第二个文件依赖于第一个
没有中定义的模块,使用外部工具(dune opam等..)保存为makefile执行该过程。我将如何改变我的 makefile 来实现这一目标?
sourcea.ml
定义了一个模块
SourceA
。因此,当您尝试编译 moduleA
时,范围内不存在
sourceB.ml
:ModuleA.a()
ModuleA
编译单元的
sourceA.ml
子模块的正确名称是SourceA.ModuleA.a()
其次,在编译
.mli
文件之前不需要生成
.ml
文件。第三,
ocamlopt -o sourcea ../A/sourcea.ml
生成可执行文件。如果您只想生成 cmx 文件,则应使用
-c
选项。
第四,OCaml 参考手册中描述了整个过程:https://ocaml.org/manual/moduleexamples.html#s:separate-compilation