单个OCaml模块导致对接口的假设不一致
以下是我基于ocamlbuild的项目结构: _tags.ml:单个OCaml模块导致对接口的假设不一致,ocaml,ocamlbuild,Ocaml,Ocamlbuild,以下是我基于ocamlbuild的项目结构: _tags.ml: true: package(batteries) Main.mlpack Stream Main/Stream.ml module MyStream = BatStream 我正在尝试使用编译Main模块 ocamlbuild -use-ocamlfind Main.cmo 在我看来,错误消息似乎不合逻辑: + ocamlfind ocamlc -pack Main/Stream.cmo -o Main.cmo File
true: package(batteries)
Main.mlpack
Stream
Main/Stream.ml
module MyStream = BatStream
我正在尝试使用编译Main
模块
ocamlbuild -use-ocamlfind Main.cmo
在我看来,错误消息似乎不合逻辑:
+ ocamlfind ocamlc -pack Main/Stream.cmo -o Main.cmo
File "_none_", line 1:
Error: The files Main/Stream.cmi and Main/Stream.cmi
make inconsistent assumptions over interface Stream
Command exited with code 2.
Compilation unsuccessful after building 3 targets (0 cached) in 00:00:00
这是使用OPAM中的OCaml 4.02.1
这仅在与电池链接时发生,因此我只能判断batters.Stream
和Main.Stream
之间存在冲突。事实上,如果我添加更多具有依赖关系的模块,我可以得到如下消息
Error: The files /home/ken/.opam/4.02.1/lib/batteries/batteries.cmi
and Main/Stream.cmi make inconsistent assumptions
over interface Stream
但是,我不希望子模块发生冲突
为什么会这样?在我看来,模块不可能在接口上与自身发生冲突。
BatStream
扩展了stdlib流
模块。本地流
模块和stdlib流
模块之间可能存在冲突。BatStream
扩展stdlib流
模块。本地流
模块和stdlib流
模块之间可能存在冲突。OCaml有一个用于编译单元名称的平面命名空间。当编译单元使用某个模块时,它会记录模块接口的名称和摘要(基本上是接口的CRC)。一致性检查确保具有相同名称的两个接口具有相同的摘要(基本上表示相同的实现)。尽管错误消息确实具有误导性,但它仍然是正确的(尽管措辞可能更好)。让我们使用ocamlobjinfo
工具:
$ ocamlobjinfo _build/Main/Stream.cmi
File _build/Main/Stream.cmi
Unit name: Stream
Interfaces imported:
83d31bf1e61f22b62a8b2728a55f2593 Stream
d0b21ad0c1f4e93fa8c05b9ded519b52 Stream
999b28e3b7638771c87eebf5a8325e42 Pervasives
60c2e7663dd57d13b5920931742e1c10 Format
9642e3ed163e46770985ca668738ed5f CamlinternalFormatBasics
6dc691300ced97c0e319cbcc0a715044 Bytes
3bd1af04573ce2da7fc3dc04403e852e Buffer
383683999ce4d4a54f1689bb92969ecb BatStream
fbefc52bb310bf525973099141e16ffe BatOrd
92bc9ee9d7e3da3421ed7fc5c0ade74d BatInterfaces
7d12ec9e52c91f3af313796ff85158c4 BatInnerIO
6f57ab9f63c2f00619c3ffc9bde0bc80 BatIO
bd48c0243cabeabfa9ba81aa02319882 BatEnum
1972feae99a1525e1b830ca37c4efa20 BatConcurrent
我们导入了两个名称相同但实现不同的接口(CRC总和不同)。第一个接口实际上是流
模块的接口,第二个接口是标准流模块的接口:
$ ocamlobjinfo /home/ivg/.opam/devel/lib/ocaml/stream.cmi
File /home/ivg/.opam/devel/lib/ocaml/stream.cmi
Unit name: Stream
Interfaces imported:
d0b21ad0c1f4e93fa8c05b9ded519b52 Stream
999b28e3b7638771c87eebf5a8325e42 Pervasives
9642e3ed163e46770985ca668738ed5f CamlinternalFormatBasics
正如您可能注意到的,每个模块总是导入自己的接口。因此,冲突出现在您的流
模块和OCaml的流
模块之间。标准的Stream
模块通过BatStream
模块进入编译单元
总而言之。接口名称空间是平面的,所以您需要使用前缀来防止冲突,参见BatStream
。是的,很难看
模块打包可以帮助您防止打包到包中的模块与使用包的模块之间的名称冲突。例如,如果您在包
P
中打包了一个模块M
,那么您可以将它与另一个模块M
链接,并且M
和P.M
之间不会有冲突(如果您做的一切都正确)。但是,在构建包时,构成包的模块不应与它们使用的模块冲突,而且不幸的是,OCaml标准库不是包,因此您应该选择与标准库或用于实现包的任何其他库不冲突的名称 OCaml有一个用于编译单元名称的平面名称空间。当编译单元使用某个模块时,它会记录模块接口的名称和摘要(基本上是接口的CRC)。一致性检查确保具有相同名称的两个接口具有相同的摘要(基本上表示相同的实现)。尽管错误消息确实具有误导性,但它仍然是正确的(尽管措辞可能更好)。让我们使用ocamlobjinfo
工具:
$ ocamlobjinfo _build/Main/Stream.cmi
File _build/Main/Stream.cmi
Unit name: Stream
Interfaces imported:
83d31bf1e61f22b62a8b2728a55f2593 Stream
d0b21ad0c1f4e93fa8c05b9ded519b52 Stream
999b28e3b7638771c87eebf5a8325e42 Pervasives
60c2e7663dd57d13b5920931742e1c10 Format
9642e3ed163e46770985ca668738ed5f CamlinternalFormatBasics
6dc691300ced97c0e319cbcc0a715044 Bytes
3bd1af04573ce2da7fc3dc04403e852e Buffer
383683999ce4d4a54f1689bb92969ecb BatStream
fbefc52bb310bf525973099141e16ffe BatOrd
92bc9ee9d7e3da3421ed7fc5c0ade74d BatInterfaces
7d12ec9e52c91f3af313796ff85158c4 BatInnerIO
6f57ab9f63c2f00619c3ffc9bde0bc80 BatIO
bd48c0243cabeabfa9ba81aa02319882 BatEnum
1972feae99a1525e1b830ca37c4efa20 BatConcurrent
我们导入了两个名称相同但实现不同的接口(CRC总和不同)。第一个接口实际上是流
模块的接口,第二个接口是标准流模块的接口:
$ ocamlobjinfo /home/ivg/.opam/devel/lib/ocaml/stream.cmi
File /home/ivg/.opam/devel/lib/ocaml/stream.cmi
Unit name: Stream
Interfaces imported:
d0b21ad0c1f4e93fa8c05b9ded519b52 Stream
999b28e3b7638771c87eebf5a8325e42 Pervasives
9642e3ed163e46770985ca668738ed5f CamlinternalFormatBasics
正如您可能注意到的,每个模块总是导入自己的接口。因此,冲突出现在您的流
模块和OCaml的流
模块之间。标准的Stream
模块通过BatStream
模块进入编译单元
总而言之。接口名称空间是平面的,所以您需要使用前缀来防止冲突,参见BatStream
。是的,很难看
模块打包可以帮助您防止打包到包中的模块与使用包的模块之间的名称冲突。例如,如果您在包
P
中打包了一个模块M
,那么您可以将它与另一个模块M
链接,并且M
和P.M
之间不会有冲突(如果您做的一切都正确)。但是,在构建包时,构成包的模块不应与它们使用的模块冲突,而且不幸的是,OCaml标准库不是包,因此您应该选择与标准库或用于实现包的任何其他库不冲突的名称 你试过清理(即,rm-rf-build
)吗?@Drup确实是这样。包含这三个文件的新项目将生成给定的错误。您是否尝试清理(即,rm-rf\u build
)?@Drup确实如此。包含这三个文件的新项目将生成给定的错误。但是我的子模块Main.Stream
肯定不应该与stlib的Stream
module.OCaml冲突,因为它不使用目录层次结构。您的模块只是Stream
,而不是Main.Stream
。我也这么认为。但是我的子模块Main.Stream
肯定不应该与stlib的Stream
module.OCaml冲突,因为它不使用目录层次结构。你的模块只是Stream
,而不是Main.Stream
。是的,这个解释是100%准确的,但情况很糟糕。是的,这个解释是100%准确的,但情况很糟糕。