Bagaimana Anda mendapatkan daftar target di makefile?


202

Saya telah menggunakan rake sedikit (program Ruby make), dan ia memiliki opsi untuk mendapatkan daftar semua target yang tersedia, misalnya

> rake --tasks
rake db:charset      # retrieve the charset for your data...
rake db:collation    # retrieve the collation for your da...
rake db:create       # Creates the databases defined in y...
rake db:drop         # Drops the database for your curren...
...

tetapi sepertinya tidak ada pilihan untuk melakukan ini di GNU make.

Tampaknya kode itu hampir ada untuk itu, pada 2007 - http://www.mail-archive.com/help-make@gnu.org/msg06434.html .

Lagi pula, saya membuat sedikit hack untuk mengekstrak target dari makefile, yang dapat Anda sertakan dalam makefile.

list:
    @grep '^[^#[:space:]].*:' Makefile

Ini akan memberi Anda daftar target yang ditentukan. Ini hanya permulaan - misalnya, tidak menyaring dependensi.

> make list
list:
copy:
run:
plot:
turnin:

2
Saya dengan cepat membaca jawaban, yang menarik, tetapi sejauh ini untuk diri saya sendiri saya lebih memilih untuk membuatnya tetap polos, sederhana, dan portabel menggunakan alias (dalam .bashrc saya): alias makefile-targets='grep "^[^#[:space:]].*:" Makefile' Paling sering saya hanya perlu memeriksa makefile saat ini, dan penyelesaian bash meluas alias saya.
RockyRoad


4
Apakah itu terlalu sepele: grep : Makefile?
cibercitizen1

Jawaban:


130

Ini adalah upaya untuk meningkatkan pendekatan hebat @ nobar sebagai berikut:

  • menggunakan perintah yang lebih kuat untuk mengekstrak nama target, yang diharapkan mencegah kesalahan positif (dan juga menghilangkan yang tidak perlu sh -c)
  • tidak selalu menargetkan makefile di direktori saat ini ; menghormati makefiles secara eksplisit ditentukan dengan-f <file>
  • mengecualikan target tersembunyi - berdasarkan konvensi, ini adalah target yang namanya tidak dimulai dengan huruf atau angka
  • lakukan dengan target palsu tunggal
  • awalan perintah dengan @untuk mencegahnya digaungkan sebelum eksekusi

Anehnya, GNU maketidak memiliki fitur untuk daftar hanya nama-nama target yang ditentukan dalam makefile. The -ppilihan menghasilkan output yang mencakup semua target, tapi mengubur mereka dalam banyak informasi lainnya.

Tempatkan aturan berikut dalam makefile untuk GNU makeuntuk mengimplementasikan target bernama listyang hanya daftar semua nama target dalam urutan abjad - yaitu: dipanggil sebagaimake list :

.PHONY: list
list:
    @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$'

Penting : Saat menempel ini, pastikan baris terakhir diindentasi oleh 1 karakter tab yang sebenarnya. (spasi tidak berfungsi) .

Perhatikan bahwa menyortir daftar target yang dihasilkan adalah pilihan terbaik, karena tidak menyortir tidak menghasilkan pemesanan yang membantu dalam urutan di mana target muncul di makefile tidak dipertahankan.
Juga, sub-target aturan yang terdiri dari beberapa target selalu dihasilkan secara terpisah dan karenanya, karena penyortiran, biasanya tidak muncul bersebelahan; misalnya, aturan yang dimulai dengan tidaka z: akan memiliki target dan terdaftar di samping satu sama lain di output, jika ada target tambahan.az

Penjelasan aturan :

  • .PHONY: list
    • mendeklarasikan daftar target target palsu, yaitu, yang tidak merujuk ke file , yang karenanya resepnya harus dipanggil tanpa syarat
  • $(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null

    • Meminta makelagi untuk mencetak dan mem-parsing basis data yang berasal dari makefile:
      • -p mencetak database
      • -Rr menekan dimasukkannya aturan dan variabel bawaan
      • -qhanya menguji status terkini dari target (tanpa membuat ulang apa pun), tetapi itu dengan sendirinya tidak mencegah pelaksanaan perintah resep dalam semua kasus; karenanya:
      • -f $(lastword $(MAKEFILE_LIST))memastikan bahwa makefile yang sama ditargetkan seperti dalam doa asli, terlepas dari apakah itu ditargetkan secara implisit atau eksplisit -f ....
        Peringatan : Ini akan rusak jika makefile Anda berisi includearahan; ke alamat ini, mendefinisikan variabel THIS_FILE := $(lastword $(MAKEFILE_LIST)) sebelum setiap includearahan dan menggunakan -f $(THIS_FILE)sebagai gantinya.
      • :adalah target yang sengaja tidak valid yang dimaksudkan untuk memastikan bahwa tidak ada perintah yang dijalankan ; 2>/dev/nullmenekan pesan kesalahan yang dihasilkan. Catatan: -pMeskipun demikian, ini bergantung pada pencetakan database, yang merupakan kasus pada GNU make 3.82. Sayangnya, GNU tidak menawarkan opsi langsung untuk hanya mencetak database, tanpa juga menjalankan tugas default (atau diberikan); jika Anda tidak perlu menargetkan Makefile tertentu, Anda dapat menggunakan make -p -f/dev/null, seperti yang direkomendasikan di manhalaman.
  • -v RS=

    • Ini adalah idiom awk yang memecah input menjadi blok-baris baris non-kosong yang bersebelahan.
  • /^# File/,/^# Finished Make data base/
    • Mencocokkan rentang garis dalam output yang berisi semua target (berlaku pada GNU make 3.82) - dengan membatasi penguraian pada rentang ini, tidak perlu berurusan dengan false positive dari bagian output lainnya.
  • if ($$1 !~ "^[#.]")
    • Secara selektif mengabaikan blok:
      • # ... mengabaikan non-target, yang bloknya dimulai dengan # Not a target:
      • . ... mengabaikan target khusus
    • Semua blok lain masing-masing harus dimulai dengan garis yang hanya berisi nama target yang didefinisikan secara eksplisit diikuti oleh :
  • egrep -v -e '^[^[:alnum:]]' -e '^$@$$' menghapus target yang tidak diinginkan dari output:
    • '^[^[:alnum:]]'... mengecualikan target tersembunyi , yang - berdasarkan konvensi - adalah target yang tidak dimulai dengan huruf atau angka.
    • '^$@$$'... tidak termasuk listtarget itu sendiri

Berlari make listkemudian mencetak semua target, masing-masing pada barisnya sendiri; Anda dapat xargsmengirim ke untuk membuat daftar yang dipisahkan oleh ruang.


Namun, ini adalah jawaban yang bagus, bagaimana saya bisa mendapatkan deskripsi untuk setiap tugas? Saat ini, saya menyimpannya sebagai komentar di atas definisi tugas. Tidak yakin apakah mungkin untuk memasukkannya dalam daftar dengan cara yang sama seperti rake --tasksitu?
Piotr Kuczynski

1
@PiotrKuczynski: Pertanyaan yang menarik, tapi saya sarankan Anda mempostingnya sebagai pertanyaan baru (menunjuk ke yang ini untuk referensi).
mklement0

"Sayangnya, GNU tidak menawarkan opsi langsung untuk hanya mencetak basis data." Ada -npilihan.
Bulletmagnet

@Bulletmagnet: Tujuan dari -n opsi ini adalah untuk "Mencetak perintah yang akan dieksekusi ..." - dengan kata lain: fitur dry-run. Juga tidak bahwa kutipan Anda hilang italicization kata hanya : make -pdengan sendirinya tidak mencetak database, tapi selalu juga menjalankan tugas bawaan ; manual merekomendasikan orang yang kikuk make -p -f/dev/nulluntuk menghindari itu.
mklement0

1
Juga akan mencantumkan target .PHONY, jadi pastikan Anda tidak memiliki.PHONY: *
tekumara

189

Di bawah Bash (setidaknya), ini dapat dilakukan secara otomatis dengan penyelesaian tab:

make spacetabtab


1
Diuji: bash --version = 4.2.45 (1) -release. make --version = 3.81.
nobar

53
+1, tetapi perhatikan bahwa ini bukan fitur bash , tetapi tergantung pada platform Anda . Platform jatuh ke dalam tiga kategori: yang mana penyelesaian ini diinstal secara default (misalnya, Debian 7, Fedora 20), yang mana Anda dapat menginstalnya secara opsional (misalnya, Ubuntu 14, dengan . /etc/bash_completion), dan yang tidak mendukungnya sama sekali (mis. OSX 10.9)
mklement0

8
ini bekerja pada OS X 10.10 (tidak dengan bash tetapi dengan zsh).
Florian Oswald

4
Tip yang bagus tetapi juga membutuhkan bash-completionpaket. Ditemukan di Fedora, RHEL, Gentoo, dll.
NoelProf

4
Ini tidak bekerja dengan membuat program membuat target AFAICT, misalnya$(RUN_TARGETS): run-%: ...
Matthias

32

Ini jelas tidak akan berfungsi dalam banyak kasus, tetapi jika Anda Makefiledibuat oleh CMake, Anda mungkin dapat menjalankannya make help.

$ make help
The following are some of the valid targets for this Makefile:
... all (the default if no target is provided)
... clean
... depend
... install
etc

Apakah Anda memiliki opsi untuk mengaktifkan CMakeList Anda untuk mendapatkannya? Saya mendapat makefile yang dihasilkan oleh CMake dan saya tidak memiliki target bantuan semu yang tersedia
Xavier T.

Nggak. Pada OSX setidaknya dengan CMake baru-baru ini (saya sebenarnya menggunakan nightlies tapi saya percaya ketika saya menulis ini saya menggunakan 3.3), jalankan saja touch CMakeLists.txt && cmake . && make helpdan itu harus bekerja. Saya hanya bisa menebak Anda menggunakan cmake kuno, atau tidak menggunakan generator Unix Makefiles?
Timmmm

Saya menggunakan CMake 3.6.2 dengan generator unix di Windows. Saya akan menggali untuk mencari penjelasan karena sepertinya berguna.
Xavier T.

26

Saya menggabungkan dua jawaban ini: https://stackoverflow.com/a/9524878/86967 dan https://stackoverflow.com/a/7390874/86967 dan melakukan beberapa pelarian sehingga ini dapat digunakan dari dalam makefile.

.PHONY: no_targets__ list
no_targets__:
list:
    sh -c "$(MAKE) -p no_targets__ | awk -F':' '/^[a-zA-Z0-9][^\$$#\/\\t=]*:([^=]|$$)/ {split(\$$1,A,/ /);for(i in A)print A[i]}' | grep -v '__\$$' | sort"

.

$ make -s list
build
clean
default
distclean
doc
fresh
install
list
makefile ## this is kind of extraneous, but whatever...
run

10
Saya juga (baru-baru ini) menemukan bahwa penyelesaian tab di bawah Bash akan mencantumkan target yang tersedia.
Nobar

1
+1 untuk pendekatan yang hebat, tetapi beberapa perbaikan dapat dilakukan: (a) menentukan secara eksplisit sh -c "…"tidak diperlukan, karena itulah yang makesecara default digunakan untuk menjalankan perintah resep; (B) perintah yang Anda gunakan terlalu sederhana, menghasilkan positif palsu (seperti yang Anda catat); (C) jika Anda awalan perintah dengan @, itu tidak akan bergema ke stdout sebelum eksekusi, meniadakan kebutuhan untuk digunakan -spada permintaan.
mklement0

1
ada target make yang lebih sederhana yang bisa Anda tambahkan: list: cat Makefile | grep "^ [Az]" | awk '{print $$ 1}' | sed "s /: // g | sort"
thamster

2
Pendekatan kucing / sed gagal pada beberapa tingkatan. Itu tidak memperluas variabel, dan juga gagal mendaftar target yang merupakan hasil dari memasukkan file lain.
Troy Daniels

1
@ mklement0: Saya lebih suka menggunakan make -s(melalui alias Bash) daripada mengawali perintah di makefile dengan @. Ada beberapa kasus di mana @mungkin berguna, terutama sebagai awalan untuk echoperintah (di mana tampilan perintah akan berlebihan), tetapi secara umum saya tidak suka menggunakannya. Dengan cara ini, saya bisa melihat "resep" ketika saya perlu (dengan tidak menggunakan -s), tetapi tidak biasanya. Berikut dokumentasi terkait: GNU Make Manual, 5.2 Recipe Echoing .
nobar

14

Jika Anda memiliki penyelesaian bash untuk makediinstal, skrip penyelesaian akan menentukan suatu fungsi _make_target_extract_script. Fungsi ini dimaksudkan untuk membuat sedskrip yang dapat digunakan untuk mendapatkan target sebagai daftar.

Gunakan seperti ini:

# Make sure bash completion is enabled
source /etc/bash_completion 

# List targets from Makefile
sed -nrf <(_make_target_extract_script --) Makefile

3
Bermanfaat, tetapi perhatikan bahwa tidak semua platform memiliki skrip /etc/bash_completiondan / atau fungsi _make_target_extract_script- Anda tampaknya berada di Ubuntu> 12. Jika Anda menargetkan /usr/share/bash-completion/completions/makesebaliknya, pendekatan Anda akan bekerja pada platform tambahan, seperti Fedora 20. Ada (lebih tua) platform yang memiliki file ini, tetapi bukan fungsinya (misalnya, Debian 7 dan Ubuntu 12); platform lain, seperti OSX, sama sekali tidak dilengkapi tab make. Mungkin memposting definisi fungsi yang sebenarnya akan sangat membantu.
mklement0

1
Terima kasih atas komentar Anda. Ini sangat dihargai. Ya, saya sudah menguji ini di Ubuntu 14.04
hek2mgl

11

Sebagai ditunjukkan mklement0 , fitur untuk mendaftarkan semua target Makefile hilang dari GNU-make, dan jawabannya serta yang lain menyediakan cara untuk melakukan ini.

Namun, posting asli juga menyebutkan rake , yang tugasnya beralih melakukan sesuatu yang sedikit berbeda dari sekadar mendaftar semua tugas di rakefile. Rake hanya akan memberi Anda daftar tugas yang memiliki deskripsi terkait. Tugas tanpa deskripsi tidak akan dicantumkan . Ini memberi penulis kemampuan untuk memberikan deskripsi bantuan yang disesuaikan dan juga menghilangkan bantuan untuk target tertentu.

Jika Anda ingin meniru perilaku rake, di mana Anda memberikan deskripsi untuk setiap target , ada teknik sederhana untuk melakukan ini: embed deskripsi dalam komentar untuk setiap target yang ingin Anda daftarkan.

Anda dapat meletakkan deskripsi di sebelah target atau, seperti yang sering saya lakukan, di sebelah spesifikasi PHONY di atas target, seperti ini:

.PHONY: target1 # Target 1 help text
target1: deps
    [... target 1 build commands]

.PHONY: target2 # Target 2 help text
target2:
    [... target 2 build commands]

...                                                                                                         

.PHONY: help # Generate list of targets with descriptions                                                                
help:                                                                                                                    
    @grep '^.PHONY: .* #' Makefile | sed 's/\.PHONY: \(.*\) # \(.*\)/\1 \2/' | expand -t20

Yang akan menghasilkan

$ make help
target1             Target 1 help text
target2             Target 2 help text

...
help                Generate list of targets with descriptions

Anda juga dapat menemukan contoh kode pendek di intisari ini dan juga di sini .

Sekali lagi, ini tidak menyelesaikan masalah daftar semua target dalam Makefile. Misalnya, jika Anda memiliki Makefile besar yang mungkin dihasilkan atau yang ditulis orang lain, dan Anda ingin cara cepat untuk membuat daftar target tanpa menggali melalui itu, ini tidak akan membantu.

Namun, jika Anda menulis Makefile, dan Anda menginginkan cara untuk menghasilkan teks bantuan secara konsisten, cara mendokumentasikan diri sendiri, teknik ini mungkin berguna.


Ini adalah teknik yang hebat - bagus dan sederhana tetapi juga memberikan deskripsi!
Brian Burns

Teknik hebat. Saya memodifikasi ini sedikit menggunakan echoperintah sebagai deskripsi perintah ( stackoverflow.com/a/52059487/814145 ).
Penghe Geng

@PengheGeng Terima kasih untuk kirimannya. Saya ingin menjelaskan bahwa @echo "Target 1"ini hanyalah pengganti dan bukan "perintah deskripsi gema". Teks bantuan yang dihasilkan tidak berasal dari @echo's. Dalam Makefile asli, ini echoakan diganti dengan perintah build atau semacamnya. Saya akan mengedit posting untuk membuatnya lebih jelas.
jsp

5

Jawaban favorit saya untuk ini diposting oleh Chris Down di Unix & Linux Stack Exchange. Saya akan mengutip.

Ini adalah bagaimana modul penyelesaian bash untuk makemendapatkan daftarnya:

make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'

Ini mencetak daftar target yang dibatasi garis baru, tanpa paging.

Pengguna Brainstone menyarankan perpipaan sort -uuntuk menghapus entri duplikat:

make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}' | sort -u

Sumber: Bagaimana daftar semua target yang dibuat? (Unix & Linux SE)


4

Jawaban @ nobar sangat membantu menunjukkan bagaimana menggunakan penyelesaian tab untuk membuat daftar target makefile .

  • Ini berfungsi baik untuk platform yang menyediakan fungsi ini secara default (misalnya, Debian, Fedora ).

  • Pada platform lain (mis., Ubuntu ) Anda harus secara eksplisit memuat fungsi ini, seperti tersirat pada jawaban @ hek2mgl :

    • . /etc/bash_completion menginstal beberapa fungsi penyelesaian-tab, termasuk untuk make
    • Atau, untuk menginstal hanya penyelesaian tab untuk make:
      • . /usr/share/bash-completion/completions/make
  • Untuk platform yang sama sekali tidak menawarkan fungsi ini , seperti OSX , Anda dapat mengambil perintah berikut (diadaptasi dari sini ) untuk mengimplementasikannya:
_complete_make() { COMPREPLY=($(compgen -W "$(make -pRrq : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($1 !~ "^[#.]") {print $1}}' | egrep -v '^[^[:alnum:]]' | sort | xargs)" -- "${COMP_WORDS[$COMP_CWORD]}")); }
complete -F _complete_make make
  • Catatan: Ini tidak secanggih fungsi penyelesaian-tab yang datang dengan distribusi Linux: terutama, ia selalu menargetkan makefile di direktori saat ini , bahkan jika baris perintah menargetkan makefile berbeda dengan -f <file>.

4

Berfokus pada sintaks yang mudah untuk menggambarkan target make, dan memiliki output bersih, saya memilih pendekatan ini:

help:
    @grep -B1 -E "^[a-zA-Z0-9_-]+\:([^\=]|$$)" Makefile \
     | grep -v -- -- \
     | sed 'N;s/\n/###/' \
     | sed -n 's/^#: \(.*\)###\(.*\):.*/\2###\1/p' \
     | column -t  -s '###'


#: Starts the container stack
up: a b
  command

#: Pulls in new container images
pull: c d 
    another command

make-target-not-shown:

# this does not count as a description, so leaving
# your implementation comments alone, e.g TODOs
also-not-shown:

Jadi memperlakukan di atas sebagai Makefile dan menjalankannya memberi Anda sesuatu seperti

> make help
up          Starts the container stack
pull        Pulls in new container images

Penjelasan untuk rantai perintah:


Solusi yang sangat bagus Saya telah menggunakan ini selama beberapa tahun sekarang .: awk -F ':|##' '/^[^\t].+:.*##/ { printf "\033[36mmake %-28s\033[0m -%s\n", $$1, $$NF }' $(MAKEFILE_LIST) | sort dengan ##sebelum komentar pada baris yang sama dengan target. Tapi saya pikir solusi Anda memungkinkan sebelum dibaca.
thoroc

Makefile terdiri dari dua baris laporan pertama grep: parentheses not balancedpada mesin OSX 10.15 saya.
Malcolm Crum

@Rumy maaf, kesalahan saya. Terima kasih telah menunjukkannya. Memperbaikinya. make mengharuskan untuk keluar dari tanda dolar yang tidak seharusnya memulai nama variabel.
Richard Kiefer

Hati-hati, StackOverflow mengubah tab menjadi spasi ketika menampilkan bagian kode di atas, tetapi Makefiles memerlukan tab. Anda dapat mengedit posting dan kemudian menyalin bagian, sehingga tab dipertahankan.
Richard Kiefer

2

Banyak solusi yang bisa diterapkan di sini, tetapi seperti yang saya suka katakan, "jika perlu dilakukan sekali, itu layak dilakukan lagi." Saya melakukan upvote saran untuk menggunakan (tab) (tab), tetapi karena beberapa telah mencatat, Anda mungkin tidak memiliki dukungan penyelesaian, atau, jika Anda memiliki banyak file yang disertakan, Anda mungkin ingin cara yang lebih mudah untuk mengetahui di mana target didefinisikan.

Saya belum menguji di bawah ini dengan sub-merek ... Saya pikir itu tidak akan berhasil. Seperti yang kita ketahui, rekursif membuat dianggap berbahaya.

.PHONY: list ls
ls list :
    @# search all include files for targets.
    @# ... excluding special targets, and output dynamic rule definitions unresolved.
    @for inc in $(MAKEFILE_LIST); do \
    echo ' =' $$inc '= '; \
    grep -Eo '^[^\.#[:blank:]]+.*:.*' $$inc | grep -v ':=' | \
    cut -f 1 | sort | sed 's/.*/  &/' | sed -n 's/:.*$$//p' | \
    tr $$ \\\ | tr $(open_paren) % | tr $(close_paren) % \
; done

# to get around escaping limitations:
open_paren := \(
close_paren := \)

Yang saya suka karena:

  • daftar target dengan memasukkan file.
  • output definisi target dinamis dinamis (menggantikan pembatas variabel dengan modulo)
  • output setiap target pada baris baru
  • tampak lebih jelas (pendapat subyektif)

Penjelasan:

  • foreach file di MAKEFILE_LIST
  • Keluarkan nama file
  • garis grep yang mengandung tanda titik dua, yang bukan indentasi, bukan komentar, dan jangan mulai dengan tanda titik
  • kecualikan ekspresi penugasan langsung (: =)
  • memotong, mengurutkan, indentasi, dan memotong dependensi aturan (setelah titik dua)
  • pembatas variabel munge untuk mencegah ekspansi

Output sampel:

 = Makefile = 
  includes
  ls list
 = util/kiss/snapshots.mk = 
  rotate-db-snapshots
  rotate-file-snapshots
  snap-db
  snap-files
  snapshot
 = util/kiss/main.mk = 
  dirs
  install
   %MK_DIR_PREFIX%env-config.php
   %MK_DIR_PREFIX%../srdb

1

Yang ini membantu saya karena saya ingin melihat target yang dibutuhkan (dan ketergantungan mereka) oleh target make. Saya tahu bahwa membuat target tidak dapat dimulai dengan "." karakter. Saya tidak tahu bahasa apa yang didukung, jadi saya menggunakan ekspresi braket egrep.

cat Makefile | egrep "^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$"

1

Ini jauh dari bersih, tetapi berhasil, bagi saya.

make -p 2&>/dev/null | grep -A 100000 "# Files" | grep -v "^$" | grep -v "^\(\s\|#\|\.\)" | grep -v "Makefile:" | cut -d ":" -f 1

Saya menggunakan make -pdump database internal, gunakan stderr, gunakan yang cepat dan kotor grep -A 100000untuk menjaga bagian bawah output. Kemudian saya membersihkan output dengan beberapa grep -v, dan akhirnya menggunakancut untuk mendapatkan apa yang ada sebelum titik dua, yaitu target.

Ini cukup untuk skrip pembantu saya di sebagian besar Makefile saya.

EDIT: menambahkan grep -v Makefileitu adalah aturan internal


1

Ini adalah modifikasi dari jawaban jsp yang sangat membantu ( https://stackoverflow.com/a/45843594/814145 ). Saya suka ide untuk mendapatkan tidak hanya daftar target tetapi juga deskripsi mereka. Makefile jsp menempatkan deskripsi sebagai komentar, yang saya temukan sering akan diulang dalam perintah gema deskripsi target. Jadi sebagai gantinya, saya mengekstrak deskripsi dari perintah gema untuk setiap target.

Contoh Makefile:

.PHONY: all
all: build
        : "same as 'make build'"

.PHONY: build
build:
        @echo "Build the project"

.PHONY: clean
clean:
        @echo "Clean the project"

.PHONY: help
help:
        @echo -n "Common make targets"
        @echo ":"
        @cat Makefile | sed -n '/^\.PHONY: / h; /\(^\t@*echo\|^\t:\)/ {H; x; /PHONY/ s/.PHONY: \(.*\)\n.*"\(.*\)"/    make \1\t\2/p; d; x}'| sort -k2,2 |expand -t 20

Output dari make help:

$ make help
Common make targets:
    make all        same as 'make build'
    make build      Build the project
    make clean      Clean the project
    make help       Common make targets

Catatan:

  • Sama seperti jawaban jsp , hanya target PHONY yang dapat didaftar, yang mungkin atau mungkin tidak berfungsi untuk kasus Anda
  • Selain itu, hanya mencantumkan target PHONY yang memiliki perintah echoatau :sebagai perintah pertama resep.:berarti "tidak melakukan apa-apa". Saya menggunakannya di sini untuk target-target yang tidak memerlukan gema, seperti alltarget di atas.
  • Ada trik tambahan untuk helptarget untuk menambahkan ":" di make helpoutput.

0

Namun jawaban tambahan lain di atas.

diuji pada MacOSX hanya menggunakan cat dan awk di terminal

cat Makefile | awk '!/SHELL/ && /^[A-z]/ {print $1}' | awk '{print substr($0, 1, length($0)-1)}'

akan menampilkan file make seperti di bawah ini:

target1

target2

target3

di Makefile, haruslah pernyataan yang sama, pastikan Anda keluar dari variabel menggunakan variabel $ daripada variabel $.

Penjelasan

cat - meludahkan isinya

| - pipa mem-parsing output ke awk berikutnya

awk - menjalankan regex tidak termasuk "shell" dan hanya menerima baris "Az" kemudian mencetak kolom pertama $ 1

awk - lagi-lagi menghapus karakter terakhir ":" dari daftar

ini adalah output kasar dan Anda dapat melakukan lebih banyak hal yang funky hanya dengan AWK. Cobalah untuk menghindari sed karena itu tidak konsisten dalam varian BSD yaitu beberapa bekerja pada * nix tetapi gagal pada BSD seperti MacOSX.

Lebih

Anda harus dapat menambahkan ini (dengan modifikasi) ke file untuk make , ke folder bash-completion default /usr/local/etc/bash-completion.d/ yang berarti ketika Anda "membuat tab tab " .. itu akan menyelesaikan target berdasarkan pada skrip satu liner.


Anda juga bisa menggunakan make -qp daripada cat. jadi itu akan menjadi make -qp | awk '/: / &&! /: = / && / ^ [Az] / &&! / PATH / &&! / DISPLAY / &&! / TERM_SESSION / &&! / USER_TEXT_ENCODING / &&! / Makefile / {print substr ($ 0, 1 , panjang ($ 0) -1) | "sort -u"} '
Jimmy MG Lim

0

Saya biasanya melakukan:

grep install_targets Makefile

Itu akan kembali dengan sesuatu seperti:

install_targets = install-xxx1 install-xxx2 ... etc

saya harap ini membantu


0

Untuk Skrip Bash

Berikut adalah cara yang sangat sederhana untuk melakukan ini bash- berdasarkan komentar oleh @ cibercitizen1 di atas :

grep : Makefile | awk -F: '/^[^.]/ {print $1;}'

Lihat juga jawaban yang lebih otoritatif oleh @ Marc.2377, yang mengatakan bagaimana modul penyelesaian Bash makemelakukannya.


-4

tidak yakin mengapa jawaban sebelumnya sangat rumit:

list:
    cat Makefile | grep "^[A-z]" | awk '{print $$1}' | sed "s/://g" 

8
The jawaban sebelumnya begitu rumit, karena mencakup semua skenario bahwa jawaban Anda TIDAK meliputi: (a) masuknya target yang ditetapkan melalui variabel (misalnya, $(SHELLS): ...), (b) dimasukkannya target yang dimulai dengan digit, (c) non dimasukkannya definisi variabel , (d) menargetkan makefile yang tepat jika makeditentukan dengan jalur makefile eksplisit. (a) adalah kelemahan krusial: bahkan jika Anda dengan tepat menargetkan makefile yang tepat , mengurai file mentah tidak akan berfungsi dalam kasus umum, karena kurangnya ekspansi variabel.
mklement0

6
Sebagai samping, re rumit: perintah Anda dapat disederhanakan berikut ini - tetapi titik utama adalah bahwa hal itu tidak cukup kuat : awk -F: '/^[A-z]/ {print $$1}' Makefile. Akhirnya, sebagian besar poin akademis: menggunakan [A-z]daripada [:alpha:]berarti Anda akan kehilangan target yang dimulai dengan karakter asing seperti á.
mklement0

@ mklement0 perintah awk pertama Anda berfungsi dengan baik, dan sejauh ini adalah yang paling sederhana, meskipun menggunakan [: alpha:] tampaknya mematahkannya karena alasan tertentu - ia melewatkan beberapa target dalam file uji.
Brian Burns

@ bburns.km: Buruk saya: Saya seharusnya mengatakan [[:alpha:]]daripada [:alpha:]( [:alpha:]mewakili set huruf sadar-lokal di dalam kelas karakter ( [...]), maka kebutuhan yang efektif untuk double [[ / ]].
mklement0

4
Mengapa jawaban ini sangat rumit? Anda berhasil mengumpulkan beberapa dosa yang tidak berguna dalam cuplikan singkat ini. awk -F: '/^[A-Za-z]/ { print $$1 }' Makefilemenggunakan satu proses dan semoga ekspresi reguler yang lebih benar (meskipun Anda tentu saja dapat memiliki target dengan garis bawah, angka dll juga, seperti yang disebutkan dalam komentar sebelumnya).
tripleee
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.