Eu encontrei uma espécie de hack para, pelo menos, gerar informações claramente estruturadas sobre qual alvo depende de quais pré-requisitos. A desvantagem é que é bastante intrusiva. Em outras palavras, você precisa alterar seu makefile para agrupar as receitas de compilaçã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 à mão para agrupar a receita de cada destino individual e, em seguida, decidir se a receita realmente será executada ou se simplesmente a saída está sendo criada e quais pré-requisitos ela depende. O último acontece apenas se a variável DEPENDENCY_GRAPH
estiver 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_GRAPH
definido 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 o suficiente para analisar e depois converter em um gráfico de pontos.
Com DEPENDENCY_GRAPH
nã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 compilação normal é usada em seu lugar. Eu ainda não testei se isso funciona de forma confiável com receitas complicadas. Um problema que já enfrentei é que ele não funciona com receitas de várias linhas.
Por exemplo, na receita de compilação do último destino, se além de dizer que o alvo está sendo construído, eu realmente queria touch
o arquivo:
$(VARIABLE_TARGET_NAME) :
$(call getRecipe,\
@echo Building target $@\
touch $@)
make
parece achar que a parte touch $@
é meramente parte do eco da linha anterior:
Building target foobar.txt touch foobar.txt
Se eu deixar a barra invertida na linha anterior, make
reclama *** unterminated call to function
call ': falta )'. Stop.
Se alguém tiver uma ideia de como fazer com que make
seja legal, sou todo ouvidos. :)
EDIT: O outro problema com essa abordagem é que isso só funcionará se nenhum resultado de compilação já existir, já que make
obviamente não executa a receita de compilação de um destino que considera atualizado.