Come visualizzare le dipendenze fornite in un makefile come albero?


18

Problema

Voglio vedere le dipendenze per uno o più target di un makefile. Quindi sto cercando un programma in grado di analizzare i makefile e quindi rappresentare le dipendenze in un formato simile ad un albero (rientro, ascii-art, ...) o come un grafico (punto, ...).

Simile

Esistono programmi che lo fanno per altre situazioni:

  • pactree o debitree possono visualizzare le dipendenze per i pacchetti software nel rispettivo formato in un albero come formato ASCII o come dotgrafico,
  • gcc -M source_file.c visualizza le dipendenze del file sorgente C come regola di creazione,
  • pstree visualizza una rappresentazione ASCII dell'albero di processo.

Progresso

Cercando sul web ho trovato poco aiuto . Questo mi ha portato a provare

make --always-make --silent --dry-run some_target | \
  grep --extended-regexp 'Considering target file|Trying rule prerequisite'

ma sembra che devo hackerare un po 'più di codice di analisi in perl o python per rappresentare questo come un bel albero / grafico. E non so ancora se otterrò davvero il grafico completo e corretto in questo modo.

Requisiti

Sarebbe bello limitare il grafico in qualche modo (nessuna regola incorporata, solo un determinato obiettivo, solo una certa profondità) ma per la maggior parte sto solo cercando uno strumento che mi dia le dipendenze in qualche "ragionevole", umano formato visualizzabile (come fanno i programmi in "Simile").

Domande

  • Ci sono programmi che possono farlo?
  • Riceverò le informazioni complete e corrette da make -dnq ...?
  • C'è un modo migliore per ottenere queste informazioni?
  • Esistono già script / tentativi di analisi di queste informazioni?

1
La cosa cruciale da capire qui è: le dipendenze NON formano un albero. Formano un grafico diretto e (si spera!) Aciclico, noto anche come DAG . Prova a delineare il grafico delle dipendenze per quanto segue e lo vedrai: A dipende da B; A dipende anche da C; B dipende da D; C dipende da D.
Wildcard

@Wildcard Lo so, ma per il mio scopo è sufficiente rappresentare le dipendenze come un albero. Sto bene duplicando i sottografi (e tagliando i cerchi) per renderlo un albero. Ci scusiamo per non essere esplicito. Per il tuo esempio, starei bene con l'output di printf 'A\n B\n D\n C\n D\n'. (Chi ha detto che non posso inserire nuove righe nei commenti? :)
Lucas

Come sarebbe distinguibile da "A dipende da B; B dipende da D; D dipende da C; A dipende da D"? È possibile imporre un ordine totale su qualsiasi DAG (poiché qualsiasi DAG rappresenta anche un ordine parziale), ma non è possibile trasformare un DAG in un albero. Questa è la teoria dei grafi di base. Sarei interessato a vedere il tuo algoritmo per la creazione di una rappresentazione ad albero di un DAG che potrebbe quindi essere visualizzato. Senza un tale algoritmo sottostante, qualsiasi strumento che cercasse di mostrare dipendenze come un albero sarebbe necessariamente estremamente caotico e soggetto a errori.
Carattere jolly

Forse non ero ancora abbastanza esplicito, ma pensavo che gli esempi che fornissi in Simile lo chiarissero. Non mi interessa la teoria dei grafi (almeno in questa domanda). Tutto ciò che voglio per questo è una rappresentazione visiva che assomigli ad un albero (specialmente se dovrebbe essere visualizzato su un terminale, poiché i dotgrafici dell'ordine sono ovviamente a posto.) Aggiornerò un po 'la domanda per renderla più chiara (spero).
Lucas,

2
RANT: Sinceramente sono un po 'frustrato dal fatto che make non offra qualcosa di simile. Make è uno dei sistemi di costruzione più diffusi al mondo, e questa caratteristica sarebbe così immensamente utile che è difficile capire che durante il dio sa quanti decenni che sono esistiti nessuno ha aggiunto una tale funzionalità. L'emissione di queste informazioni in un formato testuale chiaramente definito sarebbe totalmente sufficiente. Capisco che make sia open source e potrei sempre aggiungere questa funzione da solo. E credimi, se make non fosse sostanzialmente una scatola nera per me, lo farei! AFFRONTATI.
Antred,

Risposte:


10

Prova makefile2graph dello stesso autore, c'è uno strumento simile con MakeGraphDependencies scritto javainvece di c.

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

Quindi utilizzare un editor di grafica vettoriale per evidenziare le connessioni necessarie.


1
Ho provato quello strumento. Non inizia nemmeno a funzionare (almeno non per nessuna delle incarnazioni fatte con cui l'ho provato). Il più delle volte esce solo con qualche violazione dell'accesso alla memoria.
Antred,

3

Ho trovato una sorta di hack per almeno fornire informazioni chiaramente strutturate su quale target dipende da quali prerequisiti. Il rovescio della medaglia è che è abbastanza invadente. In altre parole, è necessario modificare il proprio makefile per avvolgere le ricette di build di tutti i target in una piccola funzione condizionale. Pubblicherò un breve esempio:

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 questo esempio, sto usando la funzione getRecipe arrotolata a mano per avvolgere la ricetta di ogni singolo target e quindi decidere se eseguire effettivamente quella ricetta o semplicemente emettere quale target viene costruito e da quali prerequisiti dipende. Quest'ultimo accade solo se la variabile DEPENDENCY_GRAPHè impostata (ad es. Come variabile d'ambiente). Nell'esempio, la ricetta di costruzione non è altro che un'eco che dice che il bersaglio è in costruzione, ma è possibile sostituirlo ovviamente con un comando a scelta.

Con DEPENDENCY_GRAPHimpostato su 1, questo porta all'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"

che dovrebbe essere abbastanza facile da analizzare e quindi convertire in un punto-grafico.

Con DEPENDENCY_GRAPHnon impostato affatto o impostato su 0, l'output è:

Building target foobar.txt
Building target Target_B
Building target Target_A
Building target Target_C
Building target Target_D
Building target TopLevelTarget

o, in altre parole, viene utilizzata la normale ricetta di costruzione. Non ho ancora testato se questo funziona in modo affidabile con ricette complicate. Un problema che ho già riscontrato è che non funziona affatto con le ricette multilinea.

Ad esempio, nell'ultima ricetta di creazione del target, se oltre a dire che il target è stato creato, volevo effettivamente touchil file:

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

makesembra pensare che la touch $@parte sia semplicemente parte dell'eco nella riga precedente:

Building target foobar.txt touch foobar.txt

Se lascio perdere la barra rovesciata nella riga precedente, mi makelamento *** unterminated call to function'call: missing )'. Stop.Se qualcuno ha idea di come makegiocare bene, sono tutto orecchi. :)

EDIT: l'altro problema con questo approccio è che funzionerà solo se non esistono già risultati di build, dato che makeovviamente non esegue la ricetta di build di un target che considera aggiornato.


aggiungi ;dopo target $@il comando touch per funzionare
mug896

per il secondo problema, utilizzare l' make -Bopzione che crea incondizionatamente tutti i target.
mug896

2

Ho usato remake --profile (una sostituzione drop-in per make), ha generato un albero delle dipendenze in un formato callgrind.

Quindi gprof2dot può generare un'immagine dell'albero di destinazione.


Capisco la documentazione errata o genera remake --profilesolo il grafico delle dipendenze per la destinazione che esegue? O può in qualche modo generare il grafico per tutti gli obiettivi?
Lucas,

Ho paura solo di quello che corre. Ma è possibile eseguire tutte con dry-run
Victor Sergienko

Oh sì, qualcosa di simile remake --targets -r | grep -v %| grep -v '\t*\.'|xargs remake -n --profile -Bsembra promettente.
Lucas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.