Jak uzyskać listę celów w pliku makefile?

Użyłem trochę rake' a (program do tworzenia Ruby) i ma on 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 opcji, aby to zrobiÄ ‡ w GNU make.

Najwyraźniej kod jest prawie do niego, od 2007 roku - http://www.mail-archive.com/[email protected]/msg06434.html .

W każdym razie, zrobiłem mały hack, aby wyodrębnić cele z pliku makefile, który można włączyć do pliku makefile.

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

Da ci listę zdefiniowanych celów. To tylko początek - nie odfiltrowuje np. zależności.

> make list
list:
copy:
run:
plot:
turnin:
Author: Brian Burns, 2010-11-18

12 answers

To jest próba poprawy na @nobar ' s wielkie podejście w następujący sposób:

  • używa bardziej rozbudowanego polecenia do wyodrębniania nazw docelowych, co miejmy nadzieję zapobiega fałszywym alarmom (a także usuwa niepotrzebne sh -c)
  • nie zawsze celuje w plik makefile w katalogu current ; respektuje pliki Makefile wyraźnie określone przez -f <file>
  • wyklucza ukryte cele - zgodnie z konwencją są to cele, których nazwa nie zaczyna się ani z literą ani cyfrą
  • sprawia, że z POJEDYNCZY fałszywy cel
  • prefiks komendy @, aby zapobiec jej odbiciu przed wykonaniem

Co ciekawe, GNU make nie ma funkcji pozwalającej wymieniać tylko nazwy celów zdefiniowanych w pliku makefile. Opcja -p generuje dane wyjściowe, które zawierają wszystkie cele, ale chowają je w wielu innych informacjach.

Umieść następującą regułę w pliku makefile dla GNU make, aby zaimplementować Nazwa celu list, która po prostu wyświetla wszystkie nazwy celu w porządku alfabetycznym - np.: invoke as make 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 '^$@$$' | xargs

Ważne: podczas wklejania tego, upewnij się, że ostatnia linia jest wcięta przez dokładnie 1 rzeczywisty znak tabulacji. (spacje działają nie działają ) .

Zauważ, że sortowanie wynikowa lista celów jest najlepszą opcją, ponieważ Nie sortowanie nie daje pomocnego porządku w tym porządku, w którym cele wyświetlanie w pliku makefile jest Nie zachowane.
Ponadto, cele podrzędne reguły zawierającej wiele celów są niezmiennie wyjściowe oddzielnie i dlatego, ze względu na sortowanie, Zwykle Nie pojawiają się obok siebie; np. reguła zaczynająca się od a z: będzie Nie mieć cele a i z wymienione obok siebie w wyjściu, jeśli istnieją dodatkowe cele cele.

Wyjaśnienie reguła :

  • .PHONY: list
    • deklaruje listę docelową fałszywym celem, tzn. jednym Nie odnoszącym się do pliku , który powinien zatem mieć swój przepis wywołany bezwarunkowo
  • $(MAKE) -prRn -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null

    • wywołuje make ponownie w celu wydrukowania i przetworzenia bazy danych pochodzącej z pliku makefile:
      • -p drukuje bazę danych
      • -Rr tłumi włączenie wbudowanych reguł i zmienne
      • -q testuje tylko aktualny stan celu (bez przerabiania czegokolwiek), ale to samo w sobie nie uniemożliwia wykonywania poleceń receptury we wszystkich przypadkach; stąd:
      • -f $(lastword $(MAKEFILE_LIST)) zapewnia, że ten sam plik makefile jest kierowany tak jak w oryginalnym wywołaniu, niezależnie od tego, czy był kierowany w sposób dorozumiany czy jawny za pomocą -f ....
        Zastrzeżenie: spowoduje to przerwanie, jeśli plik makefile zawiera dyrektywy include; aby temu zaradzić, zdefiniuj zmienną THIS_FILE := $(lastword $(MAKEFILE_LIST)) przed dowolnymi include dyrektywami i zamiast tego użyj -f $(THIS_FILE).
      • : jest celowo nieprawidłowym celem , który ma na celu zapewnić, że żadne polecenia nie są wykonywane; 2>/dev/null tłumi wynikowy komunikat o błędzie. Uwaga: polega to jednak na -p wydrukowaniu bazy danych, co ma miejsce w przypadku GNU make 3.82. Niestety, GNU make nie oferuje bezpośredniej opcji po prostu wydruku bazy danych, bez również wykonania domyślnego (lub) zadanie; jeśli nie musisz kierować konkretnego pliku Makefile, możesz użyć make -p -f/dev/null, zgodnie z zaleceniami na stronie man.
  • -v RS=

    • jest to idiom awk, który dzieli Dane wejściowe na bloki sąsiadujących ze sobą niepustych linii.
  • /^# File/,/^# Finished Make data base/
    • dopasowuje zakres linii w wyjściu, który zawiera wszystkie cele ( prawda od GNU make 3.82) - ograniczając parsowanie do tego zakresu, nie ma potrzeby radzenia sobie z fałszywymi alarmami z innych sekcji wyjściowych.
  • if ($$1 !~ "^[#.]")
    • wybiórczo ignoruje bloki:
      • # ... ignoruje inne cele, których bloki zaczynają się od # Not a target:
      • . ... ignoruje cele specjalne
    • wszystkie pozostałe bloki powinny zaczynać się od wiersza zawierającego tylko nazwę jawnie zdefiniowanego celu, po którym następuje :
  • egrep -v -e '^[^[:alnum:]]' -e '^$@$$' usuwa niechciane cele z wyjścia:
    • '^[^[:alnum:]]' ... nie obejmuje Ukryte cele, które-zgodnie z konwencją - są celami, które nie rozpoczynają się ani literą, ani cyfrą.
    • '^$@$$' ... nie obejmuje samego celu list
  • xargs
    • efektywnie konwertuje linie wyjściowe na jednolinijkową, oddzieloną spacjami listę; pomiń tę opcję, jeśli chcesz, aby każda nazwa docelowa wyświetlała się w swojej własnej linii.
 78
Author: mklement0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-09 13:25:55

W Bash (przynajmniej) można to zrobić automatycznie z wypełnieniem kart:

make(space)(tab)(tab)
 120
Author: nobar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-15 00:20:29

Połączyłem te dwie odpowiedzi: https://stackoverflow.com/a/9524878/86967 i https://stackoverflow.com/a/7390874/86967 i zrobił kilka ucieczek, aby to mogło być użyte 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
 24
Author: nobar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:36

To oczywiście nie zadziała w wielu przypadkach, ale jeśli twój {[1] } został 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
 16
Author: Timmmm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-05 16:39:43

Jeśli masz zainstalowane uzupełnianie bash dla make, skrypt uzupełniania zdefiniuje funkcję _make_target_extract_script. Ta funkcja jest przeznaczona do tworzenia skryptu sed, który może być użyty do uzyskania celów jako lista.

Użyj go tak:

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

# List targets from Makefile
sed -nrf <(_make_target_extract_script --) Makefile
 10
Author: hek2mgl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-28 08:59:33

Jak wskazuje mklement0, brakuje funkcji do wypisania wszystkich celów Makefile w GNU-make, a jego odpowiedź i inne dostarcza sposobów na to.

Jednak oryginalny post wspomina równieżrake , któregozadania switch robi coś nieco innego niż tylko lista wszystkich zadań w pliku rakefile. Rake da Ci tylko listę zadań, które mają powiązane opisy. Zadania bez opisów nie będą wyświetlane . To daje autorowi możliwość zarówno dostarczania niestandardowych opisów pomocy, jak i pomijania pomocy dla niektórych celów.

Jeśli chcesz emulować zachowanie rake ' a, gdzie podajesz opisy dla każdego celu , istnieje prosta technika: osadzanie opisów w komentarzach dla każdego celu, który chcesz umieścić na liście.

Możesz albo umieścić opis obok celu, albo, jak to często robię, obok fałszywej specyfikacji nad celem, jak to:

.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 będzie yield

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

...
help                Generate list of targets with descriptions

Możesz również znaleźć krótki przykład kodu w w tym gisti tutaj.

Ponownie, nie rozwiązuje to problemu listy wszystkich celów w pliku Makefile. Na przykład, jeśli masz duży plik Makefile, który został wygenerowany lub który napisał ktoś inny, i chcesz szybkiego sposobu na listę celów bez przekopywania się przez niego, to nie pomoże.

Jednakże, jeśli piszesz plik Makefile i chcesz, aby sposób generowania tekstu pomocy był spójny, samodokumentujący sposób, technika ta może być przydatna.

 4
Author: jsp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-22 15:45:24

@nobar ' s answer pokazuje, jak użyć tab completion, aby wyświetlić listę celów makefile.

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

  • Na innych platformach (np. Ubuntu) musisz jawnie załadować tę funkcjonalność, jak sugeruje @hek2mgl ' s answer:
    • . /etc/bash_completion instaluje kilka zakładek funkcje, w tym dla make
    • alternatywnie, aby zainstalować tylko uzupełnianie kart dla make:
      • . /usr/share/bash-completion/completions/make
  • dla platform, które w ogóle nie oferują tej funkcjonalności, takich jak OSX , możesz użyć następujących poleceń (zaadaptowanych z tutaj ), aby ją 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 wyrafinowane jak funkcjonalność uzupełniania kart, która zawiera dystrybucje Linuksa: przede wszystkim niezmiennie kieruje plik makefile w katalogu current , nawet jeśli linia poleceń kieruje inny plik makefile z -f <file>.
 3
Author: mklement0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:54

Ten był dla mnie pomocny, ponieważ chciałem zobaczyć wymagane cele budowania (i ich zależności) przez cel make. Wiem, że cele make nie mogą zaczynać się od"."charakter. Nie wiem, jakie języki są obsługiwane, więc wybrałem wyrażenia bracket egrep.

cat Makefile | egrep "^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$"
 1
Author: seanlum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-08 05:20:52

To nie jest czyste, ale wykonało swoją 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 -p, który wyrzuca wewnętrzną bazę danych, porzuca stderr, używa szybkiego i brudnego grep -A 100000, aby utrzymać dno wyjścia. Następnie czyszczę wyjście kilkoma grep -v i na koniec używam cut, Aby uzyskać to, co jest przed dwukropkiem, a mianowicie cele.

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

EDIT: added grep -v Makefile that is a internal rule

 1
Author: Lisael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-19 15:10:42

Jest tu mnóstwo praktycznych rozwiązań, ale jak lubię mówić: "Jeśli warto zrobić raz, warto zrobić ponownie." Dodałem sugestię użycia (tab) (tab), ale jak niektórzy zauważyli, możesz nie mieć obsługi uzupełniania lub, jeśli masz wiele plików nagłówkowych, możesz chcieć łatwiej dowiedzieć się, gdzie jest zdefiniowany cel.

Nie testowałem poniżej z sub-markami...Myślę, że to nie zadziała. Jak wiemy, rekurencyjny sprawia, że uważane za szkodliwe.

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

  • wypisuje cele według Pliku include.
  • wyjściowe surowe dynamiczne definicje celu (zastępuje ograniczniki zmiennych Modulo)
  • wypisuje każdy cel na nowej linii
  • wydaje się jaśniejsze (subiektywna opinia)

Wyjaśnienie:

  • foreach plik w MAKEFILE_LIST
  • wypisuje nazwę pliku
  • linie grep zawierające dwukropek, które nie są wcięte, nie komentarze i nie zaczynają się kropką
  • exclude immediate assignment expressions (:=)
  • wycinanie, sortowanie, wcięcia i wycinanie zależności od reguł (po dwukropku)
  • ograniczniki zmiennych munge zapobiegające ekspansji

Przykładowe Wyjście:

 = 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
Author: ginkgoMZD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-19 16:28:59

Jest to modyfikacja jsp's very helpful answer ( https://stackoverflow.com/a/45843594/814145 ). podoba mi się pomysł zdobycia nie tylko listy celów, ale także ich opisów. JSP 'S Makefile umieszcza opis jako komentarz, który znalazłem często 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 samo jak jsp 's odpowiedź, tylko fałszywe cele mogą być wymienione, które mogą, ale nie muszą działać dla twojej sprawy
  • ponadto wymienia tylko te fałszywe cele, które mają polecenie echo lub : jako pierwsze polecenie receptury. : oznacza "nic nie robić". Używam go tutaj dla tych celów, które nie są potrzebne echo, takie jak cel all powyżej.
  • istnieje dodatkowa sztuczka dla celu help, aby dodać": "w make help wyjście.
 1
Author: Penghe Geng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-28 13:53:42

Nie wiem dlaczego poprzednia odpowiedź była tak skomplikowana:

list:
    cat Makefile | grep "^[A-z]" | awk '{print $$1}' | sed "s/://g" 
 -3
Author: thamster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-16 19:25:17