问题
我想查看 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
调用':missing)'. 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"