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

当前回答

我个人为我构建的每个Makefile复制粘贴相同的帮助目标。

.SILENT:

.PHONY: help
## This help screen
help:
    printf "Available targets\n\n"
    awk '/^[a-zA-Z\-\_0-9]+:/ { \
        helpMessage = match(lastLine, /^## (.*)/); \
        if (helpMessage) { \
            helpCommand = substr($$1, 0, index($$1, ":")-1); \
            helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \
            printf "%-30s %s\n", helpCommand, helpMessage; \
        } \
    } \
    { lastLine = $$0 }' $(MAKEFILE_LIST)

我也在这个Github要点中保留了它的副本: https://gist.github.com/Olshansk/689fc2dee28a44397c6e31a0776ede30

其他回答

要扩展@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)'

正如mklement0所指出的,GNU-make中缺少列出所有Makefile目标的功能,他的回答和其他回答提供了实现这一点的方法。

然而,最初的帖子也提到了rake,它的任务开关做的事情与仅仅在rakefile中列出所有任务略有不同。Rake只会给您一个有相关描述的任务列表。没有描述的任务将不会被列出。这使得作者既可以提供定制的帮助描述,也可以省略某些目标的帮助。

如果您想模拟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,并且希望以一致的、自记录的方式生成帮助文本,则此技术可能会有用。

我把这两个答案结合起来: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(\$$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

我用这个:

make -npq .DEFAULT 2> /dev/null | \
      awk -v RS= -F: '$1 ~ /^[^#%]+$/ { print $1 }'

它是bash补全脚本功能的一个非常简化的版本。

这可能会产生很多假阳性,但就我的目的而言,我宁愿有假阳性而不是假阴性。

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

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