OCaml如何修复模块名称冲突

时间:2017-09-08 04:15:51

标签: namespaces ocaml

制作顶层时,不允许模块名与内部编译器库冲突。

修复此类模块名称冲突有哪些策略?

理想情况下,是否可以将一些参数传递给ocamlc,以指示它为" mangle"要使用MyProject_等自定义前缀的所有模块的名称? (从OCaml ABI的角度来看,不是字面上改变源文件)

以下完整示例:

Sqrt.ml包含

let sqrt x = x ** 0.5

Sqrt.mli包含

val sqrt : float -> float

mktop包含

#!/bin/bash

ocamlc -c Sqrt.mli -o Sqrt.cmi 
ocamlc -c Sqrt.ml  -o Sqrt.cmo

ocamlmktop -o sqrt_toplevel Sqrt.cmo

我可以制作一个包含我想要的功能的顶层。

% ./sqrt_toplevel
        OCaml version 4.04.0

# Sqrt.sqrt 4.5;;
- : float = 2.12132034355964239

如果我通过更改文件名将Sqrt模块重命名为Parse,则该名称与内部库冲突,并且顶层无法链接。

mktop现在

#!/bin/bash

ocamlc -c Parse.mli -o Parse.cmi 
ocamlc -c Parse.ml  -o Parse.cmo

ocamlmktop -o parse_toplevel Parse.cmo

将其他文件重命名为Parse.mlParse.mli

如果我这样做,我会遇到与编译器库的命名冲突。

% ./mktop |& sed -e s:"$HOME":~:
File "Parse.cmo", line 1:
Warning 31: files Parse.cmo and ~/.opam/4.04.0/lib/ocaml/compiler-libs/ocamlcommon.cma(Parse) both define a module named Parse
File "_none_", line 1:
Error: Some fatal warnings were triggered (1 occurrences)
Exit 2

3 个答案:

答案 0 :(得分:3)

除了使用与内部模块不冲突的名称之外,我没有看到记录的方法来避免此问题。

这是用于列出所有禁用名称的Unix命令,至少是:

$ cd ~/.opam/4.04.0/lib/ocaml/compiler-libs
$ ocamlobjinfo ocamlbytecomp.cma ocamlcommon.cma ocamltoplevel.cma |
    awk '/^Unit name:/ { print $3}' | sort

对我来说(现在使用OCaml 4.03.0)有96个禁用名称。我写了一个脚本来验证所有96个都是真的被禁止。

作为旁注,事实上,尽管报告了错误,但仍然生成了顶层。并且,在快速测试中,它似乎有效。函数Parse.sqrt(例如)存在并计算正确的答案。但可能还有一些我偶然遇到的问题。

答案 1 :(得分:2)

使用ocamlbuild,实现这一目标的一种标准方法是将模块封装到mlpack中,如下所述:http://l-lang.blogspot.fr/2012/12/using-ocaml-packages-with-ocamlbuild.html

文件:repo / A.ml

let a = 3;;

文件:repo / b.ml

let b = A.a;;

文件:repo.mlpack

repo/A
repo/B

文件:main.ml

Repo.B.b

这解决了名称冲突问题,但迫使您通过"超级模块访问您的模块"

答案 2 :(得分:1)

默认情况下,Dune / jbuilder会将您的模块包装到以库命名的包含模块中。虽然这不能为您提供正确的命名空间,但您只需确保您的库名称是唯一的。

sample project可以具有以下结构:

proj
├── Makefile
├── proj.opam
├── README.md
├── sub1
│   ├── lib
│   │   ├── a.ml
│   │   ├── a.mli
│   │   ├── b.ml
│   │   └── jbuild
│   └── test
│       ├── a.ml
│       ├── b.ml
│       └── jbuild
├── sub2
│   ├── bin
│   │   ├── bar_main.ml
│   │   ├── foo_main.ml
│   │   └── jbuild
│   ├── lib
│   │   ├── a.ml
│   │   └── jbuild
│   └── test
│       ├── a.ml
│       └── jbuild
└── test
    ├── jbuild
    └── run_tests.ml

请注意我们有多个a.mlb.ml个文件。

jbuild中的sub1/lib文件是:

(jbuild_version 1)

; name = name of the supermodule that will wrap all source files as submodules
; public_name = name of the library for ocamlfind and opam
(library
 ((name proj_sub1)
  (public_name proj.sub1)
  (libraries (unix))
  (synopsis "This is a short description of the sub1 library.")))

这将导致模块Proj_sub1.AProj_sub1.B分别对应sub1/lib/a.mlsub2/lib/b.ml。同样,我们还会构建Test_sub1.ATest_sub1.BProj_sub2.A