Как получить список целей в файле 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/[email protected]/msg06434.html.



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



list:
@grep '^[^#[:space:]].*:' Makefile


Это даст вам список определенных целей. Это только начало - он не отфильтровывает зависимости, например.



> make list
list:
copy:
run:
plot:
turnin:
924   12  

12 ответов:

это попытка улучшить @nobar-это следующим образом:

  • использует более надежную команду для извлечения целевых имен, которая, надеюсь, предотвращает любые ложные срабатывания (а также устраняет ненужные sh -c)
  • не всегда нацелен на makefile в настоящее каталог; уважает make-файлы, явно указанные с помощью -f <file>
  • исключает скрытые цели конвенции, это цели, чье имя не начинается ни с буквы, ни с цифры
  • позволяет делать с собой один фиктивной цели
  • префиксы команды с @ чтобы предотвратить его эхо перед исполнением

любопытно, GNU make не имеет функции для перечисления только имена целей, определенных в файле makefile. Элемент -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 фактический символ табуляции. (пробелы делать не работы).

обратите внимание, что сортировка полученный список целей является самым лучшим вариантом, так как не сортировка не дает полезного упорядочения в том порядке, в котором цели отображаются в файле makefile не сохранить.
Кроме того, подцели правила, содержащего несколько целей, неизменно выводятся отдельно и поэтому, из-за сортировки, обычно не появляются рядом друг с другом; например, правило начиная с a z: будет не есть цели a и z listed рядом друг с другом на выходе, если есть дополнительные цели.

объяснение правил:

  • .PHONY: list
    • объявляет список целей фальшивой целью, т. е. одной не со ссылкой на file, который, следовательно, должен иметь свой рецепт вызывается безусловно
  • $(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

Как mklement0 указывает, функция для перечисления всех целей Makefile отсутствует в GNU-make, и его ответ и другие предоставляют способы сделать это.

однако в исходном сообщении также упоминается грабли, которого задачи switch делает что-то немного другое, чем просто перечисление всех задач в rakefile. Рейк даст вам только список задач, которые имеют связанные описания. Задачи без описаний не будет в списке. Это дает автору возможность как предоставлять индивидуальные описания справки, так и опускать справку для определенных целей.

Если вы хотите эмулировать поведение рейка, где вы предоставляете описания для каждой цели есть простой метод для этого: добавьте описаний в комментарии для каждой цели, которую вы хотите перечислить.

вы можете либо поместить описание рядом с целью, либо, как я часто делаю, рядом с фальшивой спецификацией выше цель, вот так:

.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 чтобы получить то, что перед двоеточием, а именно, цели.

этого достаточно для моих вспомогательных скриптов на большинстве моих Makefiles.

правка: добавил grep -v Makefile это внутреннее правило

здесь много работоспособных решений, но, как я люблю говорить, "если это стоит сделать один раз, это стоит сделать снова." Я сделал upvote sugestion для использования (tab) (tab), но, как некоторые отметили, у вас может не быть поддержки завершения, или, если у вас есть много файлов include, вам может потребоваться более простой способ узнать, где определена цель.

Я не проверял ниже с суб-делает...Я думаю, что это не сработает. Как мы знаем, рекурсивные делает считается вредным.

.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). Мне нравится идея получения не только списка целей, но и их описания. jsp'S Makefile помещает описание в качестве комментария, который я нашел часто будет повторяться в команде 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" 

Comments

    Ничего не найдено.