How to display dependencies given in a makefile as a tree?
Try makefile2graph from the same author there is a a similar tool MakeGraphDependencies written in java
instead of c
.
make -Bnd | make2graph | dot -Tsvg -o out.svg
Then use some vector graphics editor to highlight connections you need.
I have found a kind of hack to at least output clearly structured information about which target depends on which prerequisites. The downside is, it's quite intrusive. In other words, you need to change your makefile to wrap the build recipes of all your targets into a little conditional function. I'll post a brief example:
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 $@)
In this example, I'm using the hand-rolled getRecipe function to wrap each individual target's recipe and then decide whether to actually run that recipe or simply output which target is being built and which prerequisites it depends on. The latter happens only if the variable DEPENDENCY_GRAPH
is set (e.g. as an environment variable). In the example, the build recipe is nothing more than an echo saying that the target is being built, but you could obviously replace this with a command of your choice.
With DEPENDENCY_GRAPH
set to 1, this results in the output:
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"
which should be easy enough to parse and then convert into a dot-graph.
With DEPENDENCY_GRAPH
not set at all or set to 0, the output is:
Building target foobar.txt
Building target Target_B
Building target Target_A
Building target Target_C
Building target Target_D
Building target TopLevelTarget
or, in other words, the normal build recipe is used instead. I haven't tested yet whether this works reliably with complicated recipes. One problem I've already run into is that it doesn't work at all with multi-line recipes.
For instance, in the last target's build recipe, if in addition to saying that the target is being built I actually wanted to touch
the file:
$(VARIABLE_TARGET_NAME) :
$(call getRecipe,\
@echo Building target $@\
touch $@)
make
seems to think that the touch $@
part is merely part of the echo in the previous line:
Building target foobar.txt touch foobar.txt
If I leave off the trailing backslash in the previous line, make
complains *** unterminated call to function
call': missing )'. Stop.
If anyone has an idea how to get make
to play nice, I'm all ears. :)
EDIT: The other problem with this approach is that this will only work if no build results already exist, as make
obviously doesn't execute the build recipe of a target it considers up-to-date.
I used remake --profile (a drop-in replacement for make
), it generated a dependency tree in a callgrind format.
Then gprof2dot can generate an image of the target tree.