2017-02-05 6 views
1

について一貫性のない仮定を引き起こし、私のocamlbuildベースのプロジェクト構造である:シングルOCamlのモジュールは、ここでインターフェース

_tags.ml:

true: package(batteries) 

Main.mlpack

Stream 

メイン/ Stream.ml

module MyStream = BatStream 

a Mainモジュールをコンパイルしようとしているmは

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を使用しています。

これは、バッテリとリンクしているときにのみ発生するので、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

あなたはきれいにしようとしましたか(つまり、 'rm -rf _build')? – Drup

+0

@Drup確かに私はしました。これらの3つのファイルを含む新しいプロジェクトは、指定されたエラーを生成します。 –

答えて

3

OCamlには、コンパイル単位の名前のためのフラットな名前空間があります。コンパイル単位が何らかのモジュールを使用する場合、モジュールインタフェースの名前とダイジェスト(基本的にはインタフェースのCRC)が記録されます。整合性チェックは、同じ名前を持つ2つのインターフェースが同じダイジェストを持つことを保証します(基本的に同じ実装を表します)。エラーメッセージは実際には誤解を招くものですが、それでも正しい(ただし、文言ははるかに良いかもしれませんが)。私たちは、同じ名前を持つインポートされた二つのインターフェースを持っている

$ 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ツールを使用してみましょう。あなたは、各モジュールは、常に独自のインターフェースをインポート気づくことのよう

$ 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 

:最初のインターフェイスは、第1には、標準のストリームモジュールのインタフェースである、実際にあなたのStreamモジュールのインタフェースです。したがって、あなたのStreamモジュールとOCamlのStreamモジュールの間に競合があります。標準のStreamモジュールは、BatStreamモジュールを介してコンパイルユニットに入っています。

要約すると、インタフェースの名前空間はフラットなので、衝突を防ぐためにprefixedを使用する必要があります(cf:BatStream)。はい、それは醜いです。

モジュールのパッキングは、パッケージにパッケージ化されたモジュールとパッケージを使用するモジュール間の名前の競合を防ぐのに役立ちます。たとえば、モジュールMがパッケージPにパッケージされている場合、別のモジュールMとリンクすることができ、MP.Mの間に矛盾はありません(すべて正しく行った場合)。しかし、パッケージをビルドするとき、それを構成するモジュールは、使用するモジュールと競合するべきではありません。残念なことに、OCaml標準ライブラリはパッケージではないので、標準ライブラリと衝突しない名前またはあなたのパッケージの実装に使用している他のライブラリ。

+0

優れた説明です。ありがとうございました! –

1

BatStreamは、stdlib Streamモジュールを拡張します。ローカルのStreamモジュールとstdlib Streamモジュールの間で競合が発生している可能性があります。

+0

私はそれほど前提にしました。しかし、確かに私の*サブモジュール* 'Main.Stream'はstlibの' Stream'モジュールと衝突してはいけません。 –

+0

OCamlはディレクトリ階層を使用しません。あなたのモジュールは 'Main'Streamではなく' Stream'です。 – Drup

関連する問題