Problema

Problema

Problema

Quero ver as dependências de um ou mais alvos de um makefile. Então, estou procurando um programa que possa analisar makefiles e então representar as dependências em algum formato semelhante a uma árvore (recuo, arte ascii, ...) ou como um gráfico (ponto, ...).

Semelhante

Existem programas que fazem isso para outras situações:

  • pactreeouárvore de dívidapode exibir as dependências dos pacotes de software no respectivo formato em uma árvore como formato ascii ou como um dotgráfico,
  • gcc -M source_file.cexibe as dependências do arquivo de origem C como uma regra make,
  • pstreeexibe uma representação ascii da árvore de processos.

Progresso

Pesquisando na web eu encontreipequena ajuda. Isso me levou a tentar

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

mas parece que preciso hackear mais algum código de análise em perl ou python para representar isso como uma bela árvore/gráfico. E ainda não sei se realmente conseguirei o gráfico completo e correto desta forma.

Requisitos

Seria bom limitar o gráfico de algumas maneiras (sem regra interna, apenas um determinado alvo, apenas alguma profundidade), mas na maioria das vezes estou apenas procurando uma ferramenta que me forneça as dependências de alguma forma humana "razoável". -formato visualizável (como fazem os programas em "Similar").

Questões

  • Existem programas que podem fazer isso?
  • Receberei as informações completas e corretas de make -dnq ...?
  • Existe uma maneira melhor de obter essas informações?
  • Já existem scripts/tentativas de analisar essas informações?

Responder1

Tentarmakefile2graphdo mesmo autor existe uma ferramenta semelhanteMakeGraphDependenciesescrito em javavez de c.

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

Em seguida, use algum editor de gráficos vetoriais para destacar as conexões necessárias.

Responder2

eu useirefazer --profile(um substituto imediato para make), gerou uma árvore de dependências em formato callgrind.

Entãogprof2dotpode gerar uma imagem da árvore de destino.

Responder3

Eu encontrei uma espécie de hack para, pelo menos, produzir informações claramente estruturadas sobre qual alvo depende de quais pré-requisitos. A desvantagem é que é bastante intrusivo. Em outras palavras, você precisa alterar seu makefile para agrupar as receitas de construção de todos os seus alvos em uma pequena função condicional. Vou postar um breve exemplo:

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

Neste exemplo, estou usando a função getRecipe enrolada manualmente para agrupar a receita de cada destino individual e, em seguida, decidir se realmente executarei essa receita ou simplesmente exibirei qual destino está sendo construído e de quais pré-requisitos ele depende. O último acontece apenas se a variável DEPENDENCY_GRAPHestiver definida (por exemplo, como uma variável de ambiente). No exemplo, a receita de construção nada mais é do que um eco dizendo que o alvo está sendo construído, mas você poderia obviamente substituir isso por um comando de sua escolha.

Com DEPENDENCY_GRAPHdefinido como 1, isso resulta na saída:

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 deve ser fácil de analisar e depois converter em um gráfico de pontos.

Com DEPENDENCY_GRAPHnão definido ou definido como 0, a saída é:

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

ou, em outras palavras, a receita de construção normal é usada. Ainda não testei se isso funciona de maneira confiável com receitas complicadas. Um problema que já encontrei é que não funciona com receitas de várias linhas.

Por exemplo, na receita de construção do último alvo, se além de dizer que o alvo está sendo construído eu realmente quisesse toucho arquivo:

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

makeparece pensar que a touch $@parte é apenas parte do eco da linha anterior:

Building target foobar.txt touch foobar.txt

Se eu deixar de fora a barra invertida na linha anterior, makereclama, *** unterminated call to functionchame': faltando )'. Stop.Se alguém tiver uma idéia de como makejogar bem, sou todo ouvidos. :)

EDIT: O outro problema com esta abordagem é que isso só funcionará se ainda não existirem resultados de construção, pois makeobviamente não executa a receita de construção de um destino que considera atualizado.

Responder4

Se você precisar apenas listar as dependências do destino específico, poderá usar o seguinte comando:

make -dn MAKE=: you_target | sed -rn "s/^ *Considering target file '(.*)'\.$/\1/p"

MAKE=:é para não correr criançafaz.

Infelizmente, os Makefiles incluídos também estão listados. Você podefiltrá-losusando o seguinte script de shell ( 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"

Agora você pode listar todas as dependências do destino usando este comando:

list-deps MAKE=: your_target

Se você precisar listar apenas as dependências que precisam ser refeitas, consulteesta resposta.

Editar: para outras pessoas que encontrarem esta resposta - você pode preservar o recuo usando

make -dn MAKE=: you_target | sed -rn "s/^(\s+)Considering target file '(.*)'\.$/\1\2/p"

Você também pode tornar isso um alvo no Makefile:

.PHONY: graph 
graph: 
    make -dn MAKE=: all | sed -rn "s/^(\s+)Considering target file '(.*)'\.$/\1\2/p" 

informação relacionada