我有一个相当大的makefile,可以通过计算变量中的名称来动态创建多个目标。 (例如foo $(VAR):$(PREREQS))。在扩展这些变量之后,是否有任何方法可以说服gnu make吐出一系列目标?
我希望能够获得aribitrary makefile的目标。我正在尝试为我的shell编写一个完成函数。
答案 0 :(得分:112)
make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'
取自make arg完成,就像魅力一样。
答案 1 :(得分:78)
你能解析make -pn
的输出(即make --print-data-base --dry-run
)吗?它打印出所有变量,规则,隐式规则以及哪些命令将以繁重的细节运行。
答案 2 :(得分:13)
我不确定这只是一个gnu make的东西,但这很有效:
make help
答案 3 :(得分:10)
一些响应者建议使用make -pn
,它将打印规则数据库但不执行任何操作 - 或多或少。这种方法的问题是-n
仍然会调用所有递归的make,并且它仍然会执行比必要更多的工作,因为它会打印出它在常规构建中调用的每个命令。更有效的解决方案是使用以下内容创建一个简单的makefile,dummy.mk:
__all_targets__: ; #no-op
现在调用make为make -p -f Makefile -f dummy.mk __all_targets__
。在任何实质性构建中,make产生的输出量的差异是显着的。例如:
$ gmake -pn | wc
138985 2632330 69612711
$ gmake -f Makefile -f /tmp/dummy.mk -pn __all_targets__ | wc
21673 93437 878985
执行时间也大大改善 - 第一版为2.063秒,第二版为0.059秒。
答案 4 :(得分:9)
在GitHub上查看bash completion for make。
答案 5 :(得分:7)
编辑:仅供参考,另一个答案中的debian bash完成git存储库现在包含了针对bash完成用例而定制的此脚本的增强版本。
#!/bin/bash
SCRIPT='
/^# Make data base/,/^# Files/d # skip until files section
/^# Not a target/,+1 d # following target isnt
/^\.PHONY:/ d # special target
/^\.SUFFIXES:/ d # special target
/^\.DEFAULT:/ d # special target
/^\.PRECIOUS:/ d # special target
/^\.INTERMEDIATE:/ d # special target
/^\.SECONDARY:/ d # special target
/^\.SECONDEXPANSION/ d # special target
/^\.DELETE_ON_ERROR:/ d # special target
/^\.IGNORE:/ d # special target
/^\.LOW_RESOLUTION_TIME:/ d # special target
/^\.SILENT:/ d # special target
/^\.EXPORT_ALL_VARIABLES:/ d # special target
/^\.NOTPARALLEL:/ d # special target
/^\.ONESHELL:/ d # special target
/^\.POSIX:/ d # special target
/^\.NOEXPORT:/ d # special target
/^\.MAKE:/ d # special target
# The stuff above here describes lines that are not
# explicit targets or not targets other than special ones
# The stuff below here decides whether an explicit target
# should be output.
/^[^#\t:=%]+:([^=]|$)/ { # found target block
h # hold target
d # delete line
}
/^# File is an intermediate prerequisite/ { # nope
s/^.*$//;x # unhold target
d # delete line
}
/^([^#]|$)/ { # end of target block
s/^.*$//;x # unhold target
s/:.*$//p # write current target
d # hide any bugs
}
'
make -npq .DEFAULT 2>/dev/null | sed -n -r "$SCRIPT" \
| sort | uniq
这是一个比debian bash完成脚本更完整的脚本,因为它提供了生成规则的结果,这是问题所要求的和最高投票答案(debian git服务器上的debian bash完成脚本)不会够远了。
这不是我链接到的原始脚本,但它更简单,触摸更快。
答案 6 :(得分:4)
这是基于Todd Hodes解决方案的别名代码
alias mtargets='make -qp | awk -F":" "/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split(\$1,A,/ /);for(i in A)print A[i]}"'
答案 7 :(得分:3)
这将给出一个很好的输出:
make -pn | perl -F: -ane 'print "$F[0]\n" if /^\w+\s*:/' | sort
答案 8 :(得分:3)
这里有一个非常好的解决方案,有一些sed和egrep魔法: https://gist.github.com/pvdb/777954
答案 9 :(得分:2)
make -qp | grep -v '^# ' | grep -v '^[[:space:]]' | grep --only-matching '^.*:'
这主要有用,虽然它可能仍然包含一些非目标内容,如vpath
指令。如果您不依赖于make
的内置规则,则可以使用make -qpR
作为管道中的第一个命令。
答案 10 :(得分:1)
Ruby解决方案:
`make -qp`.split("\n").select{|l| l =~ /^\w/ && l !~ /=/}.map{|l| l.sub(/:.*/,'')}
答案 11 :(得分:0)
我去寻找同样的问题并提出了这个问题:
make -pn | sed -rn '/^[^# \t\.%].*:/p'
这将删除所有注释行,模式规则(以制表符开头的行),所有内在函数(示例.c.o
和%.o: %.c
模式)。
答案 12 :(得分:0)
在另一个帖子中找到了这个解决方案:
sh -c "cat Makefile | egrep \"^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$\""
您也可以将其添加到Makefile
:
list:
sh -c "cat Makefile | egrep \"^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$\\""
执行make list
。
答案 13 :(得分:-1)
当然,但是你什么时候想把它吐出去?
要在运行规则时报告目标的名称,请在规则中添加一行:
foo$(VAR): $(PREREQS)
@echo now making the foo target: $@
do_other_stuff...
要立即全部吐出,你可以单独制作一个PHONY目标:
.PHONY: show_vars
show_vars:
@echo foo$(VAR)
@echo bar$(PARAM) blah$(FLAG)
# and so on
这可以作为默认目标的先决条件:
all: show_vars
...
修改:
您想要一种方法来显示任意makefile的所有可能目标,我想这意味着非侵入性。嗯......
要做到这一点,并能够应对复杂的makefile,例如涉及由eval
语句构造的规则,你必须写一些接近Make模拟器的东西。不切实际的。
要查看简单规则的目标,您可以编写一个makefile作为makefile扫描程序,在任意makefile上运行:
这将是一项令人印象深刻的工作。你确定这个目标是值得的吗?
答案 14 :(得分:-4)
grep ^[a-z].*\:$ Makefile | sed s,:,,g