
Problem
Ich möchte die Abhängigkeiten für ein oder mehrere Ziele eines Makefiles sehen. Daher suche ich nach einem Programm, das Makefiles analysieren und die Abhängigkeiten dann in einem baumartigen Format (Einrückung, ASCII-Art, ...) oder als Diagramm (Punkt, ...) darstellen kann.
Ähnlich
Es gibt Programme, die dies für andere Situationen tun:
- AbonnierenoderSchuldenbaumkann die Abhängigkeiten für Softwarepakete im jeweiligen Format in einem baumartigen ASCII-Format oder als
dot
Graph anzeigen, gcc -M source_file.c
zeigt die Abhängigkeiten der C-Quelldatei als Make-Regel an,- pstreezeigt eine ASCII-Darstellung des Prozessbaums an.
Fortschritt
Bei meiner Suche im Internet fand ichkleine HilfeDas brachte mich dazu, es zu versuchen
make --always-make --silent --dry-run some_target | \
grep --extended-regexp 'Considering target file|Trying rule prerequisite'
aber es sieht so aus, als müsste ich noch mehr Parsing-Code in Perl oder Python hacken, um dies als schönen Baum/Graph darzustellen. Und ich weiß noch nicht, ob ich auf diese Weise wirklich den vollständigen und korrekten Graphen bekomme.
Anforderungen
Es wäre schön, den Graphen in gewisser Weise einzuschränken (keine eingebaute Regel, nur ein vorgegebenes Ziel, nur eine gewisse Tiefe), aber größtenteils suche ich einfach nach einem Tool, das mir die Abhängigkeiten in einem „vernünftigen“, für Menschen lesbaren Format liefert (wie es die Programme unter „Ähnlich“ tun).
Fragen
- Gibt es Programme, die das können?
- Bekomme ich von vollständige und richtige Informationen
make -dnq ...
? - Gibt es eine bessere Möglichkeit, diese Informationen zu erhalten?
- Gibt es bereits Skripte/Versuche zum Parsen dieser Informationen?
Antwort1
Versuchenmakefile2graphvom gleichen Autor gibt es ein ähnliches ToolGraphabhängigkeiten erstellenjava
statt geschrieben c
.
make -Bnd | make2graph | dot -Tsvg -o out.svg
Verwenden Sie dann einen Vektorgrafikeditor, um die benötigten Verbindungen hervorzuheben.
Antwort2
ich benutzteneu erstellen --Profil(ein Drop-In-Ersatz für make
), es generierte einen Abhängigkeitsbaum in einem Callgrind-Format.
Danngprof2dotkann ein Bild des Zielbaums erzeugen.
Antwort3
Ich habe eine Art Hack gefunden, um zumindest klar strukturierte Informationen darüber auszugeben, welches Ziel von welchen Voraussetzungen abhängt. Der Nachteil ist, dass es ziemlich aufdringlich ist. Mit anderen Worten, Sie müssen Ihr Makefile ändern, um die Build-Rezepte aller Ihrer Ziele in eine kleine bedingte Funktion einzubinden. Ich poste ein kurzes Beispiel:
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 diesem Beispiel verwende ich die von Hand erstellte Funktion getRecipe, um das Rezept jedes einzelnen Ziels zu verpacken und dann zu entscheiden, ob dieses Rezept tatsächlich ausgeführt werden soll oder ob einfach ausgegeben werden soll, welches Ziel erstellt wird und von welchen Voraussetzungen es abhängt. Letzteres geschieht nur, wenn die Variable DEPENDENCY_GRAPH
festgelegt ist (z. B. als Umgebungsvariable). Im Beispiel ist das Build-Rezept nichts weiter als ein Echo, das angibt, dass das Ziel erstellt wird, aber Sie können dies natürlich durch einen Befehl Ihrer Wahl ersetzen.
Auf DEPENDENCY_GRAPH
1 gesetzt ergibt dies die Ausgabe:
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"
Das sollte einfach zu analysieren und dann in ein Punktdiagramm umzuwandeln sein.
Wenn DEPENDENCY_GRAPH
es gar nicht gesetzt oder auf 0 gesetzt ist, lautet die Ausgabe:
Building target foobar.txt
Building target Target_B
Building target Target_A
Building target Target_C
Building target Target_D
Building target TopLevelTarget
oder anders gesagt, es wird stattdessen das normale Build-Rezept verwendet. Ob das bei komplizierteren Rezepten zuverlässig funktioniert, habe ich noch nicht getestet. Ein Problem, auf das ich bereits gestoßen bin, ist, dass es bei mehrzeiligen Rezepten überhaupt nicht funktioniert.
Wenn ich beispielsweise im Build-Rezept des letzten Ziels nicht nur gesagt habe, dass das Ziel erstellt wird, sondern auch tatsächlich touch
die Datei haben wollte:
$(VARIABLE_TARGET_NAME) :
$(call getRecipe,\
@echo Building target $@\
touch $@)
make
scheint zu glauben, dass der touch $@
Teil lediglich ein Teil des Echos in der vorherigen Zeile ist:
Building target foobar.txt touch foobar.txt
Wenn ich den abschließenden Backslash in der vorherigen Zeile weglasse, fehlt der make
Beschwerdeaufruf *** unterminated call to function
. )'. Stop.
Wenn jemand eine Idee hat, wie man es hinbekommt, make
nett zu spielen, bin ich ganz Ohr. :)
BEARBEITEN: Das andere Problem bei diesem Ansatz besteht darin, dass er nur funktioniert, wenn noch keine Build-Ergebnisse vorliegen, da make
das Build-Rezept eines Ziels, das er als aktuell erachtet, offensichtlich nicht ausgeführt wird.
Antwort4
Wenn Sie nur die Abhängigkeiten für das bestimmte Ziel auflisten müssen, können Sie den folgenden Befehl verwenden:
make -dn MAKE=: you_target | sed -rn "s/^ *Considering target file '(.*)'\.$/\1/p"
MAKE=:
ist für nicht laufendes Kindmacht.
Leider werden auch die enthaltenen Makefiles aufgelistet.Filtern Sie sie herausmithilfe des folgenden Shell-Skripts ( 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"
Jetzt können Sie mit diesem Befehl alle Abhängigkeiten für das Ziel auflisten:
list-deps MAKE=: your_target
Wenn Sie nur die Abhängigkeiten auflisten möchten, die neu erstellt werden müssen, lesen Siediese Antwort.
Bearbeiten: Für andere, die diese Antwort finden - Sie können die Einrückung beibehalten, indem Sie
make -dn MAKE=: you_target | sed -rn "s/^(\s+)Considering target file '(.*)'\.$/\1\2/p"
Sie können dies auch im Makefile als Ziel festlegen:
.PHONY: graph
graph:
make -dn MAKE=: all | sed -rn "s/^(\s+)Considering target file '(.*)'\.$/\1\2/p"