我已经使用了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/[email protected]/msg06434.html。
无论如何,我几乎没有从makefile中提取目标,你可以将其包含在makefile中。
list:
@grep '^[^#[:space:]].*:' Makefile
它将为您提供已定义目标的列表。这只是一个开始 - 例如,它不会过滤掉依赖项。
> make list
list:
copy:
run:
plot:
turnin:
这是尝试改进@nobar's great approach如下:
sh -c
)-f <file>
明确指定的makefile@
为命令添加前缀,以防止它在执行前被回显奇怪的是,GNU make
没有列出makefile中定义的目标名称的功能。 -p
选项生成包含所有目标的输出,但将其隐藏在许多其他信息中。
将以下规则放在GNU make
的makefile中,以实现一个名为list
的目标,该目标只是按字母顺序列出所有目标名称 - 即:调用make list
:
.PHONY: list
list:
@$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$'
重要说明:粘贴此内容时,请确保最后一行缩进1个实际的tab char。 (空格不起作用)。
请注意,对结果目标列表进行排序是最佳选择,因为不排序不会产生有用的排序,因为不保留目标在makefile中出现的顺序。
此外,包含多个目标的规则的子目标总是单独输出,因此,由于分类,通常不会彼此相邻;例如,如果有其他目标,则以a z:
开头的规则将不会在输出中将目标a
和z
列在彼此旁边。
规则说明:
PHONY: list
声明目标列表伪目标,即不引用文件的目标,因此应无条件地调用其配方$(MAKE) -prRn -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null
再次调用make
以打印和解析从makefile派生的数据库:
-p
打印数据库
-Rr
禁止包含内置规则和变量
-q
只测试目标的最新状态(不重新制作任何东西),但这本身并不妨碍在所有情况下执行配方命令;因此:
-f $(lastword $(MAKEFILE_LIST))
确保在原始调用中定位相同的makefile,无论它是使用-f ...
隐式还是显式定向。
警告:如果你的makefile包含include
指令,这将会中断;为了解决这个问题,在任何THIS_FILE := $(lastword $(MAKEFILE_LIST))
指令之前定义变量include
并使用-f $(THIS_FILE)
代替。
:
是故意无效的目标,旨在确保不执行任何命令; 2>/dev/null
抑制产生的错误消息。注意:这依赖于-p
打印数据库,这是GNU make 3.82的情况。遗憾的是,GNU make没有提供直接打印数据库的选项,也没有执行默认(或给定)任务;如果您不需要定位特定的Makefile,可以按照make -p -f/dev/null
页面中的建议使用man
。-v RS=
这是一个awk成语,它将输入分解为连续的非空行块。/^# File/,/^# Finished Make data base/
匹配输出中包含所有目标的行范围(GNU make 3.82时为true) - 通过将解析限制到此范围,不需要处理来自其他输出节的误报。if ($$1 !~ "^[#.]")
选择性地忽略块:
#
...忽略非目标,其阻挡以# Not a target:
开头
.
......无视特殊目标
所有其他块应各自以一行开头,该行仅包含明确定义的目标的名称,后跟:
egrep -v -e '^[^[:alnum:]]' -e '^$@$$'
从输出中删除不需要的目标:
'^[^[:alnum:]]'
......排除隐藏的目标,按照惯例,这些目标既不是字母也不是数字。
'^$@$$'
......排除了list
目标本身然后运行make list
打印所有目标,每个目标都在自己的行上;您可以通过管道传输到xargs
来创建一个以空格分隔的列表。
这里有很多可行的解决方案,但正如我喜欢说的那样,“如果它值得做一次,那就值得再做一次。”我做了upvote sugestion使用(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 =
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
这是对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
笔记:
echo
或:
命令的PHONY目标作为配方的第一个命令。 :
的意思是“什么都不做”。我在这里用它来表示那些不需要回声的目标,例如上面的all
目标。help
目标还有一个额外的技巧,即在make help
输出中添加“:”。上面的另一个补充答案。
在MacOSX上仅使用cat和awk在终端上测试
cat Makefile | awk '!/SHELL/ && /^[A-z]/ {print $1}' | awk '{print substr($0, 1, length($0)-1)}'
将输出make文件,如下所示:
目标1
TARGET2
target3
在Makefile中,它应该是相同的语句,确保使用$$变量而不是$ variable来转义变量。
说明
猫 - 吐出内容
| - pipe将输出解析为下一个awk
awk - 运行正则表达式,不包括“shell”,只接受“A-z”行,然后输出$ 1第一列
awk - 再次从列表中删除最后一个字符“:”
这是一个粗略的输出,你可以用AWK做更多时髦的东西。尽量避免使用sed,因为它在BSD变体中并不一致,即一些在* nix上工作但在像MacOSX这样的BSD上失败。
更多
您应该能够将此(带有修改)添加到make文件中,默认为bash-completion文件夹/usr/local/etc/bash-completion.d/,这意味着当您“制作选项卡选项卡”时,它将完成基于一个班轮脚本的目标。
不确定为什么以前的答案是如此复杂:
list:
cat Makefile | grep "^[A-z]" | awk '{print $$1}' | sed "s/://g"
在Bash(至少)下,这可以通过选项卡完成自动完成:
make(space)(tab)(tab)
我将这两个答案结合起来: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
这显然在许多情况下不起作用,但如果你的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
如果你安装了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
作为mklement0 points out,GNU-make缺少列出所有Makefile目标的功能,他的回答和其他提供了实现此目的的方法。
然而,原帖还提到了rake,其任务切换与仅列出rakefile中的所有任务略有不同。 Rake只会为您提供具有相关描述的任务列表。没有描述的任务will not be listed。这使作者既能提供自定义帮助描述,又能省略某些目标的帮助。
如果你想模仿rake的行为,你提供descriptions for each target,有一个简单的技巧:在你想要列出的每个目标的注释中嵌入描述。
您可以将描述放在目标旁边,或者像往常一样,将其放在目标上方的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
您还可以在this gist和here中找到一个简短的代码示例。
同样,这并没有解决在Makefile中列出所有目标的问题。例如,如果你有一个可能生成的大型Makefile或其他人写的,你想要一个快速的方法来列出它的目标而不需要深入研究它,这将无济于事。
但是,如果您正在编写Makefile,并且希望以一致的自我文档方式生成帮助文本,则此技术可能很有用。
@nobar's answer帮助显示如何使用制表符完成列出makefile的目标。
. /etc/bash_completion
安装了几个tab-completion函数,包括make
的函数
或者,要仅安装make
的制表符完成:
. /usr/share/bash-completion/completions/make
_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
-f <file>
定位不同的makefile也是如此。这个对我有帮助,因为我想通过make目标看到所需的构建目标(及其依赖项)。我知道制作目标不能以“。”开头。字符。我不知道支持哪种语言,所以我选择了egrep的括号表达式。
cat Makefile | egrep "^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$"
这对我来说远非干净,但是做了这项工作。
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
这是一个内部规则