我曾经使用过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。
无论如何,我几乎没有从makefile中提取目标,你可以将它包含在makefile中。
list:
@grep '^[^#[:space:]].*:' Makefile
它将为您提供已定义目标的列表。这只是一个开始 - 例如,它不会过滤掉依赖项。
> make list
list:
copy:
run:
plot:
turnin:
答案 0 :(得分:149)
在Bash(至少)下,这可以通过标签完成自动完成:
make(space)(tab)(tab)
答案 1 :(得分:89)
这是尝试改进@nobar's great approach,如下所示:
sh -c
)-f <file>
@
,以防止它在执行前被回显奇怪的是,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个实际标签字符。(空格不 work)。
请注意,排序生成的目标列表是最佳选择,因为 not 排序不会产生有用的排序,因为目标的顺序出现在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 ...
隐式还是显式定位。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=
/^# File/,/^# Finished Make data base/
if ($$1 !~ "^[#.]")
#
...忽略非目标,其块以# Not a target:
.
...忽略特殊目标:
egrep -v -e '^[^[:alnum:]]' -e '^$@$$'
从输出中删除不需要的目标:
'^[^[:alnum:]]'
...排除隐藏的目标,按惯例,这些目标既不是字母也不是数字。'^$@$$'
...排除list
目标本身运行make list
然后打印所有目标,每个目标都在自己的行上;您可以通过管道xargs
来创建以空格分隔的列表。
答案 2 :(得分:24)
我将这两个答案结合起来: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
答案 3 :(得分:19)
这在很多情况下显然不起作用,但如果您的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
答案 4 :(得分:12)
如果您安装了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
答案 5 :(得分:8)
作为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,并且想要以一致的自我文档方式生成帮助文本,则此技术可能很有用。
答案 6 :(得分:4)
@nobar's answer有助于展示如何使用制表符完成列出制作文件的目标。
这适用于提供此功能的平台默认(例如, Debian,Fedora )。
在其他平台上(例如 Ubuntu ),您必须明确加载此功能,如@hek2mgl's answer所暗示的那样:
. /etc/bash_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。答案 7 :(得分:2)
在bash
中,这是一种非常简单的方法-基于@ cibercitizen1 above的评论:
grep : Makefile | awk -F: '/^[^.]/ {print $1;}'
另请参见@ Marc.2377的more authoritative answer,其中说明了make
的Bash完成模块是如何做到的。
答案 8 :(得分:2)
我最喜欢的答案是Chris Down在Unix&Linux Stack Exchange上发布的。我会报价。
这是
make
的bash完成模块获取其列表的方式:make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'
它打印出以换行符分隔的目标列表,而不进行分页。
用户Brainstone建议通过管道传递到sort -u
来删除重复的条目:
make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}' | sort -u
来源:How to list all targets in make?(Unix&Linux SE)
答案 9 :(得分:1)
将此目标添加到您的 Makefile:
help:
@echo "\nTARGETS:\n"
@make -qpRr | egrep -e '^[a-z].*:$$' | sed -e 's~:~~g' | sort
@echo ""
make -qpRr
= make --question --print-data-base --no-builtin-variables --no-builtin-rules
egrep -e '^[a-z].*:$$'
:搜索以小写开头并以“:”结尾的行sed -e 's~:~~g'
:删除“:”然后运行:
make help
这对我有用?
PD:更多信息在...
make --help
答案 10 :(得分:1)
我接受了上面提到的几个答案并编译了这个答案,它也可以为每个目标生成一个漂亮的描述,它也适用于带有变量的目标。
示例Makefile:
APPS?=app1 app2
bin: $(APPS:%=%.bin)
@# Help: A composite target that relies only on other targets
$(APPS:%=%.bin): %.bin:
echo "build binary"
@# Help: A target with variable name, value = $*
test:
echo $(MAKEFLAGS)
echo "starting test"
@# Help: A normal target without variables
# A target without any help description
clean:
echo $(MAKEFLAGS)
echo "Cleaning..."
MAKEOVERRIDES =
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在此处发布的How do you get the list of targets in a makefile?完全一样。
获取目标列表后,它会make <target> -nB
作为每个目标的空运行,并分析以@# Help:
开头的最后一行以描述目标。然后在格式正确的表格中打印出该字符串或空字符串。
如您所见,变量甚至在描述中也进行了扩展,这在我的书中是非常有用的:)。
答案 11 :(得分:1)
此help
目标仅打印带有##
后跟说明的目标。这样可以记录公共目标和私有目标。使用.DEFAULT_GOAL
可以使帮助更容易发现。
仅使用sed
,xargs
和printf
这两个很常见的
使用< $(MAKEFILE_LIST)
可以使makefile被调用为Makefile
以外的其他Makefile.github
您可以在printf
中自定义输出以适合您的偏好。设置此示例以匹配OP对rake
样式输出的请求
剪切和粘贴下面的make文件时,请不要忘记将4个空格的缩进更改为制表符。
# vim:ft=make
# Makefile
.DEFAULT_GOAL := help
.PHONY: test help
help: ## these help instructions
@sed -rn 's/^([a-zA-Z_-]+):.*?## (.*)$$/"\1" "\2"/p' < $(MAKEFILE_LIST) | xargs printf "make %-20s# %s\n"
lint: ## style, bug and quality checker
pylint src test
private: # for internal usage only
@true
test: private ## run pytest with coverage
pytest --cov test
这是上面Makefile
的输出。请注意,private
目标没有得到输出,因为它的注释只有一个#
。
$ make
make help # these help instructions
make lint # style, bug and quality checker
make test # run pytest with coverage
答案 12 :(得分:1)
要扩展answer given by @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)'
答案 13 :(得分:1)
我选择一种简单的语法来描述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:
给你类似的东西
> make help
up Starts the container stack
pull Pulls in new container images
命令链说明:
答案 14 :(得分:1)
这是对jsp非常有用的答案(https://stackoverflow.com/a/45843594/814145)的修改。我喜欢不仅获得目标列表而且获得目标描述的想法。 jsp的Makefile将描述作为注释,我经常发现该描述会在目标的description 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
输出中添加“:”。答案 15 :(得分:1)
这里有很多可行的解决方案,但正如我喜欢说的那样,“如果值得做一次,那就值得再做一次。” 我做了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
答案 16 :(得分:1)
这远非干净,但为我做了工作。
KTable<Long, ArrayList<Long>> sample = builder.stream(TOPIC)
.groupByKey()
.aggregate(
() -> new ArrayList<Long>(),
(key, val, agg) -> agg.add(val),
longSerde
);
我使用make -p 2&>/dev/null | grep -A 100000 "# Files" | grep -v "^$" | grep -v "^\(\s\|#\|\.\)" | grep -v "Makefile:" | cut -d ":" -f 1
转储内部数据库,ditch stderr,使用快速而脏的make -p
来保持输出的底部。然后我用几个grep -A 100000
清理输出,最后使用grep -v
来获取冒号之前的内容,即目标。
这对我的大多数Makefile上的助手脚本来说已经足够了。
编辑:添加cut
这是一项内部规则
答案 17 :(得分:1)
这个对我有帮助,因为我想通过make目标看到所需的构建目标(及其依赖项)。我知道制作目标不能以&#34;开始。&#34;字符。我不知道支持哪种语言,所以我选择了egrep的括号表达式。
cat Makefile | egrep "^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$"
答案 18 :(得分:0)
我通常这样做:
grep install_targets Makefile
它会返回类似以下内容:
install_targets = install-xxx1 install-xxx2 ... etc
我希望这对您有帮助
答案 19 :(得分:0)
对上面还有另一个答案。
仅在终端机上使用cat和awk在MacOSX上进行了测试
cat Makefile | awk '!/SHELL/ && /^[A-z]/ {print $1}' | awk '{print substr($0, 1, length($0)-1)}'
将输出make文件,如下所示:
target1
target2
target3
在Makefile中,它应该是同一条语句,请确保使用$$ variable而不是$ variable对变量进行转义。
说明
猫-吐出内容
| -管道将输出解析到下一个awk
awk -运行除“ shell”外的正则表达式,仅接受“ A-z”行,然后打印出$ 1第一列
awk -再次从列表中删除最后一个字符“:”
这是一个粗略的输出,您仅需AWK就可以做更多时髦的事情。尝试避免sed,因为sed在BSD变体中的一致性不高,即某些功能在* nix上有效,但在MacOSX等BSD上却不起作用。
更多
您应该能够将此文件(带有修改)添加到 make 的文件中,并添加到默认的bash-completion文件夹/ usr / local / etc / bash-completion .d / 意思是当您“制作 选项卡选项卡 ”时。.它将根据一个衬纸脚本完成目标。
答案 20 :(得分:0)
对于AWK仇恨者和为简单起见,此配置对我有效:
help:
make -qpRr $(lastword $(MAKEFILE_LIST)) | egrep -v '(^(\.|:|#|\s|$)|=)' | cut -d: -f1
(要在Makefile外部使用,只需删除$(lastword ...)
或将其替换为Makefile路径)。
如果您具有“有趣的”规则名称,则此解决方案将不起作用,但适用于大多数简单设置。基于make -qp
的解决方案的主要缺点是(如此处的其他答案),如果Makefile使用函数定义变量值-无论-q
以及是否使用{{1} },仍然会调用shell命令,并且会发生副作用。在我的设置中,运行shell函数的副作用通常是不必要的输出到标准错误,因此我在make命令后添加$(shell ...)
。
答案 21 :(得分:-4)
不确定为什么以前的答案太复杂了:
list:
cat Makefile | grep "^[A-z]" | awk '{print $$1}' | sed "s/://g"