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

当前回答

@nobar的回答很有帮助地展示了如何使用TAB补全来列出makefile的目标。

这对于默认提供此功能的平台(例如Debian、Fedora)非常有效。 在其他平台上(例如Ubuntu),你必须显式加载这个功能,正如@hek2mgl的回答所暗示的那样: . /etc/bash_completion安装几个制表符补全函数,包括make函数 或者,为make只安装制表符补全: . /usr/share/bash-completion /完成/

对于根本不提供这个功能的平台,比如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发行版附带的制表符补全功能那么复杂:最值得注意的是,它总是以当前目录中的makefile为目标,即使命令行以-f <file>为目标的另一个makefile也是如此。

其他回答

我通常这样做:

grep install_targets制作文件

它会返回如下内容:

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

我希望这对你们有帮助

@nobar的回答很有帮助地展示了如何使用TAB补全来列出makefile的目标。

这对于默认提供此功能的平台(例如Debian、Fedora)非常有效。 在其他平台上(例如Ubuntu),你必须显式加载这个功能,正如@hek2mgl的回答所暗示的那样: . /etc/bash_completion安装几个制表符补全函数,包括make函数 或者,为make只安装制表符补全: . /usr/share/bash-completion /完成/

对于根本不提供这个功能的平台,比如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发行版附带的制表符补全功能那么复杂:最值得注意的是,它总是以当前目录中的makefile为目标,即使命令行以-f <file>为目标的另一个makefile也是如此。

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

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默认情况下不支持此功能,其他回答已经展示了如何自动提取可能目标的列表。

然而,如果您想对清单有更多的控制,而不产生任何副作用(例如使用. phony目标标记文档,这阻止了使用目标名称作为Make用来决定需要重建哪些目标的实际文件的逻辑),您可以为文档发明自己的语法。我更喜欢这样使用###:

CPUS ?= $(shell nproc)
MAKEFLAGS += -j $(CPUS) -l $(CPUS) -s

# Basic paths
PREFIX  ?= usr
BINDIR  ?= $(PREFIX)/bin
ETCDIR  ?= etc
MANDIR  ?= $(PREFIX)/share/man
# ...

### help: Show help message (default target)
# use "help" as the default target (first target in the Makefile)
.PHONY: help
help:
    @printf "%s\n\n" "make: List of possible targets:"
    @grep '^### .*:' $(lastword $(MAKEFILE_LIST)) | sed 's/^### \([^:]*\): \(.*\)/\1:\t\2/' | column -ts "$$(printf '\t')"

### install: Install all files in $PREFIX (used by debian binary package build scripts)
install:
    install -D -o root -g root -m 755 ...
    ...

### release: Increase package version number
release:
    debchange --release

(像往常一样,缩进文件必须精确地从一个制表器开始,但stackoverflow不能正确地再现该细节。)

输出如下所示:

$ make
make: List of possible targets:

help:      Show help message (default target)
install:   Install all files in $PREFIX (used by debian binary package build scripts)
release:   Increase package version number

This works because only lines starting with ### and having a : character are considered as the documentation to output. Note that this intentionally does not extract the actual target name but fully trusts the documentation lines only. This allows always emitting correct output for very complex Makefile tricks, too. Also note that this avoids needing to put the documentation line on any specific position relative to actual rule. I also intentionally avoid sorting the output because the order of output can be fully controlled from the Makefile itself simply by listing the documentation lines in preferred order.

显然,您可以发明任何其他您喜欢的语法,甚至可以做一些

### en: install: Install all files in $PREFIX
### fi: asennus: asenna kaikki tiedostot hakemistoon $PREFIX

并且只打印与当前语言环境匹配的行,以支持多种语言,并具有别名来本地化目标名称:

.PHONY: asennus
asennus: install

最重要的问题是为什么要列出目标?您想要实际的文档还是某种调试信息?

注意:这个答案已经更新到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来创建一个以空格分隔的列表。