Bagaimana cara menampilkan dependensi yang diberikan dalam makefile sebagai pohon?

18

Masalah

Saya ingin melihat dependensi untuk satu atau lebih target makefile. Jadi saya mencari program yang dapat mem-parsing makefiles dan kemudian akan mewakili dependensi dalam beberapa format seperti pohon (indentasi, ascii-art, ...) atau sebagai grafik (titik, ...).

Serupa

Ada program yang melakukan ini untuk situasi lain:

  • pactree atau debtree dapat menampilkan dependensi untuk paket perangkat lunak dalam format masing-masing dalam pohon seperti format ascii atau sebagai dotgrafik,
  • gcc -M source_file.c menampilkan dependensi file sumber C sebagai aturan make,
  • pstree menampilkan representasi ascii dari pohon proses.

Kemajuan

Mencari di web saya menemukan sedikit bantuan . Itu membuat saya mencoba

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

tetapi sepertinya saya harus meretas beberapa kode parsing lebih dalam perl atau python untuk mewakili ini sebagai pohon / grafik yang bagus. Dan saya belum tahu apakah saya akan benar-benar mendapatkan grafik yang lengkap dan benar dengan cara ini.

Persyaratan

Akan lebih baik untuk membatasi grafik dalam beberapa cara (tidak ada aturan bawaan, hanya target yang diberikan, hanya beberapa kedalaman) tetapi untuk sebagian besar saya hanya mencari alat yang akan memberi saya dependensi dalam beberapa "masuk akal", manusia Format -viewable (seperti program di bawah "Mirip" lakukan).

Pertanyaan

  • Apakah ada program yang bisa melakukan ini?
  • Apakah saya akan mendapatkan informasi yang lengkap dan benar dari make -dnq ...?
  • Apakah ada cara yang lebih baik untuk mendapatkan info ini?
  • Apakah skrip / upaya untuk menguraikan informasi ini sudah ada?
Lucas
sumber
1
Hal penting untuk dipahami di sini adalah: Ketergantungan TIDAK membentuk pohon. Mereka membentuk grafik asiklik terarah dan (semoga!) — Juga dikenal sebagai DAG . Coba buat sketsa grafik dependensi untuk yang berikut dan Anda akan melihatnya: A tergantung pada B; A juga tergantung pada C; B tergantung pada D; C tergantung pada D.
Wildcard
@ Kartu Memori Saya tahu tetapi untuk tujuan saya itu sudah cukup untuk mewakili dependensi sebagai pohon. Saya baik-baik saja dengan menggandakan subgraph (dan memotong lingkaran) untuk membuatnya menjadi pohon. Maaf karena tidak eksplisit. Sebagai contoh Anda, saya akan baik-baik saja dengan output printf 'A\n B\n D\n C\n D\n'. (Siapa bilang saya tidak bisa memasukkan baris baru dalam komentar? :)
Lucas
Bagaimana itu dapat dibedakan dari "A tergantung pada B; B tergantung pada D; D tergantung pada C; A tergantung pada D"? Anda dapat memaksakan pemesanan total pada DAG mana pun (karena DAG mana pun juga mewakili pemesanan sebagian), tetapi Anda tidak dapat mengubah DAG menjadi pohon. Ini adalah teori grafik dasar. Saya akan tertarik untuk melihat algoritma Anda untuk membuat representasi pohon dari DAG yang kemudian dapat ditampilkan. Tanpa algoritme yang mendasari seperti itu, alat apa pun yang berusaha menampilkan dependensi sebagai sebuah pohon akan menjadi sangat rumit dan rentan kesalahan.
Wildcard
Mungkin saya tidak cukup eksplisit lagi tapi saya pikir contoh yang saya berikan di bawah Mirip membuatnya jelas. Saya tidak tertarik pada teori grafik (setidaknya dalam pertanyaan ini). Yang saya inginkan untuk ini adalah representasi visual yang terlihat mirip dengan pohon (terutama jika harus ditampilkan pada terminal, karena dotgrafik pesanan jelas baik-baik saja.) Saya akan memperbarui sedikit pertanyaan untuk membuatnya lebih jelas (saya harap).
Lucas
2
RANT: Saya sejujurnya sedikit frustrasi karena make tidak menawarkan sesuatu seperti ini. Make adalah salah satu sistem build paling luas di dunia, dan fitur ini akan sangat berguna sehingga sulit untuk dipahami bahwa selama Tuhan tahu berapa dekade yang telah ada tidak ada yang menambahkan fitur seperti itu. Mengeluarkan informasi ini dalam format teks yang jelas akan cukup memadai. Saya mengerti bahwa make adalah open source dan saya selalu dapat menambahkan fitur ini sendiri. Dan percayalah, jika make pada dasarnya bukan kotak hitam untuk saya, saya akan! BACAAN.
antred

Jawaban:

10

Coba makefile2graph dari penulis yang sama ada alat serupa MakeGraphDependencies yang ditulis javaalih-alih c.

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

Kemudian gunakan beberapa editor grafik vektor untuk menyorot koneksi yang Anda butuhkan.

xae
sumber
1
Saya sudah mencoba alat itu. Bahkan tidak mulai bekerja (setidaknya tidak untuk inkarnasi make apa pun yang saya coba). Sebagian besar waktu itu hanya dibuang dengan beberapa pelanggaran akses memori.
antred
3

Saya telah menemukan semacam peretasan untuk setidaknya menghasilkan informasi yang terstruktur dengan jelas tentang target yang bergantung pada prasyarat yang mana. Kelemahannya, itu cukup mengganggu. Dengan kata lain, Anda perlu mengubah makefile Anda untuk membungkus resep bangunan semua target Anda menjadi fungsi bersyarat kecil. Saya akan memposting contoh singkat:

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

Dalam contoh ini, saya menggunakan fungsi getRecipe linting tangan untuk membungkus masing-masing resep target individu dan kemudian memutuskan apakah akan benar-benar menjalankan resep itu atau hanya menampilkan target mana yang sedang dibangun dan prasyarat yang tergantung pada. Yang terakhir hanya terjadi jika variabel DEPENDENCY_GRAPHdiatur (misalnya sebagai variabel lingkungan). Pada contoh, resep build tidak lebih dari sebuah gema yang mengatakan bahwa target sedang dibangun, tetapi Anda dapat dengan jelas menggantinya dengan perintah pilihan Anda.

Dengan DEPENDENCY_GRAPHset ke 1, ini menghasilkan output:

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"

yang seharusnya cukup mudah untuk diuraikan dan kemudian dikonversi menjadi grafik-titik.

Dengan DEPENDENCY_GRAPHtidak disetel sama sekali atau set ke 0, outputnya adalah:

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

atau, dengan kata lain, resep build normal digunakan sebagai gantinya. Saya belum menguji apakah ini bisa diandalkan dengan resep yang rumit. Satu masalah yang sudah saya temui adalah bahwa itu tidak bekerja sama sekali dengan resep multi-line.

Misalnya, dalam resep build target terakhir, jika selain mengatakan bahwa target sedang dibangun, saya sebenarnya ingin ke touchfile:

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

maketampaknya berpikir bahwa touch $@bagian itu hanyalah bagian dari gema di baris sebelumnya:

Building target foobar.txt touch foobar.txt

Jika saya meninggalkan backslash tertinggal di baris sebelumnya, makemengeluh *** unterminated call to functionpanggilan ': hilang )'. Stop.Jika ada yang punya ide bagaimana bisa makebermain bagus, saya semua telinga. :)

EDIT: Masalah lain dengan pendekatan ini adalah bahwa ini hanya akan berfungsi jika tidak ada hasil build yang sudah ada, karena makejelas tidak menjalankan resep build dari target yang dianggap up-to-date.

antred
sumber
tambahkan ;setelah target $@perintah sentuh berfungsi
mug896
untuk masalah kedua, gunakan make -Bopsi yang tanpa syarat membuat semua target.
mug896
2

Saya menggunakan remake --profile (pengganti drop-in untuk make), itu menghasilkan pohon dependensi dalam format callgrind.

Kemudian gprof2dot dapat menghasilkan gambar dari pohon target.

Victor Sergienko
sumber
Apakah saya memahami dokumentasi yang salah atau remake --profilehanya menampilkan grafik ketergantungan untuk target yang dijalankannya? Atau bisakah itu entah bagaimana menampilkan grafik untuk semua target?
Lucas
Hanya yang berjalan, aku takut. Tapi Anda bisa menjalankan semuanya dengan — lari kering
Victor Sergienko
Oh ya, sesuatu seperti remake --targets -r | grep -v %| grep -v '\t*\.'|xargs remake -n --profile -Bterlihat menjanjikan.
Lucas