
問題
我想查看 makefile 的一個或多個目標的依賴關係。所以我正在尋找一個可以解析 makefile 的程序,然後以某種樹狀格式(縮進,ascii-art,...)或圖形(點,...)來表示依賴關係。
相似的
有些程式可以在其他情況下執行此操作:
- 帕克特里或者債務樹可以以樹狀圖(如 ascii 格式)或
dot
圖形的形式顯示對應格式的軟體包的依賴關係, gcc -M source_file.c
將 C 原始檔的依賴關係顯示為 make 規則,- 樹顯示進程樹的 ascii 表示形式。
進步
搜尋網路我發現沒什麼幫助。這促使我嘗試
make --always-make --silent --dry-run some_target | \
grep --extended-regexp 'Considering target file|Trying rule prerequisite'
但看起來我必須在 perl 或 python 中破解一些更多的解析程式碼才能將其表示為一個漂亮的樹/圖。我還不知道我是否真的能透過這種方式獲得完整且正確的圖表。
要求
以某種方式限制圖表會很好(沒有內建規則,只有給定的目標,只有一定的深度),但在大多數情況下,我只是在尋找一個工具,它可以為我提供一些「合理」的依賴關係,人類-可查看的格式(就像“類似”下的程序一樣)。
問題
- 有什麼程式可以做到這一點嗎?
- 我能從 獲得完整且正確的資訊嗎
make -dnq ...
? - 有沒有更好的方法來獲取這些資訊?
- 用於解析此資訊的腳本/嘗試是否已經存在?
答案1
嘗試makefile2graph來自同一作者有一個類似的工具MakeGraph依賴關係寫成java
而不是c
.
make -Bnd | make2graph | dot -Tsvg -o out.svg
然後使用一些向量圖形編輯器來突出顯示您需要的連接。
答案2
答案3
我發現了一種駭客方法,至少可以輸出清晰的結構化訊息,說明哪個目標取決於哪些先決條件。缺點是,它非常具有侵入性。換句話說,您需要更改 makefile 以將所有目標的建置配方包裝到一個小的條件函數中。我將發布一個簡短的範例:
getRecipe = $(if $(DEPENDENCY_GRAPH),@echo Target $@ depends on prerequisites "$^",$(1))
VARIABLE_TARGET_NAME = foobar.txt
all : TopLevelTarget
TopLevelTarget : Target_A Target_D
$(call getRecipe,\
@echo Building target $@)
Target_A : Target_B
$(call getRecipe,\
@echo Building target $@)
Target_D : Target_C
$(call getRecipe,\
@echo Building target $@)
Target_B : $(VARIABLE_TARGET_NAME)
$(call getRecipe,\
@echo Building target $@)
Target_C :
$(call getRecipe,\
@echo Building target $@)
$(VARIABLE_TARGET_NAME) :
$(call getRecipe,\
@echo Building target $@)
在此範例中,我使用手動 getRecipe 函數來包裝每個單獨目標的配方,然後決定是否實際執行該配方或僅輸出正在建置的目標及其依賴的先決條件。後者僅在DEPENDENCY_GRAPH
設定變數時發生(例如作為環境變數)。在範例中,建立配方只不過是一個回顯,表示正在建立目標,但您顯然可以用您選擇的命令替換它。
設定為DEPENDENCY_GRAPH
1 時,輸出結果為:
Target foobar.txt depends on prerequisites ""
Target Target_B depends on prerequisites "foobar.txt"
Target Target_A depends on prerequisites "Target_B"
Target Target_C depends on prerequisites ""
Target Target_D depends on prerequisites "Target_C"
Target TopLevelTarget depends on prerequisites "Target_A Target_D"
這應該很容易解析然後轉換成點圖。
根本DEPENDENCY_GRAPH
不設定或設定為 0 時,輸出為:
Building target foobar.txt
Building target Target_B
Building target Target_A
Building target Target_C
Building target Target_D
Building target TopLevelTarget
或者,換句話說,使用正常的建造配方。我還沒有測試過這對於複雜的食譜是否可靠。我已經遇到的一個問題是它根本不適用於多行食譜。
例如,在最後一個目標的構建配方中,如果除了說正在構建目標之外,我實際上還想要touch
該文件:
$(VARIABLE_TARGET_NAME) :
$(call getRecipe,\
@echo Building target $@\
touch $@)
make
似乎認為該touch $@
部分只是前一行中迴聲的一部分:
Building target foobar.txt touch foobar.txt
如果我在前一行中省略尾部反斜杠,make
則會抱怨*** unterminated call to function
調用':缺失)'. Stop.
如果有人知道如何make
玩得好,我會洗耳恭聽。 :)
編輯:這種方法的另一個問題是,只有在不存在構建結果的情況下,這才有效,因為make
顯然不會執行它認為最新的目標的構建配方。
答案4
如果您只需要列出特定目標的依賴項,可以使用以下命令:
make -dn MAKE=: you_target | sed -rn "s/^ *Considering target file '(.*)'\.$/\1/p"
MAKE=:
是為了不跑孩子使。
不幸的是,包含的 Makefile 也被列出了。你可以將它們過濾掉使用以下 shell 腳本 ( list-deps
):
#!/bin/sh -e
dbg="`make -dn "$@"`"
all="`echo -n "$dbg" | sed -rn "s/^ *Considering target file '(.+)'\.$/\1/p"`"
mks="`echo -n "$dbg" | sed -rn "s/^ *Reading makefile '([^']+)'.*$/\1/p"`"
echo -n "$all" | grep -vxF "$mks"
現在您可以使用以下命令列出目標的所有依賴項:
list-deps MAKE=: your_target
如果您只需要列出需要重新製作的依賴項,請參閱這個答案。
編輯:對於找到此答案的其他人 - 您可以使用以下方式保留縮排
make -dn MAKE=: you_target | sed -rn "s/^(\s+)Considering target file '(.*)'\.$/\1\2/p"
您也可以將其作為 Makefile 中的目標:
.PHONY: graph
graph:
make -dn MAKE=: all | sed -rn "s/^(\s+)Considering target file '(.*)'\.$/\1\2/p"