Wie werden Abhängigkeiten, die in einem Makefile angegeben sind, als Baum angezeigt?

18

Problem

Ich möchte die Abhängigkeiten für ein oder mehrere Ziele eines Makefiles sehen. Ich suche also ein Programm, das Makefiles parsen kann und dann die Abhängigkeiten in einem baumartigen Format (Einrückung, ASCII-Grafik, ...) oder als Grafik (Punkt, ...) darstellt.

Ähnlich

Es gibt Programme, die dies für andere Situationen tun:

  • Pactree oder Debtree können die Abhängigkeiten für Software-Pakete im jeweiligen Format in einem Baum wie ASCII-Format oder als dotGrafik anzeigen.
  • gcc -M source_file.c zeigt die Abhängigkeiten der C-Quelldatei als make-Regel an,
  • pstree zeigt eine ASCII-Darstellung des Prozessbaums an.

Fortschritt

Beim Durchsuchen des Webs habe ich wenig Hilfe gefunden . Das hat mich dazu gebracht, 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 einen schönen Baum / Graphen darzustellen. Und ich weiß noch nicht, ob ich auf diese Weise wirklich die vollständige und korrekte Grafik bekomme.

Bedarf

Es wäre schön, den Graphen in gewisser Weise einzuschränken (keine eingebaute Regel, nur ein bestimmtes Ziel, nur eine gewisse Tiefe), aber zum größten Teil suche ich nur nach einem Werkzeug, das mir die Abhängigkeiten in einem "vernünftigen", menschlichen Bereich gibt -sichtbares Format (wie die Programme unter "Ähnlich").

Fragen

  • Gibt es Programme, die das können?
  • Erhalte ich die vollständigen und korrekten Informationen von make -dnq ...?
  • Gibt es einen besseren Weg, um diese Informationen zu bekommen?
  • Gibt es bereits Skripte / Versuche zum Parsen dieser Informationen?
Lucas
quelle
1
Das Entscheidende dabei ist zu verstehen: Abhängigkeiten bilden KEINEN Baum. Sie bilden einen gerichteten und (hoffentlich!) Azyklischen Graphen - auch als DAG bekannt . Wenn Sie das Abhängigkeitsdiagramm für Folgendes skizzieren, wird es angezeigt: A hängt von B ab; A hängt auch von C ab; B hängt von D ab; C hängt von D ab.
Wildcard
@Wildcard Ich weiß, aber für meinen Zweck reicht es aus, die Abhängigkeiten als Baum darzustellen . Es ist in Ordnung, Untergraphen zu duplizieren (und in Kreise zu schneiden), um daraus einen Baum zu machen. Entschuldigung, dass Sie nicht explizit angegeben haben. Für Sie zum Beispiel wäre ich mit der Ausgabe von in Ordnung printf 'A\n B\n D\n C\n D\n'. (Wer hat gesagt, dass ich in Kommentaren keine Zeilenumbrüche einfügen kann? :)
Lucas
Wie wäre das unterscheidbar von "A hängt von B ab; B hängt von D ab; D hängt von C ab; A hängt von D ab"? Sie können jeder DAG eine Gesamtreihenfolge auferlegen (da jede DAG auch eine Teilreihenfolge darstellt), aber Sie können eine DAG nicht in einen Baum verwandeln. Dies ist die grundlegende Graphentheorie. Es würde mich interessieren, Ihren Algorithmus zum Erstellen einer Baumdarstellung einer DAG zu sehen, die dann angezeigt werden könnte. Ohne einen solchen zugrunde liegenden Algorithmus wäre jedes Tool, das Abhängigkeiten als Baum darstellen möchte, zwangsläufig extrem hacky und fehleranfällig.
Wildcard
Vielleicht war ich wieder nicht explizit genug, aber ich dachte, die Beispiele, die ich unter Ähnliches gebe, machten es klar. Die Graphentheorie interessiert mich nicht (zumindest in dieser Frage). Ich möchte lediglich eine visuelle Darstellung, die einem Baum ähnelt (insbesondere, wenn sie auf einem Terminal angezeigt werden soll, da dotOrdnungsdiagramme offensichtlich in Ordnung sind). Ich werde die Frage ein wenig aktualisieren, um sie klarer zu machen (ich hoffe).
Lucas
2
RANT: Ehrlich gesagt bin ich ein bisschen frustriert, dass make so etwas nicht sofort anbietet. Make ist eines der am weitesten verbreiteten Build-Systeme der Welt, und dieses Feature wäre so immens nützlich, dass es schwer zu fassen ist, dass während der Zeit, in der Gott weiß, wie viele Jahrzehnte dieses Make existiert hat, niemand ein solches Feature hinzugefügt hat. Die Ausgabe dieser Informationen in einem klar definierten Textformat wäre völlig ausreichend. Ich verstehe, dass make Open Source ist und ich könnte dieses Feature jederzeit selbst hinzufügen. Und glauben Sie mir, wenn make für mich im Grunde keine Blackbox wäre, würde ich es tun! Aufregen über.
27.

Antworten:

10

Versuchen makefile2graph vom selben Autor gibt es aa ähnliches Werkzeug MakeGraphDependencies geschrieben javastatt c.

make -Bnd | make2graph | dot -Tsvg -o out.svg

Verwenden Sie dann einen Vektorgrafik-Editor, um die Verbindungen hervorzuheben, die Sie benötigen.

xae
quelle
1
Ich habe das Tool ausprobiert. Beginnt nicht einmal zu arbeiten (zumindest nicht für eine der Inkarnationen, mit denen ich es ausprobiert habe). Meistens kommt es nur zu einer Verletzung des Speicherzugriffs.
Antred
3

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 zu verwandeln. Ich werde ein kurzes Beispiel posten:

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 gerollte Funktion getRecipe, um das Rezept jedes einzelnen Ziels zu verpacken und dann zu entscheiden, ob dieses Rezept tatsächlich ausgeführt oder einfach ausgegeben werden soll, welches Ziel erstellt wird und von welchen Voraussetzungen es abhängt. Letzteres geschieht nur, wenn die Variable DEPENDENCY_GRAPHgesetzt ist (zB als Umgebungsvariable). In diesem Beispiel ist das Erstellungsrezept nichts anderes als ein Echo, das besagt, dass das Ziel erstellt wird, aber Sie können dies natürlich durch einen Befehl Ihrer Wahl ersetzen.

Bei DEPENDENCY_GRAPH1 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 genug sein, um es zu analysieren und dann in ein Punktdiagramm umzuwandeln.

Wenn überhaupt DEPENDENCY_GRAPHnicht gesetzt oder auf 0 gesetzt ist, ist 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 mit anderen Worten, es wird stattdessen das normale Build-Rezept verwendet. Ich habe noch nicht getestet, ob dies bei komplizierten Rezepten zuverlässig funktioniert. Ein Problem, auf das ich bereits gestoßen bin, ist, dass es bei mehrzeiligen Rezepten überhaupt nicht funktioniert.

Zum Beispiel wollte ich im Build-Rezept des letzten Ziels, zusätzlich zu der Aussage, dass das Ziel gebaut wird, tatsächlich touchdie Datei:

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

makescheint zu denken, dass der touch $@Teil nur 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, makebeschwert sich *** unterminated call to functioncall ': missing )'. Stop.Wenn jemand eine Idee hat, wie man makeschön spielen kann, bin ich ganz Ohr. :)

BEARBEITEN: Das andere Problem bei diesem Ansatz ist, dass dies nur funktioniert, wenn noch keine Build-Ergebnisse vorhanden sind, da makedas Build-Rezept eines Ziels, das es für aktuell hält , offensichtlich nicht ausgeführt wird.

antred
quelle
;target $@
Fügen
Verwenden Sie für das zweite Problem die make -BOption, mit der alle Ziele bedingungslos festgelegt werden.
mug896
2

Ich habe remake --profile (ein Drop-In-Ersatz für make) verwendet. Es hat einen Abhängigkeitsbaum in einem Callgrind-Format generiert.

Dann kann gprof2dot ein Bild des Zielbaums erzeugen.

Victor Sergienko
quelle
Verstehe ich die Dokumentation falsch oder wird remake --profilenur das Abhängigkeitsdiagramm für das Ziel ausgegeben, das es ausführt? Oder kann es irgendwie die Grafik für alle Ziele ausgeben?
Lucas
Ich fürchte, nur der, der läuft. Aber man kann sie alle mit -dry-run laufen
Victor Sergienko
Oh ja, so etwas remake --targets -r | grep -v %| grep -v '\t*\.'|xargs remake -n --profile -Bsieht vielversprechend aus.
Lucas