为何Dune仅暴露`Foo__.Bar`模块而非`Foo.Bar`?
Dune项目中模块访问路径不符合直觉的问题
注:utop 通过 dune utop 启动。
问题场景
通过 dune init project foo 初始化项目后,在lib目录下创建两个文件:lib/foo.ml 和 lib/bar.ml。
lib/foo.ml 内容:
let x = 3
lib/bar.ml 内容:
let x = 4
在utop中可以正常通过 Foo.x 访问foo.ml中的值:
utop # Foo.x;; - : int = 3
但访问bar.ml中的值时,路径却不符合直觉:
utop # Foo.Bar.x;; Error: Unbound module Foo.Bar utop # Bar.x;; Error: Unbound module Bar utop # Foo__Bar.x;; - : int = 4 utop # Foo__.Bar.x;; - : int = 4
原本预期可以通过 Foo.Bar.x 访问,或者说,通常应该能通过 Foo.<首字母大写的文件名>.something 来访问lib目录下文件中的内容。比如Re库的lib目录下有pcre.ml文件,对应的模块可以通过Re.Pcre.exec访问:
utop # #require "re";; utop # Re.Pcre.exec;; - : rex:Re.re -> ?pos:int -> string -> Re.substrings = <fun>
这个问题在编写测试时同样存在:
测试目录下的test/dune配置:
(test (name foo) (libraries foo))
测试代码test/foo.ml中,必须写Foo__.Bar.x而非Foo.Bar.x:
assert (Foo__.Bar.x == 3)
执行测试的结果:
%dune test File "test/dune", line 2, characters 7-10: 2 | (name foo) ^^^ Fatal error: exception Assert_failure("test/foo.ml", 1, 0)
如果改成Foo.Bar.x:
assert (Foo.Bar.x == 3)
则无法通过编译:
%dune test File "test/foo.ml", line 1, characters 8-17: 1 | assert (Foo.Bar.x == 3) ^^^^^^^^^ Error: Unbound module Foo.Bar
而Re库的测试代码可以直接通过Re.FooBar这样的路径访问库模块。
疑问
为何无法通过Foo.Bar访问模块?当前行为并未限制访问lib/bar.ml中的内容,但Foo.Bar比Foo__.Bar更符合直觉、更易使用。
尝试过的解决方案
1. 使用-for-pack标志
搜索到相关问题后,尝试在lib/dune中添加该标志:
(library (name foo) (flags -for-pack))
但没有任何效果。
2. 设置(wrapped false)
根据Dune手册,添加该配置可以将模块暴露在顶层:
(library (name foo) (wrapped false))
此时在utop中可以直接访问:
utop # Bar.x;; - : int = 4
但正如文档所述,这会污染全局命名空间,因此不推荐使用。
版本信息
- OCaml: 4.14.1
- Dune: 3.9.1
内容的提问来源于stack exchange,提问作者toku-sa-n
相关产品推荐
相关产品推荐

