Как получить список целей в файле makefile?
я использовал rake немного (программа Ruby make), и у нее есть возможность получить список всех доступных целей, например
> 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...
...
но, похоже, нет возможности сделать это в GNU make.
по-видимому, код почти там для него, по состоянию на 2007 год -http://www.mail-archive.com/[email protected]/msg06434.html.
В любом случае, я сделал небольшой хак, чтобы извлечь цели из файла makefile, который вы можете включить в файл makefile.
list:
@grep '^[^#[:space:]].*:' Makefile
Это даст вам список определенных целей. Это только начало - он не отфильтровывает зависимости, например.
> make list
list:
copy:
run:
plot:
turnin:
12 ответов:
это попытка улучшить @nobar-это следующим образом:
- использует более надежную команду для извлечения целевых имен, которая, надеюсь, предотвращает любые ложные срабатывания (а также устраняет ненужные
sh -c)- не всегда нацелен на makefile в настоящее каталог; уважает make-файлы, явно указанные с помощью
-f <file>- исключает скрытые цели конвенции, это цели, чье имя не начинается ни с буквы, ни с цифры
- позволяет делать с собой один фиктивной цели
- префиксы команды с
@чтобы предотвратить его эхо перед исполнением
любопытно, GNU
makeне имеет функции для перечисления только имена целей, определенных в файле makefile. Элемент-pопция производит вывод, который включает в себя все цели, но хоронит их во многих других информация.поместите следующее правило в makefile для GNU
makeдля реализации цели с именемlistэто просто перечисляет все целевые имена в алфавитном порядке-т. е.: invoke asmake list:.PHONY: list list: @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($ !~ "^[#.]") {print $}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargsважно: при вставке этого,убедитесь, что последняя строка имеет отступ ровно 1 фактический символ табуляции. (пробелы делать не работы).
обратите внимание, что сортировка полученный список целей является самым лучшим вариантом, так как не сортировка не дает полезного упорядочения в том порядке, в котором цели отображаются в файле makefile не сохранить.
Кроме того, подцели правила, содержащего несколько целей, неизменно выводятся отдельно и поэтому, из-за сортировки, обычно не появляются рядом друг с другом; например, правило начиная сa z:будет не есть целиaиzlisted рядом друг с другом на выходе, если есть дополнительные цели.объяснение правил:
- .
PHONY: list
- объявляет список целей фальшивой целью, т. е. одной не со ссылкой на file, который, следовательно, должен иметь свой рецепт вызывается безусловно
$(MAKE) -prRn -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null
- вызывает
makeснова для печати и анализа базы данных, полученной из файла makefile:
-pпечать базы данных-Rrподавляет включение встроенных правил и переменные-qпроверяет только актуальное состояние цели (без переделки чего-либо), но это само по себе не препятствует выполнению рецепт команды во всех случаях; следовательно:-f $(lastword $(MAKEFILE_LIST))гарантирует, что один и тот же файл makefile будет нацелен, как и в исходном вызове, независимо от того, был ли он нацелен неявно или явно с помощью-f ....
будьте осторожны:это сломается, если ваш makefile содержитincludeдирективы; чтобы решить эту проблему, определите переменнуюTHIS_FILE := $(lastword $(MAKEFILE_LIST))до любойincludeдирективы и использовать-f $(THIS_FILE)вместо.:это заведомо неверный элемент что означает убедитесь, что команды не выполняются;2>/dev/nullподавляет полученное сообщение об ошибке. Примечание: это зависит от-pтем не менее печать базы данных, что имеет место по состоянию на GNU make 3.82. К сожалению, GNU make не предлагает прямого выбора просто печать базы данных, без и выполнение задачи по умолчанию (или заданной); если вы этого не сделаете нужно нацелить конкретный Makefile, вы можете использоватьmake -p -f/dev/null, как рекомендовано в
под Bash (по крайней мере), это может быть сделано автоматически с завершением вкладки:
make(space)(tab)(tab)
Я объединил эти два ответа:https://stackoverflow.com/a/9524878/86967 и https://stackoverflow.com/a/7390874/86967 и сделал некоторые побеги, чтобы это можно было использовать внутри файла makefile.
.PHONY: no_targets__ list no_targets__: list: sh -c "$(MAKE) -p no_targets__ | awk -F':' '/^[a-zA-Z0-9][^$$#\/\t=]*:([^=]|$$)/ {split($,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
Это, очевидно, не будет работать во многих случаях, но если ваш
Makefileбыл создан CMake вы могли бы быть в состоянии запустить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
если у вас есть завершение bash для
makeустановлен, сценарий завершения будет определять функцию_make_target_extract_script. Эта функция предназначена для созданияsedскрипт, который может быть использован для достижения целей в виде списка.используйте его так:
# Make sure bash completion is enabled source /etc/bash_completion # List targets from Makefile sed -nrf <(_make_target_extract_script --) Makefile
Как mklement0 указывает, функция для перечисления всех целей Makefile отсутствует в GNU-make, и его ответ и другие предоставляют способы сделать это.
однако в исходном сообщении также упоминается грабли, которого задачи switch делает что-то немного другое, чем просто перечисление всех задач в rakefile. Рейк даст вам только список задач, которые имеют связанные описания. Задачи без описаний не будет в списке. Это дает автору возможность как предоставлять индивидуальные описания справки, так и опускать справку для определенных целей.
Если вы хотите эмулировать поведение рейка, где вы предоставляете описания для каждой цели есть простой метод для этого: добавьте описаний в комментарии для каждой цели, которую вы хотите перечислить.
вы можете либо поместить описание рядом с целью, либо, как я часто делаю, рядом с фальшивой спецификацией выше цель, вот так:
.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: \(.*\) # \(.*\)/ /' | expand -t20получения
$ make help target1 Target 1 help text target2 Target 2 help text ... help Generate list of targets with descriptionsвы также можете найти короткий пример кода в этом суть и здесь тоже.
опять же, это не решает проблему перечисления всех целей в файле Makefile. Например, если у вас есть большой Makefile, который, возможно, был сгенерирован или кто-то другой написал, и вы хотите быстро перечислить свои цели, не копаясь в нем, это не поможет.
однако, если вы пишете Makefile, и вам нужен способ создания текста справки последовательным, самодокументирующим способом, этот метод может быть полезен.
@nobar-это услужливо показывает, как вкладка завершения в списке задач есть Makefile-ы.
это отлично подходит для платформ, которые обеспечивают эту функциональность по умолчанию (например, Debian, Fedora).
на других платформах (например, Ubuntu) необходимо явно нагрузка эта функциональность, как это подразумевается @hek2mgl по ответ:
. /etc/bash_completionустанавливает несколько функций завершения табуляции, включая функцию дляmake- кроме того, для установки только
Это было полезно для меня, потому что я хотел видеть требуемые цели сборки (и их зависимости) от цели make. Я знаю, что делать мишени нельзя начинать с "а"." характер. Я не знаю, какие языки поддерживаются, поэтому я пошел с выражениями скобок egrep.
cat Makefile | egrep "^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$"
это далеко не чистый, но сделал работу для меня.
make -p 2&>/dev/null | grep -A 100000 "# Files" | grep -v "^$" | grep -v "^\(\s\|#\|\.\)" | grep -v "Makefile:" | cut -d ":" -f 1Я использую
make -pчто сбрасывает внутреннюю базу данных, ditch stderr, используйте быстрый и грязныйgrep -A 100000, чтобы сохранить нижнюю часть выходной. Затем я очищаю выход с помощью парыgrep -vи, наконец, использоватьcutчтобы получить то, что перед двоеточием, а именно, цели.этого достаточно для моих вспомогательных скриптов на большинстве моих Makefiles.
правка: добавил
grep -v Makefileэто внутреннее правило
здесь много работоспособных решений, но, как я люблю говорить, "если это стоит сделать один раз, это стоит сделать снова." Я сделал upvote sugestion для использования (tab) (tab), но, как некоторые отметили, у вас может не быть поддержки завершения, или, если у вас есть много файлов include, вам может потребоваться более простой способ узнать, где определена цель.
Я не проверял ниже с суб-делает...Я думаю, что это не сработает. Как мы знаем, рекурсивные делает считается вредным.
.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 := \)Что Я например, потому что:
- список целей по включенному файлу.
- вывод необработанных динамических целевых определений (заменяет разделители переменных по модулю)
- вывод каждой цели на новой строке
- кажется, яснее (субъективное мнение)
объяснение:
- foreach файл в MAKEFILE_LIST
- output-имя файла
- строки grep, содержащие двоеточие, которые не имеют отступов, нет комментарии, и не начинайте с точки
- исключить немедленного выражения присваивания (:=)
- вырезать, сортировать, отступать и рубить правила-зависимости (после двоеточия)
- разделители переменных munge для предотвращения расширения
Пример Вывода:
= 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
это модификация jspочень полезный ответ (https://stackoverflow.com/a/45843594/814145). Мне нравится идея получения не только списка целей, но и их описания. jsp'S Makefile помещает описание в качестве комментария, который я нашел часто будет повторяться в команде Echo описания цели. Поэтому вместо этого я извлекаю описание из команды echo для каждой цели.
пример 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 \t/p; d; x}'| sort -k2,2 |expand -t 20выход
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Примечания:
- то же, что и jspответ, только фальшивые цели могут быть перечислены, которые могут или не могут работать для вашего случая
- кроме того, в нем перечислены только те фальшивые цели, которые имеют
echoили:команда как первая команда рецепта.:означает "ничего не делать". Я использую его здесь для тех целей, которые не нужны Эхо, напримерallцель выше.- есть дополнительный трюк для
helpцель добавить": "вmake helpвыход.
Не знаю, почему предыдущий ответ был так сложен:
list: cat Makefile | grep "^[A-z]" | awk '{print $}' | sed "s/://g"
Comments