Как вы получаете список целей в 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"