我使用过一些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。

不管怎样,我做了一个小hack来从makefile中提取目标,你可以将它包含在makefile中。

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

它会给你一个已定义目标的列表。这只是一个开始——例如,它并没有过滤掉依赖关系。

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

当前回答

要扩展@jsp给出的答案,甚至可以使用$(eval)函数计算帮助文本中的变量。

下面提议的版本增强了以下属性:

将扫描任何生成文件(甚至包括在内) 是否会在帮助注释中引用扩展活动变量 为真实目标添加文档锚(前缀为# TARGETDOC:) 添加列标头

所以要记录,请使用这种形式:

RANDOM_VARIABLE := this will be expanded in help text

.PHONY: target1 # Target 1 help with $(RANDOM_VARIABLE)
target1: deps
    [... target 1 build commands]

# TARGETDOC: $(BUILDDIR)/real-file.txt # real-file.txt help text
$(BUILDDIR)/real-file.txt:
    [... $(BUILDDIR)/real-file.txt build commands]

然后,在你的makefile文件的某处:

.PHONY: help # Generate list of targets with descriptions
help:
    @# find all help in targets and .PHONY and evaluate the embedded variables
    $(eval doc_expanded := $(shell grep -E -h '^(.PHONY:|# TARGETDOC:) .* #' $(MAKEFILE_LIST) | sed -E -n 's/(\.PHONY|# TARGETDOC): (.*) # (.*)/\2  \3\\n/'p | expand -t40))
    @echo
    @echo ' TARGET   HELP' | expand -t40
    @echo ' ------   ----' | expand -t40
    @echo -e ' $(doc_expanded)'

其他回答

注意:这个答案已经更新到GNU make v4.3仍然可以工作——如果你遇到什么问题,请告诉我们。

本文试图改进Brent Bradburn的伟大方法,如下所示:

使用更健壮的命令来提取目标名称,这有望防止任何误报(还消除了不必要的sh -c) 并不总是以当前目录中的makefile为目标;尊重使用-f <file>显式指定的makefile 不包括隐藏目标——按照惯例,这些目标的名称既不是以字母开头,也不是以数字开头 只对付一个假目标 使用@作为命令的前缀,防止命令在执行前被回显


奇怪的是,GNU make没有列出makefile中定义的目标名称的特性。虽然-p选项生成包含所有目标的输出,但它将这些目标隐藏在许多其他信息中,并执行默认目标(可以使用-f/dev/null来抑制)。

将下面的规则放在一个makefile中,让GNU make实现一个目标命名列表,简单地按字母顺序列出所有目标名称-即:调用为make列表:

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

重要提示:在粘贴此文件时,确保最后一行缩进了恰好1个实际的制表符字符。(空格无效)。

Note that sorting the resulting list of targets is the best option, since not sorting doesn't produce a helpful ordering in that the order in which the targets appear in the makefile is not preserved. Also, the sub-targets of a rule comprising multiple targets are invariably output separately and will therefore, due to sorting, usually not appear next to one another; e.g., a rule starting with a z: will not have targets a and z listed next to each other in the output, if there are additional targets.

规则解释:

.PHONY: list declares target list a phony target, i.e., one not referring to a file, which should therefore have its recipe invoked unconditionally LC_ALL=C makes sure that make's output in in English, as parsing of the output relies on that.Tip of the hat to Bastian Bittorf $(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null Invokes make again in order to print and parse the database derived from the makefile: -p prints the database -Rr suppresses inclusion of built-in rules and variables -q only tests the up-to-date-status of a target (without remaking anything), but that by itself doesn't prevent execution of recipe commands in all cases; hence: -f $(lastword $(MAKEFILE_LIST)) ensures that the same makefile is targeted as in the original invocation, regardless of whether it was targeted implicitly or explicitly with -f .... Caveat: This will break if your makefile contains include directives; to address this, define variable THIS_FILE := $(lastword $(MAKEFILE_LIST)) before any include directives and use -f $(THIS_FILE) instead. : is a deliberately invalid target that is meant to ensure that no commands are executed; 2>/dev/null suppresses the resulting error message. Note: This relies on -p printing the database nonetheless, which is the case as of GNU make 3.82. Sadly, GNU make offers no direct option to just print the database, without also executing the default (or given) task; if you don't need to target a specific Makefile, you may use make -p -f/dev/null, as recommended in the man page. -v RS= This is an awk idiom that breaks the input into blocks of contiguous non-empty lines. /(^|\n)# Files(\n|$$)/,/(^|\n)# Finished Make data base/ Matches the range of lines in the output that contains all targets, across paragraphs - by limiting parsing to this range, there is no need to deal with false positives from other output sections. Note: Between make versions 3.x and 4.3, paragraph structuring in make's output changed, so (^|\n) / (\n|$$) ensures that the lines that identify the start and the end of the cross-paragraph range of lines of interest are detected irrespective of whether they occur at the start or inside / at the end of a paragraph. if ($$1 !~ "^[#.]") Selectively ignores blocks: # ... ignores non-targets, whose blocks start with # Not a target: . ... ignores special targets All other blocks should each start with a line containing only the name of an explicitly defined target followed by : egrep -v -e '^[^[:alnum:]]' -e '^$@$$' removes unwanted targets from the output: '^[^[:alnum:]]' ... excludes hidden targets, which - by convention - are targets that start neither with a letter nor a digit. '^$@$$' ... excludes the list target itself

然后运行make list,打印所有目标,每个目标在自己的行上;您可以通过管道连接到xargs来创建一个以空格分隔的列表。

专注于描述make目标的简单语法,并有一个干净的输出,我选择了以下方法:

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

命令链的解释:

First, grep all targets and their preceeding line, see https://unix.stackexchange.com/a/320709/223029. Then, get rid of the group separator, see https://stackoverflow.com/a/2168139/1242922. Then, we collapse each pair of lines to parse it later, see https://stackoverflow.com/a/9605559/1242922. Then, we parse for valid lines and remove those which do not match, see https://stackoverflow.com/a/8255627/1242922, and also give the output our desired order: command, then description. Lastly, we arrange the output like a table.

我把上面提到的几个答案编译成这个,它也可以为每个目标生成一个很好的描述,它也适用于有变量的目标。

Makefile示例:

APPS?=app1 app2

bin: $(APPS:%=%.bin)
    @# Help: A composite target that relies only on other targets

$(APPS:%=%.bin): %.bin:
    @# Help: A target with variable name, value = $*

test:
    @# Help: A normal target without variables

# A target without any help description
clean:

# A hidden target
.hidden:

help:
    @printf "%-20s %s\n" "Target" "Description"
    @printf "%-20s %s\n" "------" "-----------"
    @make -pqR : 2>/dev/null \
        | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' \
        | sort \
        | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' \
        | xargs -I _ sh -c 'printf "%-20s " _; make _ -nB | (grep -i "^# Help:" || echo "") | tail -1 | sed "s/^# Help: //g"'

示例输出:

$ make help
Target               Description
------               -----------
app1.bin             A target with variable name, value = app1
app2.bin             A target with variable name, value = app2
bin                  A composite target that relies only on other targets
clean
test                 A normal target without variables

它是如何工作的:

make help目标的顶部部分与mklement0在这里发布的工作完全相同——如何在makefile中获得目标列表?

在获得目标列表之后,它运行make <target> -nB作为每个目标的演练,并解析以@# Help:开头的最后一行,用于目标的描述。或者一个空字符串被打印在一个格式化好的表格中。

正如你所看到的,变量甚至在描述中进行了扩展,这在我的书中是一个巨大的奖励:)。

如果为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

这是对jsp非常有用的回答(https://stackoverflow.com/a/45843594/814145)的修改。我喜欢这个想法,不仅要得到目标的列表,还要得到他们的描述。jsp的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 \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的答案相同,只能列出PHONY目标,这可能适用于您的情况,也可能不适用 此外,它只列出那些有echo或:命令作为recipe的第一个命令的PHONY目标。:表示“什么都不做”。我在这里将它用于那些不需要回声的目标,比如上面所有的目标。 帮助目标还有一个额外的技巧,就是在make帮助输出中添加“:”。