我已经使用了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:
12 回答
在Bash(至少)下,这可以通过选项卡完成自动完成:
这是为了改进@nobar's great approach如下:
使用更强大的命令来提取目标名称,这有望防止任何误报(并且还可以消除不必要的
sh -c
)并不总是以当前目录中的makefile为目标;尊重使用
-f <file>
明确指定的makefile排除隐藏目标 - 按照惯例,这些目标的名称既不是字母也不是数字
使用单个虚假目标
使用
@
作为前缀,以防止在执行前回显该命令奇怪的是,GNU
make
没有列出makefile中定义的目标名称的功能 .-p
选项生成包含所有目标的输出,但将其隐藏在许多其他信息中 .Place the following rule in a makefile for GNU make to implement a target named list that simply lists all target names in alphabetical order - i.e.: invoke as make list :
Important :粘贴时, make sure that the last line is indented by exactly 1 actual tab char. (spaces do not work) .
请注意,对结果目标列表进行排序是最佳选择,因为不排序不会产生有用的排序,因为不保留目标在makefile中出现的顺序 .
此外,包含多个目标的规则的子目标总是单独输出,因此,由于分类,通常不会彼此相邻;例如,如果有其他目标,则以
a z:
开头的规则将不会在输出中将目标a
和z
列在彼此旁边 .Explanation of the rule :
.
PHONY: list
声明目标列表虚假目标,即不引用文件的目标,因此应该无条件地调用其配方
$(MAKE) -prRn -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null
再次调用
make
以打印和解析从makefile派生的数据库:-p
打印数据库-Rr
禁止包含内置规则和变量-q
仅测试目标的最新状态(不重新编译任何东西),但这本身并不妨碍在所有情况下执行配方命令;因此:-f $(lastword $(MAKEFILE_LIST))
确保与原始调用中的目标相同的makefile,无论它是使用-f ...
隐式还是显式定向 .Caveat : This will break if your makefile contains include directives; to address this, define variable THIS_FILE := $(lastword $(MAKEFILE_LIST)) before any include directives and use -f $(THIS_FILE) instead.
:
是故意无效的目标,旨在确保不执行任何命令;2>/dev/null
会抑制生成的错误消息 . 注意:这依赖于-p
打印数据库,这是GNU make 3.82的情况 . 遗憾的是,GNU make没有提供直接打印数据库的选项,也没有执行默认(或给定)任务;如果您不需要定位特定的Makefile,则可以按照man
页中的建议使用make -p -f/dev/null
.-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
目标本身xargs
有效地将输出行转换为单行,以空格分隔的列表;如果您希望每个目标名称显示在其自己的行上,请省略此项 .
这里有很多可行的解决方案,但正如我喜欢说的那样,“如果值得做一次,那就值得再做一次 . ”我做了upvote sugestion使用(tab)(tab),但有些人已经注意到,你可能没有完成支持,或者,如果你有很多包含文件,你可能想要一种更简单的方法来知道目标的定义 .
我没有测试下面的子品牌...我认为它不会起作用 . 众所周知,递归会被认为是有害的 .
我喜欢哪个因为:
按包含文件列出目标 .
输出原始动态目标定义(用模数替换变量分隔符)
在新行上输出每个目标
似乎更清楚(主观意见)
说明:
MAKEFILE_LIST中的
foreach文件
输出文件名
包含冒号的
grep行,不缩进,不是注释,也不以句点开头
排除立即赋值表达式(:=)
剪切,排序,缩进和切断规则依赖(冒号后)
munge变量分隔符以防止扩展
样本输出:
我将这两个答案结合起来:https://stackoverflow.com/a/9524878/86967和https://stackoverflow.com/a/7390874/86967并进行了一些转义,以便可以在makefile中使用它 .
.
这是对jsp非常有用的答案(https://stackoverflow.com/a/45843594/814145)的修改 . 我喜欢不仅要获得目标列表而且还要获取它们的描述 . jsp 's Makefile puts the description as the comment, which I found often will be repeated in the target' s description echo命令 . 因此,我从每个目标的echo命令中提取描述 .
示例Makefile:
输出
make help
:笔记:
与jsp的答案相同,只列出PHONY目标,这可能适用于您的案例,也可能不适用
此外,它仅列出那些具有
echo
或:
命令作为配方的第一个命令的PHONY目标 .:
表示"do nothing" . 我在这里用它来表示那些不需要回声的目标,比如上面的all
目标 .help
目标还有一个额外的技巧是在make help
输出中添加":" .这远非干净,但为我做了工作 .
我使用
make -p
转储内部数据库,沟渠stderr,使用快速和脏grep -A 100000
来保持输出的底部 . 然后我用几个grep -v
清理输出,最后使用cut
来获取冒号之前的内容,即目标 .这对我的大多数Makefile上的助手脚本来说已经足够了 .
编辑:添加
grep -v Makefile
这是一个内部规则@nobar's answer帮助显示如何 use tab completion to list a makefile's targets .
这适用于提供此功能的平台 by default (例如, Debian, Fedora ) .
在其他平台(例如 Ubuntu )上,您必须 explicitly load 此功能,如@hek2mgl's answer所示:
. /etc/bash_completion
安装了几个制表符完成功能,包括make
的功能或者,仅为
make
安装选项卡完成:. /usr/share/bash-completion/completions/make
对于 platforms that don't offer this functionality at all ,例如 OSX ,您可以 source the following commands (从here调整)来实现它:
-f <file>
定位不同的makefile .这个对我有帮助,因为我想通过make目标看到所需的构建目标(及其依赖项) . 我知道制作目标不能以“ . ”开头 . 字符 . 我不知道支持哪种语言,所以我选择了egrep的括号表达式 .
如果安装了
make
的bash完成,则完成脚本将定义函数_make_target_extract_script
. 此函数用于创建sed
脚本,该脚本可用于将目标作为列表获取 .像这样用它:
这在很多情况下显然不起作用,但如果你的
Makefile
由CMake创建,你可能能够运行make help
.作为mklement0 points out,GNU-make缺少列出所有Makefile目标的功能,他的回答和其他提供了实现此目的的方法 .
但是,原帖还提到rake,其任务切换与仅列出rakefile中的所有任务略有不同 . Rake只会为您提供具有相关描述的任务列表 . 没有描述的任务will not be listed . 这使作者既能提供自定义帮助描述,又能省略某些目标的帮助 .
如果你想模仿rake的行为,你提供了descriptions for each target,有一种简单的方法可以做到这一点:在你想要列出的每个目标的注释中嵌入描述 .
您可以将描述放在目标旁边,或者像往常一样,将其放在目标上方的PHONY规范旁边,如下所示:
哪个会产生
您也可以在this gist和here中找到一个简短的代码示例 .
同样,这并没有解决在Makefile中列出所有目标的问题 . 例如,如果你有一个可能生成的大型Makefile或其他人写的,你想要一个快速的方法来列出它的目标而不需要挖掘它,这将无济于事 .
但是,如果您正在编写Makefile,并且希望以一致的自我文档方式生成帮助文本,则此技术可能很有用 .
不确定为什么以前的答案是如此复杂: