Ответ 1
Можете ли вы проанализировать вывод из make -pn
(т.е. make --print-data-base --dry-run
)? Он печатает все переменные, правила, неявные правила и какие команды будут выполняться с кропотливой детализацией.
У меня довольно большой make файл, который на лету создает множество целей, вычисляя имена из переменных. (например, foo $(VAR): $(PREREQS)). Есть ли способ, который gnu make может убедить в том, чтобы выплевывать список целей после того, как он расширил эти переменные?
Я хотел бы получить цели для файла make файла aribitrary. Я пытаюсь написать функцию завершения для моей оболочки.
Можете ли вы проанализировать вывод из make -pn
(т.е. make --print-data-base --dry-run
)? Он печатает все переменные, правила, неявные правила и какие команды будут выполняться с кропотливой детализацией.
make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'
Взято из завершения make arg, которое работает как шарм.
Я не уверен, что это всего лишь gnu make thing, но это хорошо работает:
make help
Несколько респондентов предложили использовать make -pn
, который будет печатать базу данных правил, но ничего не выполнять - более или менее. Проблема с этим подходом заключается в том, что -n
все еще вызывает все рекурсивные make, и он все еще делает намного больше работы, чем необходимо, потому что он печатает каждую команду, которую он вызывал бы в обычной сборке. Более эффективным решением было бы создать тривиальный makefile, dummy.mk, с этим содержимым:
__all_targets__: ; #no-op
Теперь вызовите make как make -p -f Makefile -f dummy.mk __all_targets__
. При любом существенном построении разница в объеме выпуска, созданного make, значительна. Например:
$ gmake -pn | wc
138985 2632330 69612711
$ gmake -f Makefile -f /tmp/dummy.mk -pn __all_targets__ | wc
21673 93437 878985
Время исполнения было значительно лучше - 2.063s для первой версии, 0.059s для второго.
Завершите bash завершение для make в GitHub.
Изменить: FYI репозиторий debian bash git в другом ответе теперь включает расширенную версию этого script адаптированного к bash вариантам использования для завершения.
#!/bin/bash
SCRIPT='
/^# Make data base/,/^# Files/d # skip until files section
/^# Not a target/,+1 d # following target isnt
/^\.PHONY:/ d # special target
/^\.SUFFIXES:/ d # special target
/^\.DEFAULT:/ d # special target
/^\.PRECIOUS:/ d # special target
/^\.INTERMEDIATE:/ d # special target
/^\.SECONDARY:/ d # special target
/^\.SECONDEXPANSION/ d # special target
/^\.DELETE_ON_ERROR:/ d # special target
/^\.IGNORE:/ d # special target
/^\.LOW_RESOLUTION_TIME:/ d # special target
/^\.SILENT:/ d # special target
/^\.EXPORT_ALL_VARIABLES:/ d # special target
/^\.NOTPARALLEL:/ d # special target
/^\.ONESHELL:/ d # special target
/^\.POSIX:/ d # special target
/^\.NOEXPORT:/ d # special target
/^\.MAKE:/ d # special target
# The stuff above here describes lines that are not
# explicit targets or not targets other than special ones
# The stuff below here decides whether an explicit target
# should be output.
/^[^#\t:=%]+:([^=]|$)/ { # found target block
h # hold target
d # delete line
}
/^# File is an intermediate prerequisite/ { # nope
s/^.*$//;x # unhold target
d # delete line
}
/^([^#]|$)/ { # end of target block
s/^.*$//;x # unhold target
s/:.*$//p # write current target
d # hide any bugs
}
'
make -npq .DEFAULT 2>/dev/null | sed -n -r "$SCRIPT" \
| sort | uniq
Это гораздо более полное script, чем завершение debian bash script, поскольку оно предоставляет результаты для сгенерированных правил, на которые задают вопрос, и верхний проголосовавший ответ (debian bash завершение script на сервере debian git) недостаточно далеко.
Это не оригинальный script, с которым я связан, но он намного проще и быстрее нажимает.
Это код для псевдонима, основанного на решении Todd Hodes
alias mtargets='make -qp | awk -F":" "/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split(\$1,A,/ /);for(i in A)print A[i]}"'
Это даст хороший результат:
make -pn | perl -F: -ane 'print "$F[0]\n" if /^\w+\s*:/' | sort
Существует очень приятное решение с некоторой магией sed и egrep: https://gist.github.com/pvdb/777954
Угадайте, что я немного опаздываю на эту вечеринку, но если вы ищете определенную команду, вы можете попробовать
make -qp | grep -v '^# ' | grep -v '^[[:space:]]' | grep --only-matching '^.*:'
В основном это работает, хотя он может содержать некоторые нецелевые элементы, такие как директива vpath
. Если вы не зависите от встроенных правил make
, вы можете использовать make -qpR
в качестве первой команды в конвейере.
Решение Ruby:
`make -qp`.split("\n").select{|l| l =~ /^\w/ && l !~ /=/}.map{|l| l.sub(/:.*/,'')}
Im работает над Solaris 10 и турбокомпрессором C. Данное решение не работает для моего проекта makefile. даже после изменения командной строки выше в синтаксисе tcsh. Тем не менее, я узнал, что вы можете получить легкое решение, используя
remake --tasks | grep -v "clean some static output or just grep tabs on start of line" | awk ´{print $1}´
версия римейка:
remake --version
является
GNU Make 3.82+dbg0.8
Built for sparc-sun-sparc2-9
и некоторые другие несущественные данные версии
Я пошел искать тот же вопрос и придумал этот поворот:
make -pn | sed -rn '/^[^# \t\.%].*:/p'
Это удаляет все строки комментариев, шаблонные правила (строки, начинающиеся с вкладок), все шаблоны (примеры .c.o
и %.o: %.c
).
Нашел это решение в другом потоке:
sh -c "cat Makefile | egrep \"^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$\""
Вы также можете добавить его в свой Makefile
:
list:
sh -c "cat Makefile | egrep \"^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$\\""
И выполните make list
.
Конечно, но когда вы хотите, чтобы он выплюнул их?
Чтобы сообщить имя цели при ее запуске, поместите строку в правило:
foo$(VAR): $(PREREQS)
@echo now making the foo target: [email protected]
do_other_stuff...
Чтобы выплевывать их все сразу, вы можете сделать отдельную цель PHONY:
.PHONY: show_vars
show_vars:
@echo foo$(VAR)
@echo bar$(PARAM) blah$(FLAG)
# and so on
И это может быть предпосылкой вашей целевой цели по умолчанию:
all: show_vars
...
EDIT:
Вам нужен способ показать все возможные цели произвольного make файла, который, я полагаю, означает неинтрузивно. Ну...
Чтобы сделать это точно и уметь справляться со сложными make файлами, например. с использованием правил, построенных операторами eval
, вам нужно написать что-то близко к эмулятору Make. Непрактичный.
Чтобы увидеть цели простых правил, вы можете написать makefile, который будет действовать как сканер make файлов, работающий в произвольном make файле:
Это будет впечатляющая работа. Вы уверены, что цель стоит усилий?
grep ^[a-z].*\:$ Makefile | sed s,:,,g