Problem

Problem

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 dotGraph anzeigen,
  • gcc -M source_file.czeigt 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 erstellenjavastatt 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_GRAPHfestgelegt 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_GRAPH1 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_GRAPHes 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 touchdie Datei haben wollte:

$(VARIABLE_TARGET_NAME) :
    $(call getRecipe,\
        @echo Building target $@\
        touch $@)

makescheint 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 makeBeschwerdeaufruf *** unterminated call to function. )'. Stop.Wenn jemand eine Idee hat, wie man es hinbekommt, makenett 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 makedas 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" 

verwandte Informationen