我使用过一些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非常有用的回答(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帮助输出中添加“:”。

其他回答

这里有很多可行的解决方案,但正如我喜欢说的,“如果值得做一次,就值得再做一次。” 我确实赞成使用(tab)(tab)的建议,但正如一些人指出的那样,您可能没有补全支持,或者,如果您有许多包含文件,您可能想要一种更简单的方法来知道目标定义在哪里。

我还没有测试下面的子制作…我认为这行不通。我们知道,递归是有害的。

.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 := \)

我喜欢它是因为:

通过包含文件列出目标。 输出原始动态目标定义(用模替换变量分隔符) 在新行上输出每个目标 似乎更清楚了(主观意见)

解释:

MAKEFILE_LIST中的foreach文件 输出文件的名称 包含冒号的Grep行,不缩进,没有注释,也不以句号开头 排除立即赋值表达式(:=) 切、排序、缩进和切规则依赖项(冒号后) 蒙格变量分隔符以防止扩展

样例输出:

 = 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

这显然在很多情况下都不起作用,但如果你的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

@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也是如此。

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

对于讨厌AWK的人来说,为了简单起见,这个精巧的设计适合我:

help:
  make -qpRr $(lastword $(MAKEFILE_LIST)) | egrep -v '(^(\.|:|#|\s|$)|=)' | cut -d: -f1

(对于在Makefile外部使用,只需删除$(最后一个词…)或将其替换为Makefile路径)。

This solution will not work if you have "interesting" rule names but will work well for most simple setups. The main downside of a make -qp based solution is (as in other answers here) that if the Makefile defines variable values using functions - they will still be executed regardless of -q, and if using $(shell ...) then the shell command will still be called and its side effects will happen. In my setup often the side effects of running shell functions is unwanted output to standard error, so I add 2>/dev/null after the make command.