Как вы получаете список целей в 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/help-make@gnu.org/msg06434.html.
В любом случае, я сделал маленький взлом, чтобы извлечь цели из файла makefile, который вы можете включить в файл makefile.
list:
@grep '^[^#[:space:]].*:' Makefile
Это даст вам список определенных целей. Это только начало - например, он не отфильтровывает зависимости.
> make list
list:
copy:
run:
plot:
turnin:
12 ответов
это попытка улучшить @ nobar большой подход следующим образом:
- использует более надежную команду для извлечения целевых имен, которая, надеюсь, предотвращает любые ложные срабатывания (а также устраняет ненужные
sh -c
) - не всегда нацелен на makefile в настоящее directory; уважает makefiles, явно указанные с
-f <file>
- исключает скрытые цели конвенции, это цели, имя которых не начинается ни с буквы, ни с цифры
- обходится один фиктивной цели
- префиксы команды с
@
чтобы предотвратить его эхо перед выполнением
любопытно, GNU make
не имеет функции для перечисления только имен целей, определенных в файле makefile. The -p
опция производит вывод, который включает в себя все цели, но хоронит их во многих других информация.
поместите следующее правило в makefile для GNU make
для реализации цели с именем list
это просто перечисляет все целевые имена в алфавитном порядке-т. е.: 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 ($ !~ "^[#.]") {print $}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs
важно: наклеивая это,убедитесь, что последняя строка имеет отступ ровно 1 фактическая вкладка char. (пробелы делать не работы).
обратите внимание, что сортировка полученный список целей является самым лучшим вариантом, так как не сортировка не создает полезного порядка в том порядке, в котором цели появляются в makefile не сохранить.
Кроме того, подцели правила, состоящего из нескольких целей, неизменно выводятся отдельно и будет поэтому, из-за сортировки, обычно не появляются рядом друг с другом; например, правило начиная с a z:
Уилл!--49-->не есть цели a
и z
в списке рядом друг с другом на выходе, если есть дополнительные цели.
объяснение правил:
- .
PHONY: list
- объявляет целевой список фальшивой целью, т. е. one не со ссылкой на , который поэтому должен иметь свой вызванный рецепт безусловно
-
$(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
As mklement0 указывает, функция для перечисления всех целей Makefile отсутствует в GNU-make, и его ответ и другие способы сделать это.
однако в исходном сообщении также упоминается грабли, которого задачи switch делает что-то немного другое, чем просто перечисление всех задач в rakefile. Rake даст вам только список задач, которые имеют связанные описания. Задачи без описаний не будет перечислено. Это дает автору возможность предоставляют индивидуальные описания и опустить помощь для определенных целей.
Если вы хотите эмулировать поведение рейка, где вы предоставляете описания для каждой цели есть простой метод для этого: добавьте описаний в комментарии для каждой цели, которую вы хотите перечислить.
вы можете поместить описание рядом с целью или, как я часто делаю, рядом с фальшивой спецификацией выше цель, вот так:
.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
чтобы получить то, что перед двоеточием, а именно, цели.
этого достаточно для моих вспомогательных скриптов на большинстве моих файлов Makefile.
EDIT: добавлено grep -v Makefile
это внутреннее правило
здесь много работоспособных решений, но, как мне нравится говорить: "если это стоит сделать один раз, это стоит сделать снова." Я сделал upvote sugestion для использования (tab) (tab), но, как некоторые отметили, у вас может не быть поддержки завершения, или, если у вас есть много файлов include, вам может потребоваться более простой способ узнать, где определена цель.
Я не тестировал ниже с sub-makes...Думаю, это не сработает. Как мы знаем, рекурсивный делает считается вредным.
.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). Мне нравится идея получить не только список целей, но и их описания. jspMakefile помещает описание в качестве комментария, который я нашел, часто будет повторяться в команде 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"