对接口做出不一致的假设

Make inconsistent assumptions over interface

我想优化 makefile 的编译时间。浪费我时间的一个问题是,修改一个文件后,例如 make returns,

File "frontend/parser_e.ml", line 1:
Error: The files expression/rc.cmi and frontend/gen/lexer_ref.cmi
       make inconsistent assumptions over interface Utility
make: *** [frontend/parser_e.cmx] Error 2
rm frontend/parser_name.ml

请注意,有问题的文件可能会更改,但这种情况经常发生。我要做的是 make clean 然后 make,因此它不是增量构建并且需要时间。

所以有人知道我应该在 makefile 中检查什么以减少出现此类错误的可能性吗?

编辑 1:

其实我所有的ml相关文件都是深度1,除了frontend/gen/*,深度是2。根据@camlspotter的回答,我稍微修改了ocamldep 我的一部分 makefile。现在看起来像这样:

DIRS= -I frontend -I frontend/gen -I lib ...

depend: $(AUTOGEN)
        # ocamldep -native $(DIRS) */*.ml */*.mli > depend # this is what was written before, I don't hink it is correct
        ocamldep -native $(DIRS) *.ml *.mli > depend

因此,make 跟随另一个 make 会立即给出不一致错误。

一个问题是我没有AUTOGEN,这正常吗?

还有一个问题是make depend生成了一个depend,有0个字符,正常吗?

编辑 2:

我按照 OCaml 源代码的 Makefile 修改了 depend:

beforedepend:: */*.ml

depend: beforedepend
    (for d in \
    frontend frontend/gen lib ... ; \
    do ocamldep $(DIRS) $$d/*.mli $$d/*.ml; \
    done) > depend

我实际上有大约20个文件夹,每个文件夹有1-5毫升的文件。这一次,make响过了for d in ...,不想停下来。但是如果我删除 3-4 个文件夹,它会在几秒钟后成功创建 depend

您的 Makefile 没有涵盖模块之间所有必要的依赖关系。

的含义
File "frontend/parser_e.ml", line 1:
Error: The files expression/rc.cmi and frontend/gen/lexer_ref.cmi
       make inconsistent assumptions over interface Utility

是:

  • frontend/parser_e.ml 取决于 expression/rc.mlfrontend/gen/lexer_ref.ml
  • expression/rc.mlfrontend/gen/lexer_ref.ml 都使用名为 Utility
  • 的模块
  • expression/rc.mlfrontend/gen/lexer_ref.ml必须与Utility的类型(接口)一致,但没有。

我想到造成这种状态的两种可能:

  • 可能有两个不同的utility.ml,例如dir_a/utility.mldir_b/utility.ml。 OCaml 不允许链接具有相同名称的模块。您可以使用打包模块解决此问题(请参阅 -pack 编译器选项)。你的情况不是这样。
  • 这两个模块使用相同的 utility.ml,但您的 Makefile 可能并不完全了解依赖关系。这就是你的情况。

第二种情况的一种可能情况是:

  • 您已修改 utility.mlutility.mli 并且其界面(.cmi 文件)已更改。
  • expression/rc.mlfrontend/gen/lexer_ref.ml 中的一个针对 Utility 的这个新接口重新编译,但另一个不是,因为依赖性未知。
  • 编译器发现两个模块在frontend/parser_e.ml中一起使用时存在不一致问题。

为了修复,您必须 运行 ocamldep 捕获所有必要的模块依赖项并将其通知给 make。注意:

  • 给出正确的选项和参数。由于您使用嵌套目录,因此需要多次 -I 选项。
  • 确保自动生成的 .ml.mli 文件确实在 ocamldep 运行 之前生成。由于您似乎有 .mly.mll 文件并且您遇到了有关它们的问题,我怀疑您在这里遗漏了一些东西。

在 OCaml 编译器源代码本身中可以找到 OCaml 模块依赖性分析的一个很好的例子。最好用 beforedependdependinclude .depend.

检查它的行

一般提示:

  • include .depend 添加到您的 Makefile 并将所有模块依赖项捕获到此 .depend 文件中,使用 ocamldep
  • 请注意,您项目的所有 .ml.mli 文件都必须由 ocamldep 扫描。不要忘记正确添加 -I 选项,否则它会遗漏一些依赖项。
  • 在 运行 宁 ocamldep 之前,确保自动生成 .ml.mli 文件,例如 .mly 和 [=40= 的输出] 生成。或者它遗漏了一些依赖项。

典型的 Makefile 如下所示:

beforedepend:: x.ml

x.ml: x.mly
  ocamlyacc x.mly

beforedepend:: y.ml

y.ml: y.mll
  ocamllex y.mll

depend: beforedepend
  ocamldep -I <dir1> -I <dir2> <all the ml and mli paths> > .depend

include .depend