Comment afficher les dépendances données dans un makefile sous forme d'arbre?

18

Problème

Je veux voir les dépendances pour une ou plusieurs cibles d'un makefile. Je recherche donc un programme qui peut analyser les makefiles et représenter ensuite les dépendances dans un format arborescent (indentation, ascii-art, ...) ou sous forme de graphique (point, ...).

Similaire

Il existe des programmes qui le font pour d'autres situations:

  • pactree ou debtree peuvent afficher les dépendances des packages logiciels au format respectif dans une arborescence comme le format ascii ou sous forme de dotgraphique,
  • gcc -M source_file.c affiche les dépendances du fichier source C en tant que règle de création,
  • pstree affiche une représentation ascii de l'arbre de processus.

Le progrès

En cherchant sur le Web, j'ai trouvé peu d'aide . Cela m'a amené à essayer

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

mais il semble que je doive pirater un peu plus de code d'analyse en perl ou en python afin de le représenter comme un joli arbre / graphique. Et je ne sais pas encore si je vais vraiment obtenir le graphique complet et correct de cette façon.

Exigences

Ce serait bien de limiter le graphique à certains égards (pas de règle intégrée, seulement une cible donnée, seulement une certaine profondeur) mais pour la plupart je cherche juste un outil qui me donnera les dépendances dans certains "raisonnables", humains -Format visible (comme le font les programmes sous "Similaire").

Des questions

  • Y a-t-il des programmes qui peuvent le faire?
  • Vais-je obtenir les informations complètes et correctes de make -dnq ...?
  • Existe-t-il un meilleur moyen d'obtenir ces informations?
  • Des scripts / tentatives d'analyse de ces informations existent-ils déjà?
Lucas
la source
1
La chose cruciale à comprendre ici est: les dépendances ne forment PAS un arbre. Ils forment un graphique dirigé et (espérons-le!) Acyclique, également connu sous le nom de DAG . Essayez d'esquisser le graphique de dépendance pour ce qui suit et vous le verrez: A dépend de B; A dépend également de C; B dépend de D; C dépend de D.
Wildcard
@Wildcard Je sais mais pour mon but, il suffit de représenter les dépendances comme un arbre. Je suis d'accord avec la duplication des sous-graphiques (et la découpe dans les cercles) pour en faire un arbre. Désolé de ne pas être explicite. Pour votre exemple, je serais bien avec la sortie de printf 'A\n B\n D\n C\n D\n'. (Qui a dit que je ne pouvais pas mettre de nouvelles lignes dans les commentaires? :)
Lucas
Comment cela se distinguerait-il de "A dépend de B; B dépend de D; D dépend de C; A dépend de D"? Vous pouvez imposer un ordre total à n'importe quel DAG (car tout DAG représente également un ordre partiel), mais vous ne pouvez pas transformer un DAG en arborescence. Il s'agit de la théorie des graphes de base. Je serais intéressé de voir votre algorithme pour créer une représentation arborescente d'un DAG qui pourrait ensuite être affichée. Sans un tel algorithme sous-jacent, tout outil qui chercherait à afficher les dépendances sous forme d'arbre serait nécessairement extrêmement hacky et sujet aux erreurs.
Wildcard
Peut-être que je n'étais pas encore assez explicite, mais je pensais que les exemples que je donnais sous Similaire étaient clairs. Je ne suis pas intéressé par la théorie des graphes (du moins dans cette question). Tout ce que je veux, c'est une représentation visuelle qui ressemble à un arbre (surtout si elle doit être affichée sur un terminal, car les dotgraphiques de commande sont évidemment très bien.) Je mettrai à jour un peu la question pour la rendre plus claire (j'espère).
Lucas
2
RANT: Honnêtement, je suis un peu frustré de voir que make n'offre pas quelque chose comme ça, prêt à l'emploi. Make est l'un des systèmes de construction les plus répandus au monde, et cette fonctionnalité serait si immensément utile qu'il est difficile de comprendre que pendant Dieu sait combien de décennies cette marque a existé, personne n'a ajouté une telle fonctionnalité. Produire ces informations dans un format textuel clairement défini serait tout à fait suffisant. Je comprends que make est open source et je pourrais toujours ajouter cette fonctionnalité moi-même. Et croyez-moi, si make n'était pas fondamentalement une boîte noire pour moi, je le ferais! RANT sur.
entrée le

Réponses:

10

Essayez makefile2graph du même auteur, il existe un outil similaire MakeGraphDependencies écrit à la javaplace de c.

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

Utilisez ensuite un éditeur de graphiques vectoriels pour mettre en évidence les connexions dont vous avez besoin.

xae
la source
1
J'ai essayé cet outil. Ne commence même pas à fonctionner (du moins pour aucune des incarnations de make avec lesquelles j'ai essayé). La plupart du temps, il se contente de violer l'accès à la mémoire.
entrée le
3

J'ai trouvé une sorte de hack pour produire au moins des informations clairement structurées sur quelle cible dépend de quelles conditions préalables. L'inconvénient est que c'est assez intrusif. En d'autres termes, vous devez modifier votre makefile pour encapsuler les recettes de construction de toutes vos cibles dans une petite fonction conditionnelle. Je posterai un bref exemple:

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 $@)

Dans cet exemple, j'utilise la fonction getRecipe roulée à la main pour encapsuler la recette de chaque cible individuelle, puis décider s'il faut réellement exécuter cette recette ou simplement afficher la cible en cours de construction et les conditions préalables dont elle dépend. Cette dernière ne se produit que si la variable DEPENDENCY_GRAPHest définie (par exemple en tant que variable d'environnement). Dans l'exemple, la recette de construction n'est rien de plus qu'un écho disant que la cible est en cours de construction, mais vous pouvez évidemment la remplacer par une commande de votre choix.

Avec DEPENDENCY_GRAPH1, cela donne la sortie:

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"

qui devrait être assez facile à analyser puis à convertir en un graphique à points.

Avec DEPENDENCY_GRAPHpas du tout défini ou réglé sur 0, la sortie est:

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

ou, en d'autres termes, la recette de construction normale est utilisée à la place. Je n'ai pas encore testé si cela fonctionne de manière fiable avec des recettes compliquées. Un problème que j'ai déjà rencontré est qu'il ne fonctionne pas du tout avec des recettes multi-lignes.

Par exemple, dans la recette de construction de la dernière cible, si en plus de dire que la cible est en cours de construction, je voulais en fait touchle fichier:

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

makesemble penser que la touch $@partie fait simplement partie de l'écho de la ligne précédente:

Building target foobar.txt touch foobar.txt

Si je laisse la barre oblique inverse à la ligne précédente, se makeplaint l' *** unterminated call to functionappel ': manquant )'. Stop.Si quelqu'un a une idée de comment makejouer gentiment, je suis à l'écoute. :)

EDIT: L'autre problème avec cette approche est que cela ne fonctionnera que si aucun résultat de build n'existe déjà, car makeévidemment n'exécute pas la recette de build d'une cible qu'il considère à jour.

furieux
la source
ajouter ;après target $@la commande tactile à works
mug896
pour le deuxième problème, utilisez l' make -Boption qui fait inconditionnellement toutes les cibles.
mug896
2

J'ai utilisé remake --profile (un remplacement pour make), il a généré un arbre de dépendance au format callgrind.

alors gprof2dot peut générer une image de l'arborescence cible.

Victor Sergienko
la source
Est-ce que je comprends mal la documentation ou ne remake --profilegénère que le graphique des dépendances pour la cible qu'il exécute? Ou peut-il en quelque sorte sortir le graphique pour toutes les cibles?
Lucas
Seul celui qu'il dirige, je le crains. Mais vous pouvez tous les exécuter avec -dry-run
Victor Sergienko
Oh oui, quelque chose comme remake --targets -r | grep -v %| grep -v '\t*\.'|xargs remake -n --profile -Bprometteur.
Lucas