2017-02-05 24 views
1

這是我基於ocamlbuild項目結構:單OCaml的模塊導致大約接口不一致的假設

_tags.ml:

true: package(batteries) 

Main.mlpack

Stream 

主/ Stream.ml

module MyStream = BatStream 

I a米試圖編譯使用

ocamlbuild -use-ocamlfind Main.cmo 

錯誤消息Main模塊似乎相當不合邏輯對我說:

+ 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。

這隻發生在與電池連接時,所以我只能算出Batteries.StreamMain.Stream之間有衝突。事實上,如果我添加更多的模塊與依賴關係,我可以得到一個消息像

Error: The files /home/ken/.opam/4.02.1/lib/batteries/batteries.cmi 
     and Main/Stream.cmi make inconsistent assumptions 
     over interface Stream 

不過,我不希望子模塊發生衝突。

這是怎麼發生的?對我來說,模塊可能會通過接口與自身發生衝突,這似乎是不可能的。

+0

你有沒有嘗試過清理(即'室射頻_build')? – Drup

+0

@Drup的確如此。包含這三個文件的新項目將生成給定的錯誤。 –

回答

3

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數額是不同的)。第一個接口實際上是你Stream模塊的接口,第二個是標準的流模塊的接口:

$ 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 

正如你可能會注意到每個模塊始終進口自己的接口。所以衝突在您的Stream模塊和OCaml的Stream模塊之間。標準的Stream模塊通過BatStream模塊進入編譯單元。

總結。接口命名空間是平坦的,所以你需要使用前綴來防止衝突,參見BatStream。是的,這很醜陋。

模塊包裝可以幫助您防止被包裝到一個封裝模塊,並使用該包模塊之間的名稱衝突。舉例來說,如果你有裝在包P模塊M,那麼你可以與其他模塊M鏈接它,會有MP.M之間沒有衝突(如果你正確地做了一切)。但是,當你建立的包,構成它的模塊,不應該有,他們使用的模塊衝突,不幸的是,OCaml的標準庫是不是一個包,所以你應該選擇不與標準庫名稱衝突或者您正在用於實現您的軟件包的任何其他庫。

+0

一個很好的解釋。謝謝! –

1

BatStream擴展了stdlib Stream模塊。衝突可能發生在您的本地Stream模塊和stdlib Stream模塊之間。

+0

我儘量多的。但是我的*子模塊* Main.Stream'不應該和stlib的'Stream'模塊衝突。 –

+0

OCaml不使用目錄層次結構。你的模塊只是'Stream',而不是'Main.Stream'。 – Drup