第 18 章 依赖生成器 (ocamldep)

The ocamldep 命令扫描一组 OCaml 源文件 (.ml.mli 文件) 以查找对外部编译单元的引用,并以适合 make 实用程序的格式输出依赖关系行。这确保了 make 将以正确的顺序编译源文件,并在修改源文件时重新编译需要重新编译的文件。

典型的用法是

        ocamldep options *.mli *.ml > .depend

其中 *.mli *.ml 展开到当前目录中的所有源文件,而 .depend 是应包含依赖关系的文件。(有关典型的 Makefile,请参见下文。)

为使用字节码编译器 ocamlc 和使用原生代码编译器 ocamlopt 进行编译生成依赖关系。

1 选项

ocamldep 识别以下命令行选项。

-absname
在错误消息中显示绝对文件名。
-all
生成所有必需文件的依赖关系,而不是假设隐式依赖关系。
-allow-approx
在解析失败时允许回退到基于词法分析器的近似值。
-args filename
filename 读取其他以换行符结尾的命令行参数。
-args0 filename
filename 读取其他以空字符结尾的命令行参数。
-as-map
对于以下文件,不包括模块别名的延迟依赖关系。此选项假设它们是使用选项 -no-alias-deps -w -49 编译的,并且在为其他文件计算依赖关系时,使用 -map 选项传递这些文件或其接口。另请注意,为了使依赖关系在映射文件的实现中正确,其接口不应强制转换其包含的任何别名。
-debug-map
转储每个映射文件的延迟依赖关系映射。
-I directory
将给定目录添加到用于搜索源文件的目录列表中。如果源文件 foo.ml 提到了外部编译单元 Bar,则仅当 bar 的源代码在当前目录或使用 -I 指定的目录之一中找到时,才会生成对该单元的接口 bar.cmi 的依赖关系。否则,假设 Bar 是来自标准库的模块,并且不会生成任何依赖关系。对于跨多个目录的程序,建议将相同的 -I 选项传递给 ocamldep,这些选项传递给编译器。
-H directory
行为与 -I 相同,只是最后搜索 -H 目录。包含此标志是为了更轻松地使用与编译器相同的选项调用 ocamldep,其中 -H 用于程序不应直接提到的传递依赖关系。
-nocwd
不要将当前工作目录添加到包含目录列表中。
-impl file
file 作为 .ml 文件处理。
-intf file
file 作为 .mli 文件处理。
-map file
读取并传播 file 中模块别名的延迟依赖关系,以便如果后续文件使用这些模块,则它们将依赖于导出的别名模块。请参见下面的示例。
-ml-synonym .ext
将给定的扩展名(带前导点)视为 .ml 的同义词。
-mli-synonym .ext
将给定的扩展名(带前导点)视为 .mli 的同义词。
-modules
输出以下形式的原始依赖关系:
      filename: Module1 Module2 ... ModuleN
其中 Module1、…、ModuleN 是文件 filename 中引用的编译单元的名称,但这些名称不会解析为源文件名。此类原始依赖关系无法被 make 使用,但可以由其他工具(如 Omake)进行后处理。
-native
为纯原生代码程序(没有字节码版本)生成依赖关系。当实现文件(.ml 文件)没有显式接口文件(.mli 文件)时,ocamldep 会生成对字节码编译文件(.cmo 文件)的依赖关系以反映接口更改。这可能会导致仅编译为原生代码的程序进行不必要的字节码重新编译。标志 -native 会导致生成对原生编译文件(.cmx)的依赖关系,而不是对 .cmo 文件的依赖关系。(如果所有源文件都有显式的 .mli 接口文件,则此标志没有任何区别。)
-one-line
每个文件输出一行,而不管长度如何。
-open module
假设在解析每个后续文件之前都打开了模块 module
-pp command
导致 ocamldep 将给定的 command 作为每个源文件的预处理器调用。
-ppx command
通过预处理器 command 传递抽象语法树。
-shared
除了原生编译文件 (.cmx) 之外,还为原生插件文件 (.cmxs) 生成依赖关系。
-slash
在 Windows 下,使用正斜杠 (/) 作为路径分隔符,而不是通常的反斜杠 (\)。在 Unix 下,此选项不执行任何操作。
-sort
根据文件的依赖关系对文件进行排序。
-version
打印版本字符串并退出。
-vnum
打印简短的版本号并退出。
-help--help
显示简短的使用摘要并退出。

2 一个典型的 Makefile

这是一个 OCaml 程序的模板 Makefile

OCAMLC=ocamlc
OCAMLOPT=ocamlopt
OCAMLDEP=ocamldep
INCLUDES=                 # all relevant -I options here
OCAMLFLAGS=$(INCLUDES)    # add other options for ocamlc here
OCAMLOPTFLAGS=$(INCLUDES) # add other options for ocamlopt here

# prog1 should be compiled to bytecode, and is composed of three
# units: mod1, mod2 and mod3.

# The list of object files for prog1
PROG1_OBJS=mod1.cmo mod2.cmo mod3.cmo

prog1: $(PROG1_OBJS)
        $(OCAMLC) -o prog1 $(OCAMLFLAGS) $(PROG1_OBJS)

# prog2 should be compiled to native-code, and is composed of two
# units: mod4 and mod5.

# The list of object files for prog2
PROG2_OBJS=mod4.cmx mod5.cmx

prog2: $(PROG2_OBJS)
        $(OCAMLOPT) -o prog2 $(OCAMLFLAGS) $(PROG2_OBJS)

# Common rules

%.cmo: %.ml
        $(OCAMLC) $(OCAMLFLAGS) -c $<

%.cmi: %.mli
        $(OCAMLC) $(OCAMLFLAGS) -c $<

%.cmx: %.ml
        $(OCAMLOPT) $(OCAMLOPTFLAGS) -c $<

# Clean up
clean:
        rm -f prog1 prog2
        rm -f *.cm[iox]

# Dependencies
depend:
        $(OCAMLDEP) $(INCLUDES) *.mli *.ml > .depend

include .depend

如果您使用模块别名来为模块提供更短的名称,则需要更改上述定义。假设您的映射文件称为 mylib.mli,以下是最低限度的修改。

OCAMLFLAGS=$(INCLUDES) -open Mylib

mylib.cmi: mylib.mli
        $(OCAMLC) $(INCLUDES) -no-alias-deps -w -49 -c $<

depend:
        $(OCAMLDEP) $(INCLUDES) -map mylib.mli $(PROG1_OBJS:.cmo=.ml) > .depend

请注意,在这种情况下,您不应与其他文件一起计算 mylib.mli 的依赖关系,因此需要显式传递要处理的文件列表。如果 mylib.mli 本身具有依赖关系,则应使用 -as-map 计算这些依赖关系。