Перечислите цели / задачи в GNU make, которые содержат переменные в своем определении - PullRequest
99 голосов
/ 17 июня 2010

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

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

Ответы [ 16 ]

112 голосов
/ 02 марта 2012
make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'     

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

78 голосов
/ 03 сентября 2010

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

13 голосов
/ 12 октября 2012

Я не уверен, что это только гну, но это хорошо работает:

make help

10 голосов
/ 12 сентября 2011

Несколько респондентов предложили использовать make -pn, который напечатает базу данных правил, но не выполнит ничего - более или менее. Проблема с этим подходом состоит в том, что -n по-прежнему вызывает все рекурсивные операции, и он по-прежнему выполняет гораздо больше работы, чем необходимо, поскольку он печатает каждую команду, которую он вызвал бы в обычной сборке. Более эффективным решением было бы создать тривиальный make-файл 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,063 с для первой версии, 0,059 с для второй.

9 голосов
/ 23 сентября 2011

Проверьте bash завершение для make на GitHub.

7 голосов
/ 26 августа 2012

Редактировать: К вашему сведению, репозиторий git для завершения bash debian в другом ответе теперь включает расширенную версию этого сценария, адаптированную для случаев использования завершения 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

Это гораздо более полный сценарий, чем debian bashСценарий завершения, потому что он предоставляет результаты для сгенерированных правил, о которых спрашивает вопрос, а ответ с наибольшим количеством голосов (сценарий завершения bash Debian на git-сервере debian) идет недостаточно далеко.

Это не оригиналскрипт, на который я ссылаюсь, но он намного проще и на ощупь быстрее.

4 голосов
/ 20 марта 2015

Это код для псевдонима, основанный на решении Тодда Ходеса ​​

alias mtargets='make -qp | awk -F":" "/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split(\$1,A,/ /);for(i in A)print A[i]}"'
3 голосов
/ 06 февраля 2013

Здесь есть очень хорошее решение с магией sed и egrep: https://gist.github.com/pvdb/777954

3 голосов
/ 08 июля 2011

Это даст хороший вывод:

make -pn | perl -F: -ane 'print "$F[0]\n" if /^\w+\s*:/' | sort
2 голосов
/ 06 марта 2011

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

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

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

...