¿Cómo mostrar las dependencias dadas en un archivo MAKE como un árbol?

18

Problema

Quiero ver las dependencias para uno o más objetivos de un archivo MAKE. Por lo tanto, estoy buscando un programa que pueda analizar archivos MAKE y luego represente las dependencias en un formato similar a un árbol (sangría, arte ascii, ...) o como un gráfico (punto, ...).

Similar

Hay programas que hacen esto para otras situaciones:

  • pactree o deuda libre puede mostrar las dependencias de los paquetes de software en el formato respectivo en un árbol como formato ascii o como un dotgráfico,
  • gcc -M source_file.c muestra las dependencias del archivo fuente C como una regla de creación,
  • pstree muestra una representación ascii del árbol de procesos.

Progreso

Buscando en la web encontré poca ayuda . Eso me llevó a intentar

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

pero parece que tengo que hackear un poco más de código de análisis en perl o python para representar esto como un buen árbol / gráfico. Y aún no sé si realmente obtendré el gráfico completo y correcto de esta manera.

Requisitos

Sería bueno limitar el gráfico de alguna manera (sin regla incorporada, solo un objetivo dado, solo algo de profundidad) pero en su mayor parte solo estoy buscando una herramienta que me proporcione las dependencias en algunos humanos "razonables" formato visible (como los programas en "Similar" do).

Preguntas

  • ¿Hay algún programa que pueda hacer esto?
  • ¿Recibiré la información completa y correcta make -dnq ...?
  • ¿Hay una mejor manera de obtener esta información?
  • ¿Ya existen scripts / intentos para analizar esta información?
Lucas
fuente
1
Lo crucial que hay que entender aquí es: las dependencias NO forman un árbol. Forman un gráfico dirigido y (¡con suerte!) Acíclico, también conocido como DAG . Intente dibujar el gráfico de dependencia para lo siguiente y lo verá: A depende de B; A también depende de C; B depende de D; C depende de D.
Wildcard
@Wildcard Lo sé, pero para mi propósito es suficiente representar las dependencias como un árbol. Estoy bien duplicando subgrafías (y cortando círculos) para convertirlo en un árbol. Perdón por no ser explícito. Por ejemplo, estaría bien con la salida de printf 'A\n B\n D\n C\n D\n'. (¿Quién dijo que no puedo poner nuevas líneas en los comentarios? :)
Lucas
¿Cómo podría distinguirse eso de "A depende de B; B depende de D; D depende de C; A depende de D"? Puede imponer un pedido total en cualquier DAG (ya que cualquier DAG también representa un pedido parcial), pero no puede convertir un DAG en un árbol. Esta es la teoría básica de grafos. Me interesaría ver su algoritmo para crear una representación en árbol de un DAG que luego podría mostrarse. Sin dicho algoritmo subyacente, cualquier herramienta que buscara mostrar las dependencias como un árbol sería necesariamente hacky y propensa a errores.
Comodín
Tal vez no fui lo suficientemente explícito nuevamente, pero pensé que los ejemplos que doy en Similar lo dejaron claro. No estoy interesado en la teoría de grafos (al menos en esta pregunta). Todo lo que quiero para esto es una representación visual que se parezca a un árbol (especialmente si se debe mostrar en un terminal, porque los dotgráficos de orden obviamente están bien). Actualizaré la pregunta un poco para aclararla (espero).
Lucas
2
RANT: Sinceramente, estoy un poco frustrado de que la marca no ofrezca algo como esto fuera de la caja. Make es uno de los sistemas de construcción más extendidos en el mundo, y esta característica sería tan inmensamente útil que es difícil de comprender que durante el día de Dios sabe cuántas décadas ha existido esa marca, nadie agregó esa característica. Enviar esta información en un formato de texto claramente definido sería totalmente suficiente. Entiendo que make es de código abierto y siempre podría agregar esta característica yo mismo. Y créeme, si make no fuera básicamente una caja negra para mí, ¡lo haría! Despotricar sobre.
antred

Respuestas:

10

Intente makefile2graph del mismo autor, hay una herramienta similar MakeGraphDependencies escrita en javalugar de c.

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

Luego use un editor de gráficos vectoriales para resaltar las conexiones que necesita.

xae
fuente
1
He probado esa herramienta. Ni siquiera comienza a funcionar (al menos no para ninguna de las encarnaciones con las que lo probé). La mayoría de las veces simplemente se expulsa con alguna violación de acceso a la memoria.
antred
3

He encontrado un tipo de pirateo para al menos generar información claramente estructurada sobre qué objetivo depende de qué requisitos previos. La desventaja es que es bastante intrusiva. En otras palabras, debe cambiar su archivo MAKE para ajustar las recetas de compilación de todos sus objetivos en una pequeña función condicional. Publicaré un breve ejemplo:

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

En este ejemplo, estoy usando la función getRecipe enrollada a mano para envolver la receta de cada objetivo individual y luego decidir si ejecutar esa receta o simplemente generar qué objetivo se está construyendo y de qué requisitos previos depende. Esto último ocurre solo si DEPENDENCY_GRAPHse establece la variable (por ejemplo, como una variable de entorno). En el ejemplo, la receta de construcción no es más que un eco que dice que el objetivo se está construyendo, pero obviamente podría reemplazarlo con un comando de su elección.

Con el DEPENDENCY_GRAPHconjunto a 1, esto da como resultado la salida:

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"

que debería ser lo suficientemente fácil de analizar y luego convertir en un gráfico de puntos.

Con DEPENDENCY_GRAPHno establecido en absoluto o establecido en 0, la salida es:

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

o, en otras palabras, se usa la receta de compilación normal. Todavía no he probado si esto funciona de manera confiable con recetas complicadas. Un problema con el que ya me he encontrado es que no funciona en absoluto con recetas de varias líneas.

Por ejemplo, en la receta de compilación del último objetivo, si además de decir que se está construyendo el objetivo, realmente quería touchel archivo:

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

makeparece pensar que la touch $@parte es simplemente parte del eco en la línea anterior:

Building target foobar.txt touch foobar.txt

Si dejo de lado la barra diagonal inversa de la línea anterior, la makequeja se *** unterminated call to functionllama ': falta. )'. Stop.Si alguien tiene una idea de cómo makejugar bien, soy todo oídos. :)

EDITAR: El otro problema con este enfoque es que esto solo funcionará si no existen resultados de compilación, ya que makeobviamente no ejecuta la receta de compilación de un objetivo que considera actualizado.

antred
fuente
agregar ;después de que target $@el comando táctil funcione
mug896
para el segundo problema, use la make -Bopción que crea incondicionalmente todos los objetivos.
mug896
2

Utilicé remake --profile (un reemplazo directo para make), generó un árbol de dependencia en un formato callgrind.

Entonces gprof2dot puede generar una imagen del árbol de destino.

Victor Sergienko
fuente
¿Entiendo que la documentación es incorrecta o remake --profilesolo muestra el gráfico de dependencia para el destino que ejecuta? ¿O puede de alguna manera generar el gráfico para todos los objetivos?
Lucas
Solo el que corre, me temo. Pero se puede ejecutar a todos con -dry-run
Victor Sergienko
Oh sí, algo así remake --targets -r | grep -v %| grep -v '\t*\.'|xargs remake -n --profile -Bparece prometedor.
Lucas