Jak wyświetlić zależności podane w makefile jako drzewo?


18

Problem

Chcę zobaczyć zależności dla jednego lub większej liczby celów makefile. Szukam więc programu, który może analizować pliki makefile, a następnie będzie reprezentować zależności w jakimś drzewiastym formacie (wcięcie, ascii-art, ...) lub jako wykres (kropka, ...).

Podobny

Istnieją programy, które robią to w innych sytuacjach:

  • pactree lub dług może wyświetlać zależności dla pakietów oprogramowania w odpowiednim formacie w drzewie jak format ascii lub jako dotwykres,
  • gcc -M source_file.c wyświetla zależności pliku źródłowego C jako regułę make,
  • pstree wyświetla ascii reprezentację drzewa procesów.

Postęp

Przeszukując Internet, znalazłem niewielką pomoc . To skłoniło mnie do spróbowania

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

ale wygląda na to, że muszę zhakować trochę więcej parsującego kodu w Perlu lub Pythonie, aby przedstawić to jako ładne drzewo / wykres. I nie wiem jeszcze, czy naprawdę w ten sposób uzyskam pełny i poprawny wykres.

Wymagania

Byłoby miło ograniczyć wykres w pewien sposób (brak wbudowanej reguły, tylko dany cel, tylko pewna głębokość), ale w przeważającej części szukam tylko narzędzia, które da mi zależności w pewnym „rozsądnym” ludzkim sensie -widoczny format (jak programy w „Podobne” zrobić).

pytania

  • Czy są jakieś programy, które mogą to zrobić?
  • Czy otrzymam pełne i prawidłowe informacje make -dnq ...?
  • Czy istnieje lepszy sposób na uzyskanie tych informacji?
  • Czy skrypty / próby analizy tych informacji już istnieją?

1
Kluczową rzeczą do zrozumienia tutaj jest: Zależności NIE tworzą drzewa. Tworzą one ukierunkowany i (miejmy nadzieję) acykliczny wykres - znany również jako DAG . Spróbuj naszkicować wykres zależności dla następujących elementów, a zobaczysz: A zależy od B; A zależy również od C; B zależy od D; C zależy od D.
Wildcard

@Wildcard Wiem, ale dla moich celów wystarczy przedstawić zależności jako drzewo. Nie mam nic przeciwko powielaniu podrozdziałów (i wycinaniu kół), aby zrobić z niego drzewo. Przepraszamy za brak jednoznaczności. Dla ciebie przykład byłbym w porządku z wyjściem printf 'A\n B\n D\n C\n D\n'. (Kto powiedział, że nie mogę wstawiać nowych wierszy w komentarzach? :)
Lucas

Jak można by to odróżnić od „A zależy od B; B zależy od D; D zależy od C; A zależy od D”? Możesz nałożyć całkowite uporządkowanie na dowolny DAG (ponieważ każdy DAG stanowi również częściowe uporządkowanie), ale nie możesz zamienić DAG w drzewo. To podstawowa teoria grafów. Byłbym zainteresowany, aby zobaczyć twój algorytm tworzenia reprezentacji drzewa DAG, który mógłby następnie zostać wyświetlony. Bez takiego bazowego algorytmu każde narzędzie, które dąży do wyświetlenia zależności jako drzewa, z konieczności byłoby niezwykle hackerskie i podatne na błędy.
Wildcard

Może znów nie byłem wystarczająco wyraźny, ale pomyślałem, że przykłady, które podałem w sekcji Podobne , jasno to wyjaśniły. Nie interesuje mnie teoria grafów (przynajmniej w tym pytaniu). Wszystko, czego chcę, to wizualna reprezentacja, która wygląda podobnie do drzewa (zwłaszcza jeśli powinna być wyświetlana na terminalu, ponieważ dotwykresy zamówień są oczywiście w porządku.) Zaktualizuję to pytanie nieco, aby było jaśniejsze (mam nadzieję).
Lucas

2
RANT: Szczerze mówiąc, jestem trochę sfrustrowany, że make nie oferuje czegoś takiego po wyjęciu z pudełka. Marka jest jednym z najbardziej rozpowszechnionych systemów kompilacji na świecie, a ta funkcja byłaby tak niezwykle przydatna, że ​​trudno jest pojąć, że w ciągu Boga wie, ile dziesięcioleci istnienia istniało, nikt nie dodał takiej cechy. Przekazanie tych informacji w jasno określonym formacie tekstowym byłoby całkowicie wystarczające. Rozumiem, że marka jest oprogramowaniem typu open source i zawsze mogłem osobiście dodać tę funkcję. I uwierzcie mi, gdyby marka nie była dla mnie zasadniczo czarną skrzynką, zrobiłbym to! RANT ponad.
antred 27.07.17

Odpowiedzi:


10

Spróbuj makefile2graph od tego samego autora, zamiast tego jest napisane podobne narzędzie MakeGraphDependencies .javac

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

Następnie użyj edytora grafiki wektorowej, aby podświetlić potrzebne połączenia.


1
Wypróbowałem to narzędzie. Nawet nie zaczyna działać (przynajmniej nie dla żadnego z wcieleń, z którymi próbowałem). W większości przypadków po prostu kończy się z pewnym naruszeniem dostępu do pamięci.
antred 27.07.17

3

Znalazłem rodzaj włamania, aby przynajmniej uzyskać jasno skonstruowane informacje o tym, który cel zależy od wymagań wstępnych. Minusem jest to, że jest dość nachalne. Innymi słowy, musisz zmienić swój plik makefile, aby zawrzeć receptury kompilacji wszystkich celów w małą funkcję warunkową. Podam krótki przykład:

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

W tym przykładzie używam ręcznie zwiniętej funkcji getRecipe, aby zawinąć recepturę każdego celu, a następnie zdecydować, czy faktycznie uruchomić ten przepis, czy po prostu wypisać, który cel jest budowany i od których warunków zależy. To drugie dzieje się tylko wtedy, gdy zmienna DEPENDENCY_GRAPHjest ustawiona (np. Jako zmienna środowiskowa). W tym przykładzie przepis na kompilację jest niczym więcej niż echem mówiącym, że budowany jest cel, ale można oczywiście zastąpić to poleceniem według własnego wyboru.

Przy DEPENDENCY_GRAPHustawieniu na 1 daje to wynik:

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"

które powinno być wystarczająco łatwe do przeanalizowania, a następnie przekształcenia w wykres punktowy.

Jeśli DEPENDENCY_GRAPHnie jest ustawiony wcale lub ustawiony na 0, wynikiem jest:

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

lub innymi słowy, zamiast tego używana jest normalna receptura kompilacji. Nie testowałem jeszcze, czy działa to niezawodnie ze skomplikowanymi przepisami. Jednym z problemów, na które już natknąłem się, jest to, że w ogóle nie działa z recepturami wieloliniowymi.

Na przykład w przepisie kompilacji ostatniego celu, jeśli oprócz stwierdzenia, że ​​cel jest budowany, naprawdę chciałem do touchpliku:

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

makewydaje się myśleć, że ta touch $@część jest jedynie częścią echa w poprzedniej linii:

Building target foobar.txt touch foobar.txt

Jeśli zostawiam ostatni odwrotny ukośnik w poprzedniej linii, makenarzeka na *** unterminated call to functionwezwanie: brak. )'. Stop.Jeśli ktoś ma pomysł, jak makegrać ładnie, jestem cały. :)

EDYCJA: Innym problemem związanym z tym podejściem jest to, że zadziała to tylko wtedy, gdy wyniki kompilacji już nie istnieją, ponieważ makeoczywiście nie wykonuje się przepisu kompilacji celu, który uważa za aktualny.


dodaj ;po target $@komendzie dotyku do pracy
mug896

w przypadku drugiego problemu użyj make -Bopcji, która bezwarunkowo czyni wszystkie cele.
mug896

2

Użyłem remake --profile (zamiennik drop-in make), wygenerowało drzewo zależności w formacie callgrind.

Następnie gprof2dot może wygenerować obraz drzewa docelowego.


Czy rozumiem, że dokumentacja jest nieprawidłowa, czy remake --profilewyświetla tylko wykres zależności dla wykonywanego celu? Czy może w jakiś sposób generuje wykres dla wszystkich celów?
Lucas

Obawiam się, że tylko ten działa. Ale możesz je wszystkie uruchomić z „suchym biegiem”
Victor Sergienko

O tak, coś w tym remake --targets -r | grep -v %| grep -v '\t*\.'|xargs remake -n --profile -Bwygląda obiecująco.
Lucas
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.