Jak uzyskać listę celów w makefile?

202

Użyłem trochę prowizji (program do tworzenia Ruby) i ma opcję uzyskania listy wszystkich dostępnych celów, np.

> 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...
...

ale wydaje się, że nie ma takiej możliwości w GNU make.

Najwyraźniej kod jest już prawie gotowy, począwszy od 2007 r. - http://www.mail-archive.com/[email protected]/msg06434.html .

W każdym razie zrobiłem niewielki hack, aby wyodrębnić cele z makefile, który możesz dołączyć do makefile.

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

Daje ci listę zdefiniowanych celów. To tylko początek - na przykład nie filtruje zależności.

> make list
list:
copy:
run:
plot:
turnin:
Brian Burns
źródło
2
Szybko czytam odpowiedzi, które są interesujące, ale do tej pory wolę zachować prostotę, prostotę i przenośność za pomocą aliasu (w moim .bashrc): alias makefile-targets='grep "^[^#[:space:]].*:" Makefile' Najczęściej muszę tylko sprawdzić aktualny plik makefile, a uzupełnianie bash rozszerza się mój alias.
RockyRoad
4
Jest to zbyt trywialne tylko: grep : Makefile?
cibercitizen1

Odpowiedzi:

130

Jest to próba ulepszenia wspaniałego podejścia @ nobar w następujący sposób:

  • używa bardziej niezawodnej komendy do wyodrębnienia nazw docelowych, co, miejmy nadzieję, zapobiega wszelkim fałszywym trafieniom (a także eliminuje niepotrzebne sh -c)
  • niezmiennie nie celuje w plik makefile w bieżącym katalogu; szanuje makefile jawnie określone za pomocą-f <file>
  • wyklucza ukryte cele - zgodnie z konwencją są to cele, których nazwa nie zaczyna się od litery ani cyfry
  • wystarcza jeden fałszywy cel
  • @poprzedza polecenie znakiem, aby zapobiec jego powtórzeniu przed wykonaniem

Co ciekawe, GNU makenie ma funkcji wyświetlania tylko nazw celów zdefiniowanych w makefile. Ta -popcja generuje dane wyjściowe, które obejmują wszystkie cele, ale zakopuje je w wielu innych informacjach.

Umieść następującą regułę w pliku makefile dla GNU, makeaby zaimplementować nazwany cel, listktóry po prostu wyświetla wszystkie nazwy celów w kolejności alfabetycznej - tzn .: wywołaj jakomake 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 '^$@$$'

Ważne : po wklejeniu upewnij się, że ostatni wiersz jest wcięty dokładnie 1 rzeczywistym znakiem tabulacji. (spacje nie działają) .

Zauważ, że sortowanie wynikowej listy celów jest najlepszą opcją, ponieważ brak sortowania nie daje pomocnej kolejności, ponieważ kolejność pojawiania się celów w pliku makefile nie jest zachowana.
Również cele podrzędne reguły składającej się z wielu celów są niezmiennie wyprowadzane oddzielnie i dlatego, z powodu sortowania, zwykle nie pojawiają się obok siebie; np. reguła zaczynająca się od niea z: będzie miała celów i będzie wyświetlana obok siebie , jeśli są dodatkowe cele.az

Objaśnienie reguły :

  • .PHONY: list
    • deklaruje listę celów jako fałszywy cel, tzn. taki, który nie odwołuje się do pliku , który dlatego powinien zostać bezwarunkowo wywołany
  • $(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null

    • Wywołuje makeponownie, aby wydrukować i przeanalizować bazę danych pochodzącą z makefile:
      • -p drukuje bazę danych
      • -Rr pomija włączenie wbudowanych reguł i zmiennych
      • -qtestuje tylko aktualny status celu (bez przerabiania czegokolwiek), ale to samo w sobie nie uniemożliwia wykonania poleceń receptury we wszystkich przypadkach; W związku z tym:
      • -f $(lastword $(MAKEFILE_LIST))zapewnia, że ​​ten sam plik makefile jest kierowany jak w pierwotnym wywołaniu, niezależnie od tego, czy był on celowany pośrednio czy jawnie -f ....
        Zastrzeżenie : To się zepsuje, jeśli twój plik makefile zawiera includedyrektywy; aby rozwiązać ten problem, zdefiniuj zmienną THIS_FILE := $(lastword $(MAKEFILE_LIST)) przed wszelkimi includedyrektywami i użyj -f $(THIS_FILE)zamiast tego.
      • :jest celowo niepoprawnym celem, który ma zapewnić, że żadne polecenia nie zostaną wykonane ; 2>/dev/nullpomija wynikowy komunikat o błędzie. Uwaga: To jednak polega na -pwydrukowaniu bazy danych, co ma miejsce w przypadku GNU make 3.82. Niestety, GNU make oferty opcja nie do bezpośredniego prostu wydrukować bazę danych, bez również wykonanie domyślne (lub danego zadania); jeśli nie musisz kierować na konkretny plik Makefile, możesz użyć make -p -f/dev/null, zgodnie z zaleceniami na manstronie.
  • -v RS=

    • Jest to idiom awk, który dzieli dane wejściowe na bloki ciągłych niepustych linii.
  • /^# File/,/^# Finished Make data base/
    • Odpowiada zakresowi wierszy na wyjściu, które zawierają wszystkie cele (prawdziwe jak w GNU make 3.82) - ograniczając parsowanie do tego zakresu, nie ma potrzeby radzenia sobie z fałszywymi dodatnimi z innych sekcji wyjściowych.
  • if ($$1 !~ "^[#.]")
    • Selektywnie ignoruje bloki:
      • # ... ignoruje nie-cele, których bloki zaczynają się od # Not a target:
      • . ... ignoruje specjalne cele
    • Wszystkie pozostałe bloki powinny zaczynać się od wiersza zawierającego tylko nazwę wyraźnie określonego celu, po którym następuje :
  • egrep -v -e '^[^[:alnum:]]' -e '^$@$$' usuwa niechciane cele z danych wyjściowych:
    • '^[^[:alnum:]]'... wyklucza ukryte cele, które - zgodnie z konwencją - to cele, które nie zaczynają się od litery ani cyfry.
    • '^$@$$'... wyklucza listsam cel

Uruchomione make listnastępnie drukuje wszystkie cele, każdy na osobnej linii; możesz potokować, aby xargszamiast tego utworzyć listę oddzieloną spacjami.

mklement0
źródło
To świetna odpowiedź, jednak jak uzyskać opis każdego zadania? Obecnie przechowuję go jako komentarz nad definicją zadania. Nie jesteś pewien, czy możliwe jest umieszczenie go na liście w podobny sposób jak rake --taskson?
Piotr Kuczyński
1
@PiotrKuczynski: Interesujące pytanie, ale sugeruję, abyś zamieścił je jako nowe pytanie (wskazując na to w celach informacyjnych).
mklement0
„Niestety, GNU sprawia, że ​​nie ma bezpośredniej opcji drukowania bazy danych”. Istnieje -nopcja.
Bulletmagnet
@Bulletmagnet: Celem tej -nopcji jest „Wydrukowanie poleceń, które zostaną wykonane ...” - innymi słowy: funkcja suchobiegu. Też nie, że Twój cytat brakuje italicization słowa tylko : make -pprzez sam robi wydrukować bazę danych, ale niezmiennie prowadzi również zadanie domyślnej ; instrukcja zaleca niezręczny, make -p -f/dev/nullaby tego uniknąć.
mklement0
1
Wymienione zostaną również wszystkie cele .PHONY, więc upewnij się, że ich nie masz.PHONY: *
tekumara,
189

W Bash (przynajmniej) można to zrobić automatycznie po uzupełnieniu tabulatora:

make spacetabtab

nobar
źródło
1
Testowane: wersja bash - wersja = 4.2.45 (1). make --version = 3,81.
nobar
53
+1, ale pamiętaj, że nie jest to funkcja bash , ale zależy od twojej platformy . Platformy dzielą się na trzy kategorie: te, w których to uzupełnienie jest instalowane domyślnie (np. Debian 7, Fedora 20), te, w których można je opcjonalnie zainstalować (np. Ubuntu 14, z . /etc/bash_completion) i te, które w ogóle go nie obsługują (np. OSX 10.9)
mklement0
8
działa na OS X 10.10 (nie z bash, ale z zsh).
Florian Oswald,
4
Świetna wskazówka, ale potrzebuje również bash-completionpakietu. Znaleziono w Fedorze, RHEL, Gentoo, itp.
NoelProf,
4
Nie działa to z programowo utworzonymi celami make AFAICT, np.$(RUN_TARGETS): run-%: ...
Matthias
31

To oczywiście nie zadziała w wielu przypadkach, ale jeśli Makefilezostał stworzony przez CMake, możesz być w stanie uruchomić 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
Timmmm
źródło
Czy masz opcję włączenia CMakeList, aby to uzyskać? Mam plik makefile wygenerowany przez CMake i nie mam dostępnego pseudo celu
Xavier T.
Nie. Na OSX przynajmniej z najnowszym CMake (faktycznie używam nightlies, ale wydaje mi się, że kiedy to napisałem, używałem 3.3), po prostu uruchom touch CMakeLists.txt && cmake . && make helpi powinno działać. Mogę tylko zgadywać, że używasz starożytnego cmake'a, czy nie używasz generatora Makefiles Unixa?
Timmmm
Używam CMake 3.6.2 z generatorem unixowym w systemie Windows. Poszukam wyjaśnienia, ponieważ wydaje się to przydatne.
Xavier T.
26

Połączyłem te dwie odpowiedzi: https://stackoverflow.com/a/9524878/86967 i https://stackoverflow.com/a/7390874/86967 i zrobiłem trochę ucieczki, aby można było tego użyć z wnętrza 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
nobar
źródło
10
Odkryłem również (niedawno), że uzupełnianie tabulatorów w Bash wyświetli listę dostępnych celów.
nobar
1
+1 za świetne podejście, ale można wprowadzić kilka ulepszeń: (a) wyraźne określenie nie sh -c "…"jest konieczne, ponieważ makedomyślnie używa tego do wywoływania poleceń receptur; (b) użyte polecenie jest zbyt uproszczone, co prowadzi do fałszywych trafień (jak zauważasz); (c) jeśli użyjesz przedrostka, polecenie @nie zostanie powtórzone na standardowe wyjście przed wykonaniem, co eliminuje potrzebę użycia -sprzy wywołaniu.
mklement0
1
istnieje znacznie prostszy cel, który możesz dodać: list: cat Makefile | grep "^ [Az]" | awk „{print $$ 1}” | sed "s /: // g | sort"
thamster
2
Podejście cat / sed kończy się niepowodzeniem na kilku poziomach. Nie rozwija zmiennych, a także nie wyświetla listy celów, które są wynikiem dołączenia innych plików.
Troy Daniels
1
@ mklement0: Wolę używać make -s(za pomocą aliasu Bash) niż komend poprzedzających w pliku makefile @. W niektórych przypadkach @może być przydatny, zwłaszcza jako przedrostek echopoleceń (gdzie wyświetlanie polecenia byłoby zbędne), ale ogólnie nie lubię go używać. W ten sposób widzę „przepisy”, kiedy muszę ( nie używam -s), ale zazwyczaj nie. Oto powiązana dokumentacja: GNU Make Manual, 5.2 Recepcja echa .
nobar
14

Jeśli masz ukończone bash dla makezainstalowanego skryptu zakończenia zdefiniuje funkcję _make_target_extract_script. Ta funkcja ma na celu utworzenie sedskryptu, którego można użyć do uzyskania celów jako listy.

Użyj tego w ten sposób:

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

# List targets from Makefile
sed -nrf <(_make_target_extract_script --) Makefile
hek2mgl
źródło
3
Pomocne, ale zauważ, że nie wszystkie platformy mają skrypt /etc/bash_completioni / lub funkcję _make_target_extract_script- wydaje się, że jesteś na Ubuntu> 12. Jeśli celujesz /usr/share/bash-completion/completions/makezamiast tego, twoje podejście będzie działać na dodatkowych platformach, takich jak Fedora 20. Istnieją (starsze) platformy, które mają ten plik, ale nie funkcja (np. Debian 7 i Ubuntu 12); inne platformy, takie jak OSX, wcale nie są wyposażone w funkcję uzupełniania tabulatorów make. Być może pomocne byłoby opublikowanie rzeczywistej definicji funkcji.
mklement0
1
Dzięki za komentarz. Jest to bardzo mile widziane. Tak, przetestowałem to na Ubuntu 14.04
hek2mgl
11

Jak wskazuje mklement0 , w GNU-make brakuje funkcji wyświetlania wszystkich celów Makefile, a jego odpowiedź i inne zapewniają sposoby na to.

Jednak oryginalny post wspomina także o prowizji , której zmiana zadań robi coś nieco innego niż tylko wypisanie wszystkich zadań w pliku rakefile. Rake da ci tylko listę zadań, które mają powiązane opisy. Zadania bez opisów nie zostaną wymienione . Daje to autorowi możliwość dostarczenia dostosowanych opisów pomocy, a także pominięcia pomocy dla niektórych celów.

Jeśli chcesz naśladować zachowanie prowizji, w którym podajesz opisy dla każdego celu , możesz to zrobić za pomocą prostej techniki: umieść opisy w komentarzach dla każdego celu, który chcesz wymienić.

Możesz umieścić opis obok celu lub, jak to często robię, obok specyfikacji PHONY nad celem, tak jak poniżej:

.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

Który da

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

...
help                Generate list of targets with descriptions

Możesz także znaleźć krótki przykład kodu w tej liście i tutaj .

Ponownie nie rozwiązuje to problemu umieszczenia wszystkich celów w pliku Makefile. Na przykład, jeśli masz duży plik Makefile, który mógł zostać wygenerowany lub napisany przez kogoś innego, i chcesz szybko wyświetlić listę jego celów bez przekopywania się, nie pomoże to.

Jeśli jednak piszesz plik Makefile i chcesz uzyskać sposób generowania tekstu pomocy w spójny, samowydajny sposób, ta technika może być przydatna.

jsp
źródło
To świetna technika - ładna i prosta, ale zawiera także opisy!
Brian Burns
Świetna technika. Zmodyfikowałem to nieco, aby użyć echopolecenia jako opisu polecenia ( stackoverflow.com/a/52059487/814145 ).
Penghe Geng
@PengheGeng Dzięki za post. Chcę wyjaśnić, że @echo "Target 1"to tylko symbol zastępczy, a nie „polecenie echa opisu”. Wygenerowany tekst pomocy nie pochodzi z @echo. W prawdziwym pliku Makefile echozostaną one zastąpione poleceniem kompilacji lub jakimś innym. Zedytuję post, aby to wyjaśnić.
jsp
4

Odpowiedź @ nobar pomaga pokazać, jak używać uzupełniania tabulatorów, aby wyświetlić listę celów makefile .

  • Działa to świetnie na platformach, które domyślnie zapewniają tę funkcjonalność (np. Debian, Fedora ).

  • Na innych platformach (np. Ubuntu ) musisz jawnie załadować tę funkcję, zgodnie z odpowiedzią @ hek2mgl :

    • . /etc/bash_completion instaluje kilka funkcji uzupełniania tabulatorów, w tym tę dla make
    • Alternatywnie, aby zainstalować tylko uzupełnianie kart dla make:
      • . /usr/share/bash-completion/completions/make
  • W przypadku platform, które w ogóle nie oferują tej funkcji , takich jak OSX , można zaimplementować następujące polecenia (dostosowane tutaj ), aby je zaimplementować:
_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
  • Uwaga: Nie jest to tak skomplikowane, jak funkcja uzupełniania tabulatorów, która jest dostarczana z dystrybucjami Linuksa: przede wszystkim niezmiennie jest kierowana na plik makefile w bieżącym katalogu , nawet jeśli wiersz poleceń jest skierowany na inny plik makefile -f <file>.
mklement0
źródło
4

Moja ulubiona odpowiedź na to pytanie została opublikowana przez Chrisa Downa w Unix & Linux Stack Exchange. Zacytuję.

Oto jak moduł uzupełniania basha makepobiera swoją listę:

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

Drukuje listę celów rozdzielaną znakami nowej linii, bez stronicowania.

Użytkownik Brainstone sugeruje potokowanie w sort -ucelu usunięcia zduplikowanych wpisów:

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

Źródło: Jak wyświetlić listę wszystkich celów w marce? (Unix i Linux SE)

Marc.2377
źródło
4

Koncentrując się na łatwej składni do opisu celu make i mając czysty wynik, wybrałem takie podejście:

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:

Traktowanie powyższego jako pliku Makefile i uruchomienie go daje ci coś w rodzaju

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

Objaśnienie łańcucha poleceń:

Richard Kiefer
źródło
Bardzo fajne rozwiązanie. Używam tego od kilku lat: awk -F ':|##' '/^[^\t].+:.*##/ { printf "\033[36mmake %-28s\033[0m -%s\n", $$1, $$NF }' $(MAKEFILE_LIST) | sort z ##komentarzem przed tą samą linią co cel. Ale myślę, że twoje rozwiązanie pozwala na czytelność.
toroc
Makefile składający się z pierwszych dwóch wierszy raportów grep: parentheses not balancedna moim komputerze z systemem OSX 10.15.
Malcolm Crum
@ Crummy przepraszam, mój błąd. Dzięki za zwrócenie na to uwagi. Naprawione. make wymaga znaków dolara, które nie powinny rozpoczynać nazw zmiennych.
Richard Kiefer
Uważaj, StackOverflow konwertuje tabulacje na spacje podczas wyświetlania powyższych sekcji kodu, ale Makefile wymagają tabulatorów. Możesz edytować post, a następnie skopiować sekcje, aby zachować zakładki.
Richard Kiefer
2

Wiele praktycznych rozwiązań tutaj, ale jak lubię mówić: „jeśli warto to zrobić raz, to warto to zrobić ponownie”. Poprosiłem o skorzystanie z sugestii użycia (tab) (tab), ale jak niektórzy zauważyli, możesz nie mieć pomocy w uzupełnianiu lub, jeśli masz wiele plików dołączeń, możesz chcieć łatwiejszego sposobu, aby ustalić, gdzie jest zdefiniowany cel.

Nie testowałem poniżej z pod-markami ... Myślę, że to nie zadziała. Jak wiemy rekurencyjny sprawia, że ​​jest uważany za szkodliwy.

.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 := \)

Które lubię, ponieważ:

  • lista celów według dołączonego pliku.
  • generuj surowe dynamiczne definicje celu (zamienia zmienne ograniczniki na modulo)
  • wypisuje każdy cel w nowej linii
  • wydaje się jaśniejszy (subiektywna opinia)

Wyjaśnienie:

  • plik foreach na MAKEFILE_LIST
  • wypisuje nazwę pliku
  • linie grep zawierające dwukropek, które nie są wcięte, nie są komentarzami i nie zaczynają się kropką
  • wyklucz wyrażenia natychmiastowego przypisania (: =)
  • wycinanie, sortowanie, wcięcie i dzielenie zależności reguł (po dwukropku)
  • Ograniczniki zmiennych munge, aby zapobiec ekspansji

Przykładowe dane wyjściowe:

 = 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
ginkgoMZD
źródło
1

Ten był dla mnie pomocny, ponieważ chciałem zobaczyć cele kompilacji wymagane (i ich zależności) przez make target. Wiem, że tworzenie celów nie może zaczynać się od „.” postać. Nie wiem, jakie języki są obsługiwane, więc wybrałem wyrażenia nawiasowe egrep.

cat Makefile | egrep "^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$"
seanlum
źródło
1

To jest dalekie od czystego, ale wykonałem pracę dla mnie.

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

Używam make -ptego, który zrzuca wewnętrzną bazę danych, ditch stderr, używam szybkiego i brudnego, grep -A 100000aby utrzymać dół wyniku. Następnie oczyszczam dane wyjściowe za pomocą kilku grep -v, a na koniec używam, cutaby uzyskać to, co znajduje się przed dwukropkiem, a mianowicie cele.

To wystarczy dla moich skryptów pomocniczych na większości moich plików Makefiles.

EDYCJA: dodano, grep -v Makefileże jest to reguła wewnętrzna

Lisael
źródło
1

Jest to modyfikacja bardzo pomocnej odpowiedzi jsp ( https://stackoverflow.com/a/45843594/814145 ). Podoba mi się pomysł, aby uzyskać nie tylko listę celów, ale także ich opisy. Makefile jsp umieszcza opis jako komentarz, który często znalazłem, będzie powtarzany w poleceniu echo opisu celu. Zamiast tego wyodrębniam opis z polecenia echo dla każdego celu.

Przykład 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

Wyjście 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

Uwagi:

  • Tak jak odpowiedź jsp , na liście mogą znajdować się tylko cele PHONY, które mogą, ale nie muszą działać w twoim przypadku
  • Ponadto wyświetla tylko te cele PHONY, które mają polecenie echolub :jako pierwsze polecenie przepisu. :oznacza „nic nie rób”. Używam go tutaj do celów, których echo nie jest potrzebne, takich jak allcel powyżej.
  • Istnieje dodatkowa sztuczka dla helpcelu, aby dodać „:” do make helpwyniku.
Penghe Geng
źródło
0

Jeszcze jedna dodatkowa odpowiedź na powyższe.

testowane na MacOSX-ie przy użyciu tylko cat i awk na terminalu

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

wyświetli plik make jak poniżej:

cel1

target2

target3

w Makefile powinna to być ta sama instrukcja, upewnij się, że uciekasz przed zmiennymi używając zmiennej $$ zamiast $ zmiennej.

Wyjaśnienie

kot - wypluwa zawartość

| - potok analizuje dane wyjściowe do następnego awk

awk - uruchamia wyrażenie regularne z wyłączeniem „powłoki” i akceptując tylko wiersze „Az”, a następnie drukuje pierwszą kolumnę o wartości 1 USD

awk - ponownie usuwa ostatni znak „:” z listy

jest to szorstki wynik i możesz robić bardziej funkowe rzeczy za pomocą AWK. Staraj się unikać sed, ponieważ nie jest on tak spójny w wariantach BSD, tzn. Niektóre działają na * nix, ale zawodzą na BSD takich jak MacOSX.

Więcej

Powinieneś być w stanie dodać to (z modyfikacjami) do pliku do zrobienia , do domyślnego folderu zakończenia bash /usr/local/etc/bash-completion.d/, co oznacza, że ​​kiedy "zrobisz kartę tab " ... cele oparte na skrypcie jednoliniowym.

Jimmy MG Lim
źródło
możesz także użyć make -qp zamiast cat. więc zmieni się w make -qp | awk '/: / &&! /: = / && / ^ [Az] / &&! / PATH / &&! / DISPLAY / &&! / TERM_SESSION / &&! / USER_TEXT_ENCODING / &&! / Makefile / {print substr (0 USD, 1 , długość (0 USD) -1) | „sort -u”} '
Jimmy MG Lim
0

Zwyklę robię:

grep install_targets Makefile

Wróciłby z czymś takim jak:

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

mam nadzieję, że to pomoże

Heider Sati
źródło
0

Skrypt Bash

Oto bardzo prosty sposób, aby to zrobić bash- w oparciu o komentarz @ cibercitizen1 powyżej :

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

Zobacz także bardziej autorytatywną odpowiedź @ Marc.2377, która mówi, jak makerobi to moduł uzupełniania Bash .

jvriesem
źródło
-4

nie jestem pewien, dlaczego poprzednia odpowiedź była tak skomplikowana:

list:
    cat Makefile | grep "^[A-z]" | awk '{print $$1}' | sed "s/://g" 
thamster
źródło
8
Poprzednia odpowiedź jest tak skomplikowana, ponieważ obejmuje wszystkie scenariusze, że odpowiedź ta nie obejmuje: (a) włączenie celów określonych poprzez zmienne (np $(SHELLS): ...), (b) włączenie celów, które zaczynają się od cyfry, (c) nie- włączenie definicji zmiennych , (d) ukierunkowanie na właściwy makeplik makefile, jeśli został określony za pomocą jawnej ścieżki makefile. (a) jest kluczową wadą: nawet jeśli niezawodnie wybrałeś właściwy plik makefile, parsowanie surowego pliku nie będzie działać w ogólnym przypadku, z powodu braku rozszerzania zmiennej.
mklement0
6
Tak na marginesie, ponownie skomplikowane: Twój komenda może być uproszczone do dalszej - ale głównym punktem jest to, że nie jest wystarczająco wytrzymałe : awk -F: '/^[A-z]/ {print $$1}' Makefile. Wreszcie, w dużej mierze akademicki punkt: użycie [A-z]zamiast [:alpha:]oznacza, że ​​ominiesz cele zaczynające się od obcej postaci, takiej jak á.
mklement0
@ mklement0 twoje pierwsze polecenie awk działa ładnie i jest jak dotąd najprostsze, chociaż użycie [: alpha:] z jakiegoś powodu wydaje się go zepsuć - brakuje niektórych celów w pliku testowym.
Brian Burns,
@ bburns.km: Mam złe: Powinienem powiedzieć [[:alpha:]]zamiast [:alpha:]( [:alpha:]reprezentuje lokalizacji świadomy zestaw liter wewnątrz klasy znaków ( [...]), stąd konieczność efektywnej podwójne [[ / ]].
mklement0
4
Dlaczego ta odpowiedź jest tak skomplikowana? Udaje ci się zebrać kilka bezużytecznych grzechów w tym krótkim fragmencie. awk -F: '/^[A-Za-z]/ { print $$1 }' Makefileużywa pojedynczego procesu i, mam nadzieję, bardziej poprawnego wyrażenia regularnego (chociaż oczywiście możesz mieć cele z podkreśleniami, liczbami itp., jak zauważono we wcześniejszych komentarzach).
tripleee