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

当前回答

这里有很多可行的解决方案,但正如我喜欢说的,“如果值得做一次,就值得再做一次。” 我确实赞成使用(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

其他回答

专注于描述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.

这里有很多可行的解决方案,但正如我喜欢说的,“如果值得做一次,就值得再做一次。” 我确实赞成使用(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

我用这个:

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

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

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

我把这两个答案结合起来: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 -p 2&>/dev/null | grep -A 100000 "# Files" | grep -v "^$" | grep -v "^\(\s\|#\|\.\)" | grep -v "Makefile:" | cut -d ":" -f 1

我使用make -p来转储内部数据库,沟渠stderr,使用快速和肮脏的grep -A 100000来保持输出的底部。然后我用几个grep -v来清除输出,最后使用cut来获得冒号之前的内容,即目标。

这对于我的大多数makefile上的助手脚本来说已经足够了。

编辑:添加grep -v Makefile,这是一个内部规则