假设我有一组模块,每个模块都有子模块。
M1.X M2.X M3.X
M1.Y M2.Y M3.Y
M1.Z M2.Z M3.Z
M1.W M2.W M3.W
M1.Q M2.Q M3.Q
M1.P M2.P M3.P
此外,我希望这些灌木中的每一个都位于一个主模块下。
Home.M1
Home.M2
Home.M3
现在,使用Oasis的Pack:
选项可以很容易地为M1
、M2
和M3
中的每一个构建项目目录。特别是,我喜欢并试图解决的问题是(a)能够以标准.ml
/.mli
格式布置我的文件,以及(b)让ocamldoc
生成正确链接的文档。
但是,由于我想将M1
、M2
和M3
中的每一个分布在一个公共模块层次结构下的同一个库中,我不能使用Pack:
,而是被迫将整个该死的东西放入一个文件中,以便(a)不意外地破坏全局名称空间,(b)不意外在Home.
名称空间中大量增加不打算直接使用的模块,以及(c)不破坏ocamldoc链接。
所以我的问题是,根据上面建议的目标,我如何使用Oasis创建具有这种形式的分层模块的包
一些附加限制包括:
M1.
、M2.
和M3.
命名空间下的模块发生冲突并非偶然——这种情况在真实情况下也会发生- CCD_ 16和CCD_ 17命名空间中的模块取决于CCD_
我的偏好是能够达成一个解决方案,也允许合理的文件布局,例如
src -+
+-- m1 -+
| +-- x.ml
| +-- x.mli
| +-- y.ml
| +-- y.mli
| +-- z.ml
| +-- z.mli
| |
| ...
|
|
+-- m2 -+
| +-- x.ml
| +-- x.mli
| +-- y.ml
| +-- y.mli
| +-- z.ml
| +-- z.mli
| |
| ...
|
|
+-- m3 -+
+-- x.ml
+-- x.mli
+-- y.ml
+-- y.mli
+-- z.ml
+-- z.mli
|
...
绿洲也有可能不可能做到这一点。在这种情况下,关于如何使用其他构建工具的建议是可以接受的,也是受欢迎的。假设我对其他工具了解甚少。。。因为这可能是真的!
带绿洲
oasis
中的pack
有点坏,因为它通过将所有路径包括在搜索路径中来破坏名称空间。有一个长期存在的可接受的bug请求,但事情仍然是原来的样子。但是,如果它工作正常,它可以帮助您,因为它将创建一个库名称空间,允许您在不同的文件夹中具有相同名称的模块。但是,它不起作用,所以我们应该忘记它
我们在BAP项目中采用的方法是用丑陋的bap_subproject_
前缀破坏所有模块名称,这可以保护我们免受与自己模块的冲突,以及来自外部库的冲突。对于每个bap_subproject
,我们都有一个文件夹,其中包含所有名称错误的实现模块,以及一个总括模块来管理它们。该模块存储在文件bap_subproject.ml
中,它为要导出的所有模块和类型定义别名。通常它包含以下条目:
module X = Bap_subproject_x
还有一个大型的Bap
项目,它将所有子库联合在一个名称空间Bap.Std
下,并重新导出所需的一切,这样在一个open Bap.Std
之后,您就可以访问bap_disasm/bap_disasm_insn.ml[i]
中定义的Insn
模块
没有绿洲
免责声明:如果您使用插件进行扩展,此解决方案可能仍然适用于oasis。
我们在一个项目中使用了这种方法,不幸的是,该项目是封闭源代码的,所以我无法提供链接。每个子项目都生活在自己的子文件夹中,在自己的命名空间中(我们在每个子文件夹中都有parser
模块,没有任何阻塞)。对于每个子项目,在top
文件夹中都有一个mlpack
文件:
root +
|
+-- expr.mlpack
+-- expr -+
|
+- lexer.*
+- parser.*
+- ast.*
+- ...
+-- cameo.mlpack
+-- cameo-+
|
+- lexer.*
+- parser.*
+- ast.*
+- ...
expr.mlpack
的内容是:
expr/Lexer
expr/Parser
expr/Ast
...
ocamlbuild
将该expr.mlpack
视为一个独立模块,其中定义了Lexer
、Parser
等子模块(并且可访问为例如Expr.Lexer
)。并且与同样具有Lexer
的同级项目没有冲突,也与ocaml-libs
或任何其他外部Lexer
没有冲突,因为expr
文件夹实际上从未包含在搜索路径中。
如果你需要在你的系统中添加另一层,比如一个包对一个包,那么你有三个选择:
- 递归地使用相同的方法,即创建另一个超级文件夹,该超级文件夹具有指向子文件夹的
mlpack
或mllib
文件 - 只需添加引用所有顶级
mlpack
模块的big.mlpack
- 创建重新引入所有模块的
big.ml
最后两种方法当然要求顶级封装模块具有不同的名称。但通常情况下,这是足够公平的。