第 18 章 相依性產生器 (ocamldep)

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,則只有在目前目錄或使用 -I 指定的目錄之一中找到 bar 的原始碼時,才會產生對該單元介面 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 計算它們。