Как вы получаете список целей в make-файле?


202

Я немного использовал 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 .

В любом случае, я немного взломал, чтобы извлечь цели из make-файла, который вы можете включить в make-файл.

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

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

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

2
Я быстро читаю ответы, которые интересны, но до сих пор для себя я предпочитаю сохранять их простыми, простыми и переносимыми, используя псевдоним (в моем .bashrc): alias makefile-targets='grep "^[^#[:space:]].*:" Makefile' чаще всего мне просто нужно проверить текущий make-файл, и расширение bash расширяется мой псевдоним.
RockyRoad


4
Это слишком просто grep : Makefile:?
cibercitizen1

Ответы:


130

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

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

Любопытно, что в GNU makeнет возможности перечислять только имена целей, определенных в make-файле. -pОпция производит вывод , который включает в себя все цели, но хоронит их в много другой информации.

Поместите следующее правило в make-файл для GNU, makeчтобы реализовать именованную цель, listкоторая просто перечисляет все имена целей в алфавитном порядке - то есть: invoke asmake list :

.PHONY: list
list:
    @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$'

Важно : вставив это, убедитесь, что последняя строка имеет ровно 1 фактический символ табуляции. (пробелы не работают) .

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

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

  • ,PHONY: list
    • объявляет список целей фальшивой целью, т.е. не ссылающейся на файл , поэтому его рецепт должен вызываться безоговорочно
  • $(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null

    • Вызывается makeснова, чтобы распечатать и проанализировать базу данных, полученную из make-файла:
      • -p печатает базу данных
      • -Rr подавляет включение встроенных правил и переменных
      • -qтолько проверяет текущее состояние цели (не переделывая ничего), но это само по себе не препятствует выполнению команд рецепта во всех случаях; следовательно:
      • -f $(lastword $(MAKEFILE_LIST))гарантирует, что тот же make-файл нацелен как на исходный вызов, независимо от того, был ли он нацелен неявно или явно -f ....
        Предостережение : это сломается, если ваш make-файл содержит 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, как рекомендуется на manстранице.
  • -v RS=

    • Это идиома awk, которая разбивает ввод на блоки непрерывных непустых строк.
  • /^# File/,/^# Finished Make data base/
    • Соответствует диапазону строк в выходных данных, которые содержат все цели (истинно для GNU make 3.82) - ограничивая синтаксический анализ этим диапазоном, нет необходимости иметь дело с ложными срабатываниями из других выходных секций.
  • if ($$1 !~ "^[#.]")
    • Выборочно игнорирует блоки:
      • # ... игнорирует нецелевые объекты, чьи блоки начинаются с # Not a target:
      • . ... игнорирует специальные цели
    • Все остальные блоки должны начинаться со строки, содержащей только имя явно определенной цели, за которой следует :
  • egrep -v -e '^[^[:alnum:]]' -e '^$@$$' удаляет нежелательные цели из вывода:
    • '^[^[:alnum:]]'... исключает скрытые цели, которые, по соглашению, являются целями, которые не начинаются ни с буквы, ни с цифры.
    • '^$@$$'... исключает listсаму цель

Запуск make listзатем печатает все цели, каждая на своей линии; xargsвместо этого вы можете создать список, разделенный пробелами.


Это отличный ответ, однако, как бы я получил описание для каждой задачи? В настоящее время я храню это как комментарий выше определения задачи. Не уверен, возможно ли включить его в список таким же образом, как rake --tasksэто?
Петр Кучинский

1
@PiotrKuczynski: Интересный вопрос, но я предлагаю вам опубликовать его как новый вопрос (указывая на этот вопрос для справки).
mklement0

«К сожалению, GNU make не предлагает прямой возможности просто распечатать базу данных». Там есть -nвариант.
Bulletmagnet

@Bulletmagnet: Назначение -nопции - «Распечатать команды, которые будут выполнены ...» - другими словами: функция пробного запуска. Также не то что ваша цитата отсутствует italicization слова просто : make -pсам по себе делает печать базы данных, но неизменно также выполняет задачу по умолчанию ; руководство рекомендует неуклюже make -p -f/dev/nullизбегать этого.
mklement0

1
Также будет перечислены любые цели .PHONY, поэтому убедитесь, что у вас их нет.PHONY: *
tekumara

189

Под Bash (по крайней мере) это можно сделать автоматически с завершением табуляции:

make spacetabtab


1
Протестировано: bash - версия = 4.2.45 (1) -релиз. make --version = 3,81.
Нобар

53
+1, но учтите, что это не функция bash , а зависит от вашей платформы . Платформы делятся на три категории: те, где это завершение установлено по умолчанию (например, Debian 7, Fedora 20), те, где вы можете установить его по желанию (например, Ubuntu 14, с . /etc/bash_completion), и те, которые вообще не поддерживают его. (например, OSX 10.9)
mklement0

8
он работает на OS X 10.10 (не с bash, а с zsh).
Флориан Освальд

4
Отличный совет, но также нуждается в bash-completionупаковке. Найдено в Fedora, RHEL, Gentoo и т. Д.
NoelProf

4
Это не работает с программно созданными целевыми объектами AFAICT, например$(RUN_TARGETS): run-%: ...
Matthias

32

Это, очевидно, не будет работать во многих случаях, но если ваш 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

Есть ли у вас возможность включить в свой CMakeList, чтобы получить это? Я получил make-файл, сгенерированный CMake, и у меня нет цели псевдо-помощи
Xavier T.

Нет. На OSX по крайней мере с недавним CMake (я на самом деле использую ночные программы, но я полагаю, что когда я писал это, я использовал 3.3), просто запустите, touch CMakeLists.txt && cmake . && make helpи это должно работать. Я могу только догадываться, что вы используете древний cmake или не используете генератор Unix Makefiles?
Timmmm

Я использую CMake 3.6.2 с генератором Unix на Windows. Я покопаюсь в поисках объяснения, потому что оно кажется удобным.
Ксавье Т.

26

Я объединил эти два ответа: https://stackoverflow.com/a/9524878/86967 и https://stackoverflow.com/a/7390874/86967 и сделал несколько экранировок, чтобы их можно было использовать из make-файла.

.PHONY: no_targets__ list
no_targets__:
list:
    sh -c "$(MAKE) -p no_targets__ | awk -F':' '/^[a-zA-Z0-9][^\$$#\/\\t=]*:([^=]|$$)/ {split(\$$1,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

10
Я также (недавно) обнаружил, что завершение табуляции в Bash будет перечислять доступные цели.
Нобар

1
+1 за отличный подход, но можно сделать несколько улучшений: (а) явное указание sh -c "…"не нужно, потому что это то, что makeпо умолчанию используется для вызова команд рецепта; (б) используемая вами команда слишком упрощена, что приводит к ложным срабатываниям (как вы заметили); (c) если вы добавите к команде префикс @, она не будет передана на стандартный вывод перед выполнением, что устраняет необходимость использования -sпри вызове.
mklement0

1
есть гораздо более простая цель make, которую вы можете добавить: list: cat Makefile | grep "^ [Az]" | awk '{print $$ 1}' | sed "s /: // g | sort"
thamster

2
Подход кошка / седь терпит неудачу на нескольких уровнях. Он не раскрывает переменные, а также не может перечислить цели, которые являются результатом включения других файлов.
Трой Дэниелс

1
@ mklement0: я предпочитаю использовать make -s(через псевдоним Bash), а не префиксировать команды в make-файле с помощью @. В некоторых случаях это @может быть полезно, особенно в качестве префикса для echoкоманд (когда отображение команды будет избыточным), но в целом я не люблю его использовать. Таким образом, я могу видеть «рецепты», когда мне нужно ( не используя -s), но обычно нет. Вот соответствующая документация: Руководство по GNU Make, 5.2 Повторение рецепта .
Нобар

14

Если у вас есть makeустановленное завершение bash , скрипт завершения определит функцию _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

3
Полезно, но обратите внимание, что не на всех платформах есть сценарий /etc/bash_completionи / или функция _make_target_extract_script- вы, кажется, находитесь на Ubuntu> 12. Если вы нацеливаетесь /usr/share/bash-completion/completions/makeвместо этого, ваш подход будет работать на дополнительных платформах, таких как Fedora 20. Существуют (более старые) платформы, которые имеют этот файл, но не функция (например, Debian 7 и Ubuntu 12); другие платформы, такие как OSX, вообще не идут с завершением табуляции make. Возможно, было бы полезно опубликовать фактическое определение функции.
mklement0

1
Спасибо за ваш комментарий. Это высоко ценится. Да, я проверял это на Ubuntu 14.04
hek2mgl

11

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

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

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

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

.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: \(.*\) # \(.*\)/\1 \2/' | expand -t20

Который даст

$ make help
target1             Target 1 help text
target2             Target 2 help text

...
help                Generate list of targets with descriptions

Вы также можете найти краткий пример кода в этом и здесь .

Опять же, это не решает проблему перечисления всех целей в Makefile. Например, если у вас есть большой Makefile, который, возможно, был сгенерирован или кто-то другой написал, и вы хотите быстрый способ перечислить свои цели, не просматривая его, это не поможет.

Однако, если вы пишете Makefile и вам нужен способ генерировать текст справки согласованным, самодокументируемым способом, этот метод может оказаться полезным.


Это отличная техника - приятная и простая, но также дает описания!
Брайан Бернс

Отличная техника. Я немного изменил это, чтобы использовать echoкоманду в качестве описания команды ( stackoverflow.com/a/52059487/814145 ).
Penghe Geng

@PengheGeng Спасибо за пост. Я хочу прояснить, что @echo "Target 1"это просто заполнитель, а не «команда echo description». Сгенерированный текст справки не приходит от @echo. В реальном Makefile они echoбудут заменены командой build или чем-то подобным. Я отредактирую пост, чтобы сделать это более понятным.
JSP

5

Мой любимый ответ на это был опубликован Крисом Дауном в Unix & Linux Stack Exchange. Я процитирую

Вот как модуль завершения bash makeполучает свой список:

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

Он выводит список целей, разделенных символом новой строки, без разбивки на страницы.

Пользователь Brainstone предлагает использовать трубопровод sort -uдля удаления повторяющихся записей:

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

Источник: Как перечислить все цели в make? (Unix & Linux SE)


4

Ответ @ nobar показывает, как использовать завершение табуляции для вывода списка целей make-файла .

  • Это прекрасно работает для платформ, которые предоставляют эту функциональность по умолчанию (например, Debian, Fedora ).

  • На других платформах (например, Ubuntu ) вы должны явно загрузить эту функциональность, как подразумевается в ответе @ hek2mgl :

    • . /etc/bash_completion устанавливает несколько функций завершения табуляции, в том числе для make
    • Кроме того, чтобы установить только вкладку завершения для make:
      • . /usr/share/bash-completion/completions/make
  • Для платформ, которые вообще не предлагают эту функциональность , таких как OSX , вы можете использовать следующие команды (адаптированные здесь ) для ее реализации:
_complete_make() { COMPREPLY=($(compgen -W "$(make -pRrq : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($1 !~ "^[#.]") {print $1}}' | egrep -v '^[^[:alnum:]]' | sort | xargs)" -- "${COMP_WORDS[$COMP_CWORD]}")); }
complete -F _complete_make make
  • Примечание: это не так сложно, как функциональность дополнения табуляции, которая поставляется с дистрибутивами Linux: в первую очередь это неизменно предназначается для make-файла в текущем каталоге , даже если командная строка предназначается для другого make-файла с -f <file>.

4

Сосредоточившись на простом синтаксисе для описания цели создания и имея чистый вывод, я выбрал этот подход:

help:
    @grep -B1 -E "^[a-zA-Z0-9_-]+\:([^\=]|$$)" Makefile \
     | grep -v -- -- \
     | sed 'N;s/\n/###/' \
     | sed -n 's/^#: \(.*\)###\(.*\):.*/\2###\1/p' \
     | column -t  -s '###'


#: Starts the container stack
up: a b
  command

#: Pulls in new container images
pull: c d 
    another command

make-target-not-shown:

# this does not count as a description, so leaving
# your implementation comments alone, e.g TODOs
also-not-shown:

Так что, рассматривая вышесказанное как Makefile и запустив его, вы получите что-то вроде

> make help
up          Starts the container stack
pull        Pulls in new container images

Пояснение к цепочке команд:


Очень хорошее решение. Я использовал это в течение нескольких лет: awk -F ':|##' '/^[^\t].+:.*##/ { printf "\033[36mmake %-28s\033[0m -%s\n", $$1, $$NF }' $(MAKEFILE_LIST) | sort с ##комментарием перед той же строкой, что и цель. Но я думаю, что ваше решение позволяет до удобочитаемости.
Торок

Makefile состоит из первых двух строк отчетов grep: parentheses not balancedо моей машине OSX 10.15.
Малкольм Крам

@ Извините, извините, моя ошибка. Спасибо за указание на это. Починил это. make требует экранирования знаков доллара, которые не должны начинаться с имен переменных.
Ричард Кифер

Обратите внимание, StackOverflow преобразует вкладки в пробелы при отображении разделов кода выше, но Make-файлы требуют вкладки. Вы можете отредактировать сообщение, а затем скопировать разделы, чтобы вкладки были сохранены.
Ричард Кифер

2

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

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

.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
  • выведите имя файла
  • строки 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

1

Это было полезно для меня, потому что я хотел видеть цели сборки, требуемые (и их зависимости) целью make. Я знаю, что создание целей не может начинаться с "." персонаж. Я не знаю, какие языки поддерживаются, поэтому я использовал скобочные выражения egrep.

cat Makefile | egrep "^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$"

1

Это далеко не чисто, но сделал работу для меня.

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что это внутреннее правило


1

Это изменение очень полезного ответа jsp ( https://stackoverflow.com/a/45843594/814145 ). Мне нравится идея получить не только список целей, но и их описание. Makefile jsp помещает описание в качестве комментария, который, как я обнаружил, часто повторяется в команде echo description the description. Поэтому вместо этого я извлекаю описание из команды 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 \1\t\2/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 ответ «s, только Фиктивные цели могут быть перечислены, которые могут или не могут работать для вашего случая
  • Кроме того, в нем перечислены только те цели PHONY, которые имеют команду echoили :в качестве первой команды рецепта. :означает «ничего не делать». Я использую это здесь для тех целей, которые не нужны эхо, такие какall цель выше.
  • Есть дополнительная хитрость для helpцели, чтобы добавить «:» в make helpвывод.

0

Еще один дополнительный ответ на выше.

протестировано на MacOSX с использованием только cat и awk на терминале

cat Makefile | awk '!/SHELL/ && /^[A-z]/ {print $1}' | awk '{print substr($0, 1, length($0)-1)}'

будет вывод файла make, как показано ниже:

target1

target2

target3

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

объяснение

кошка - выплевывает содержимое

| - труба анализирует вывод на следующий awk

awk - запускает регулярное выражение, исключая "shell" и принимая только строки "Az", затем выводит первый столбец за $ 1

awk - еще раз удаляет последний символ ":" из списка

это грубый вывод, и вы можете делать более интересные вещи с помощью только AWK. Старайтесь избегать sed, поскольку он не так согласован в вариантах BSD, т.е. некоторые из них работают на * nix, но не работают на BSD, таких как MacOSX.

Больше

Вы должны иметь возможность добавить это (с изменениями) в файл для make , в папку завершения bash по умолчанию /usr/local/etc/bash-completion.d/, что означает, что когда вы «сделаете вкладку вкладки » ... она завершит цели основаны на сценарии с одним вкладышем.


Вы также можете использовать make -qp вместо cat. так что он станет make -qp | awk '/: / &&! /: = / && / ^ [Az] / &&! / PATH / &&! / DISPLAY / &&! / TERM_SESSION / &&! / USER_TEXT_ENCODING / &&! / Makefile / {печать подстроки ($ 0, 1 , длина ($ 0) -1) | "sort -u"} '
Джимми М.Г. Лим

0

Я обычно делаю:

grep install_targets Makefile

Это вернулось бы с чем-то вроде:

install_targets = install-xxx1 install-xxx2 ... etc

надеюсь, это поможет


0

Для сценария Bash

Вот очень простой способ сделать это на bashоснове комментария @ cibercitizen1 выше :

grep : Makefile | awk -F: '/^[^.]/ {print $1;}'

Смотрите также более авторитетный ответ от @ Marc.2377, в котором говорится, как это makeделает модуль завершения Bash .


-4

не уверен, почему предыдущий ответ был таким сложным:

list:
    cat Makefile | grep "^[A-z]" | awk '{print $$1}' | sed "s/://g" 

8
Предыдущий ответ настолько сложен, поскольку он охватывает все сценарии , что ваш ответ не распространяется на : (а) включение целей , определенных с помощью переменных (например, $(SHELLS): ...), (б) включение целей , которые начинаются с цифрой, (с) не- включение определений переменных , (d) нацеливание на соответствующий make-файл, если он makeбыл указан с явным путем make-файла. (а) является решающим недостатком: даже если вы надежно нацелены на правильный make-файл, анализ необработанного файла не будет работать в общем случае из-за отсутствия расширения переменной.
mklement0

6
Как и в сторону, вновь осложнено: ваша команда может быть упрощена к следующему - но главное заключается в том , что это не достаточно прочным : awk -F: '/^[A-z]/ {print $$1}' Makefile. Наконец, в значительной степени академический момент: использование, [A-z]а не [:alpha:]означает, что вы пропустите цели, начинающиеся с иностранного символа, такого как á.
mklement0

@ mklement0 Ваша первая команда awk работает хорошо, и до сих пор является самой простой, хотя использование [: alpha:], кажется, почему-то нарушает ее - она ​​пропускает некоторые цели в тестовом файле.
Брайан Бернс

@ bburns.km: Мое плохое: я должен был сказать, [[:alpha:]]а не [:alpha:]( [:alpha:]представляет набор букв с учетом локали внутри класса символов ( [...]), следовательно, эффективная потребность в двойном [[ / ]].
mklement0

4
Почему этот ответ такой сложный? Вам удалось собрать несколько бесполезных грехов в этом коротком фрагменте. awk -F: '/^[A-Za-z]/ { print $$1 }' Makefileиспользует один процесс и, мы надеемся, более правильное регулярное выражение (хотя вы, конечно, могли бы иметь цели с подчеркиванием, цифрами и т. д., как отмечалось в предыдущих комментариях)
tripleee
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.