我试图用Dune编译OCaml代码,但出现了以下错误:
Error: No implementations provided for the following modules:
CallccBp referenced from bin/.CallccTest.eobjs/native/dune__exe__CallccTest.cmx
通过执行命令:$ dune build
我的项目层次结构如下:
callcc/
bin/
callccTest.ml
dune
[
(executable
(name callccTest)
(libraries CallccBp))
]
lib/
CallccBp.mli
dune
[
(library
(name CallccBp)
(modules_without_implementation CallccBp))
]
test/
callccTest.ml
dune [
(test
(name callccTest))
]
callcc.opam
dune-project
我该如何解决这个问题?
看看您与octacron的讨论,让我们从基础开始:
my_module.mli
您声明值、模块等签名的文件。不是强制性的,如果您从OCaml 开始,我建议不要使用它们
my_module.ml
实现您的值、模块等的文件。强制要求,因为这些文件使您的程序运行
让我们看看玩具项目:
.
├── bin
│ ├── dune
(executable
(name main)
)
│ └── main.ml
├── dune-project
├── lib
│ ├── dune
(library
(name my_module)
)
│ └── my_module.ml
└── program.opam
如果我想在bin/main.ml
中使用my_module
中的值,我必须:
- 在
my_module.ml
中具有值 - 在我的
bin/dune
文件中添加(libraries my_module)
节 - 将这些值与
My_module.<name_of_value>
一起使用
所以这看起来像:
.
├── bin
│ ├── dune
(executable
(name main)
(libraries my_module)
)
│ └── main.ml
let () =
let b = My_module.incr 3 in
Printf.printf "%dn" b
├── dune-project
├── lib
│ ├── dune
│ └── my_module.ml
let incr a = a + 1
└── program.opam
现在,让我们回到您的层次结构:
callcc/
bin/
callccTest.ml
dune
[
(executable
(name callccTest)
(libraries CallccBp))
]
lib/
CallccBp.mli
dune
[
(library
(name CallccBp)
(modules_without_implementation CallccBp))
]
test/
callccTest.ml
dune [
(test
(name callccTest))
]
callcc.opam
dune-project
除了CallccBp.mli
只是一个接口,而不是一个实现之外,一切看起来都很好。作为启动程序,您可以删除此文件,创建CallccBp.ml
并填充以下两个函数:
CallccBp.ml
let callcc = failwith "TODO"
let throw = failwith "TODO"
如果您进行编译,dune不应该抱怨,现在您所要做的就是提供一个比failwith "TODO"
更有用的实现
如果我们回到我们的玩具项目,看看你为什么想要一个mli文件:
.
├── bin
│ ├── dune
(executable
(name main)
(libraries my_module)
)
│ └── main.ml
let () =
let b = My_module.incr 3 in
Printf.printf "%dn" b
├── dune-project
├── lib
│ ├── dune
│ └── my_module.ml
let dummy _ = failwith "USELESS"
let incr a = a + 1
│ └── my_module.mli
val incr : int -> int
(** [incr d] will return [d] incremented by 1. Highly efficient. Trust me. *)
└── program.opam
我可以在bin/main.ml
中使用My_module.incr
,但不能在My_module.dummy
中使用,因为mli
文件没有显示它,因此在my_module.ml
之外无法访问它。另外,对于库用户来说,my_module.mli
文件是一个入口点,他们不想知道它是如何实现的,只想使用它,知道可用的值、它们的类型,通常还知道它们从注释中做了什么。
modules_without_implementation
节用于不需要实现的mli
文件,即类型声明文件,因此模块如下所示:
AST.mli
type ('a, 'b) res = Ok of 'a | Error of 'b
type num = Int of int | Float of float
type person = {id : int; name : string; age : num}
你可以在另一个文件中使用它们,比如
file.ml
type t = {player1 : AST.person; player2 : AST.person}
let whos_older p1 p2 =
Printf.printf "%s is oldern"
(if p1.AST.age > p2.AST.age then p1.name else p2.name)
但这在开始时并没有真正的用处,因为我再次建议不要在开始的中触摸mli
文件
错误消息抱怨模块CallccBp
没有实现(也就是没有ml文件(。在不知道CallccBp
的内容的情况下,该模块可能包含异常或扩展构造函数声明(或任何其他类型的运行时组件(。您的第一个修复应该是添加一个callccBp.ml
文件并删除(module_without_implementation ...)
行。