Перечислите цели/цели в GNU make, которые содержат переменные в их определении

У меня довольно большой make файл, который на лету создает множество целей, вычисляя имена из переменных. (например, foo $(VAR): $(PREREQS)). Есть ли способ, который gnu make может убедить в том, чтобы выплевывать список целей после того, как он расширил эти переменные?

Я хотел бы получить цели для файла make файла aribitrary. Я пытаюсь написать функцию завершения для моей оболочки.

Ответ 1

Можете ли вы проанализировать вывод из make -pn (т.е. make --print-data-base --dry-run)? Он печатает все переменные, правила, неявные правила и какие команды будут выполняться с кропотливой детализацией.

Ответ 2

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

Взято из завершения make arg, которое работает как шарм.

Ответ 3

Я не уверен, что это всего лишь gnu make thing, но это хорошо работает:

make help

Ответ 4

Несколько респондентов предложили использовать 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 для второго.

Ответ 6

Изменить: 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, с которым я связан, но он намного проще и быстрее нажимает.

Ответ 7

Это код для псевдонима, основанного на решении Todd Hodes

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

Ответ 8

Это даст хороший результат:

make -pn | perl -F: -ane 'print "$F[0]\n" if /^\w+\s*:/' | sort

Ответ 10

Угадайте, что я немного опаздываю на эту вечеринку, но если вы ищете определенную команду, вы можете попробовать

make -qp | grep -v '^# ' | grep -v '^[[:space:]]' | grep --only-matching '^.*:'

В основном это работает, хотя он может содержать некоторые нецелевые элементы, такие как директива vpath. Если вы не зависите от встроенных правил make, вы можете использовать make -qpR в качестве первой команды в конвейере.

Ответ 11

Решение Ruby:

`make -qp`.split("\n").select{|l| l =~ /^\w/ && l !~ /=/}.map{|l| l.sub(/:.*/,'')}

Ответ 12

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

и некоторые другие несущественные данные версии

Ответ 13

Я пошел искать тот же вопрос и придумал этот поворот:

make -pn | sed -rn '/^[^# \t\.%].*:/p'

Это удаляет все строки комментариев, шаблонные правила (строки, начинающиеся с вкладок), все шаблоны (примеры .c.o и %.o: %.c).

Ответ 14

Нашел это решение в другом потоке:

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.

Ответ 15

Конечно, но когда вы хотите, чтобы он выплюнул их?

Чтобы сообщить имя цели при ее запуске, поместите строку в правило:

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 файле:

  • Получите все целевые имена из make файла с помощью sed.
  • `include` makefile, чтобы использовать его для расширения переменных.
  • Используйте `show_%:; echo $$ * `для печати всех целей

Это будет впечатляющая работа. Вы уверены, что цель стоит усилий?

Ответ 16

grep ^[a-z].*\:$ Makefile | sed s,:,,g