你如何获得makefile中的目标列表?

Bri*_*rns 176 makefile gnu-make targets

我已经使用了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...
...
Run Code Online (Sandbox Code Playgroud)

但似乎没有选择在GNU make中执行此操作.

显然,代码几乎就在那里,截至2007年 - http://www.mail-archive.com/help-make@gnu.org/msg06434.html.

无论如何,我几乎没有从makefile中提取目标,你可以将其包含在makefile中.

list:
    @grep '^[^#[:space:]].*:' Makefile
Run Code Online (Sandbox Code Playgroud)

它将为您提供已定义目标的列表.这只是一个开始 - 例如,它不会过滤掉依赖项.

> make list
list:
copy:
run:
plot:
turnin:
Run Code Online (Sandbox Code Playgroud)

nob*_*bar 167

在Bash(至少)下,这可以通过选项卡完成自动完成:

__PRE__

  • +1,但请注意,这不是_bash_功能,但取决于您的_platform_.平台分为三类:默认安装完成的那些(例如,Debian 7,Fedora 20),你可以_optionally_安装它的那些(例如,Ubuntu 14,带有./ etc/bash_completion`),以及那些根本不支持它(例如,OSX 10.9) (49认同)
  • 它适用于OS X 10.10(不是使用bash而是使用zsh). (5认同)
  • 这不适用于以编程方式创建的make目标AFAICT,例如`$(RUN_TARGETS):run-%:...` (3认同)
  • 伟大的提示,但也需要`bash-completion`包.在Fedora,RHEL,Gentoo等中找到. (2认同)
  • 这似乎也被 eval 和潜在的 `varname:=...` 混淆了 - 我的完成最终包括 `$(foreach f,` 等。现在我正在使用 `make -Bn` 或 `make -Bn targetname`,它像从头开始一样对 default 或 targetname 进行试运行。结合(可选)打印当前目标及其依赖项的目标,这可以为您提供所需的所有信息。顺便说一句,`make --print-data-base` 显示所有目标/先决条件/配方,包括通配符目标的每个扩展! (2认同)

mkl*_*nt0 107

这是尝试改进@ nobar的伟大方法,如下所示:

  • 使用更强大的命令来提取目标名称,这有望防止任何误报(并且还可以消除不必要的sh -c)
  • 并不总是以当前目录中的makefile为目标; 尊重使用明确指定的makefile-f <file>
  • 排除隐藏目标 - 按惯例,这些目标的名称既不是字母也不是数字
  • 使用单个虚假目标
  • 命令前缀,@以防止在执行前回显它

奇怪的是,GNU make没有列出makefile中定义的目标名称的功能.该-p选项生成包含所有目标的输出,但将其隐藏在许多其他信息中.

将以下规则放在GNU的makefile中,make以实现一个名为的目标list,该目标只是按字母顺序列出所有目标名称 - 即:调用asmake 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 '^$@$$'
Run Code Online (Sandbox Code Playgroud)

重要说明:粘贴此内容时,请确保最后一行缩进1个实际的tab char.(空格也没有工作).

请注意,对结果目标列表进行排序是最佳选择,因为排序不会产生有用的排序,因为保留目标在makefile中出现的顺序.
此外,包含多个目标的规则的子目标总是单独输出,因此,由于分类,通常不会彼此相邻; 例如,如果有其他目标,则开头的规则a z:没有目标a并且在输出中彼此相邻z列出.

规则说明:

  • .PHONY: list
    • 声明目标列表是假目标,即引用文件的目标,因此应该无条件地调用其配方
  • $(MAKE) -pRrq -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要约没有直接的选项,只是打印数据库,不执行默认(或给出)任务; 如果您不需要定位特定的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
    • 有效地将输出行转换为单行,空格分隔的列表; 如果您希望每个目标名称显示在其自己的行上,请省略此项.

  • 还将列出任何 .PHONY 目标,因此请确保您没有 `.PHONY: *` (2认同)

nob*_*bar 25

我将这两个答案结合起来:https://stackoverflow.com/a/9524878/86967/sf/answers/517361211/ 并进行了一些转义,以便可以在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"
Run Code Online (Sandbox Code Playgroud)

.

$ make -s list
build
clean
default
distclean
doc
fresh
install
list
makefile ## this is kind of extraneous, but whatever...
run
Run Code Online (Sandbox Code Playgroud)

  • 我(最近)也发现Bash下的标签完成将列出可用的目标. (10认同)
  • 您可以添加一个更简单的 make 目标: list: cat Makefile | grep "^[Az]" | awk '{print $$1}' | sed "s/://g | 排序" (2认同)
  • cat/sed方法在几个级别上失败.它不会扩展变量,也无法列出包含其他文件的目标. (2认同)

Tim*_*mmm 22

这在很多情况下显然不起作用,但如果你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
Run Code Online (Sandbox Code Playgroud)


hek*_*mgl 13

如果已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
Run Code Online (Sandbox Code Playgroud)

  • 有帮助,但请注意,并非所有平台都有脚本`/ etc/bash_completion`和/或函数`_make_target_extract_script` - 你似乎在Ubuntu> 12.如果你的目标是`/ usr/share/bash-completion/completions/make`相反,您的方法将适用于其他平台,例如Fedora 20.有(较旧的)平台具有此文件,但不具有该功能(例如,Debian 7和Ubuntu 12); 其他平台,例如OSX,根本没有"make"的标签完成.也许发布实际的函数定义会有所帮助. (3认同)

Mar*_*377 12

我最喜欢的答案是Chris Down在 Unix & Linux Stack Exchange 上发表的。我来报价。

这是 bash 完成模块make获取其列表的方式:

make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'
Run Code Online (Sandbox Code Playgroud)

它打印出以换行符分隔的目标列表,无需分页。

用户Brainstone建议通过管道sort -u删除重复条目:

make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}' | sort -u
Run Code Online (Sandbox Code Playgroud)

来源:如何列出 make 中的所有目标?(Unix&Linux SE)


jsp*_*jsp 11

正如mklement0指出的那样,GNU-make缺少列出所有Makefile目标的功能,他的答案和其他提供了实现此目的的方法.

但是,原帖还提到了rake,其任务切换与仅列出rakefile中的所有任务略有不同.Rake只会为您提供具有相关描述的任务列表.没有描述的任务将不会列出.这使作者既能提供自定义帮助描述,又能省略某些目标的帮助.

如果您想模拟rake的行为,在那里为每个目标提供描述,可以使用一种简单的方法:在您要列出的每个目标的注释中嵌入描述.

您可以将描述放在目标旁边,或者像往常一样,将其放在目标上方的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
Run Code Online (Sandbox Code Playgroud)

哪个会产生

$ make help
target1             Target 1 help text
target2             Target 2 help text

...
help                Generate list of targets with descriptions
Run Code Online (Sandbox Code Playgroud)

您还可以找到一个简短的代码示例这个要点,并在这里了.

同样,这并没有解决在Makefile中列出所有目标的问题.例如,如果你有一个可能生成的大型Makefile或其他人写的,你想要一个快速的方法来列出它的目标而不需要深入研究它,这将无济于事.

但是,如果您正在编写Makefile,并且希望以一致的自我文档方式生成帮助文本,则此技术可能很有用.

  • @MikkoRantalainen 等人,从 StackOverflow 复制/粘贴时,空格被解释为空格。就我而言,“expand -t20”正在寻找制表符,因此我需要将“\1 \2”中的空格更改为制表符才能正常工作。 (2认同)

ron*_*akg 10

我采用了上面提到的一些答案并编译了这个答案,它还可以为每个目标生成一个很好的描述,并且它也适用于带有变量的目标。

示例生成文件:

APPS?=app1 app2

bin: $(APPS:%=%.bin)
    @# Help: A composite target that relies only on other targets

$(APPS:%=%.bin): %.bin:
    @# Help: A target with variable name, value = $*

test:
    @# Help: A normal target without variables

# A target without any help description
clean:

# A hidden target
.hidden:

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"'

Run Code Online (Sandbox Code Playgroud)

输出示例:

$ 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
Run Code Online (Sandbox Code Playgroud)

它是如何工作的:

目标的顶部部分的make help工作方式与 mklement0 此处发布的完全相同 - How do you get the list of Targets in a makefile?

获取目标列表后,它会make <target> -nB为每个目标运行试运行,并解析以@# Help:目标描述开头的最后一行。并且该字符串或空字符串会打印在格式良好的表格中。

正如您所看到的,变量甚至在描述中也得到了扩展,这对我的书中来说是一个巨大的好处:)。


Ric*_*fer 8

专注于描述 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:
Run Code Online (Sandbox Code Playgroud)

因此,将上述内容视为 Makefile 并运行它会给您类似的结果

> make help
up          Starts the container stack
pull        Pulls in new container images
Run Code Online (Sandbox Code Playgroud)

命令链说明:

  • 请注意,StackOverflow 在显示上面的代码部分时会将制表符转换为空格,但 Makefile 需要制表符。您可以编辑帖子,然后复制各个部分,以便保留选项卡。 (2认同)

jvr*_*sem 5

对于 Bash 脚本

这是一种非常简单的方法,基于上面bash@cibercitizen1 的评论:

grep : Makefile | awk -F: '/^[^.]/ {print $1;}'
Run Code Online (Sandbox Code Playgroud)

另请参阅@Marc.2377 的更权威的答案,其中说明了 Bash 补全模块是如何make做到这一点的。


mar*_*rio 5

将此目标添加到您的 Makefile 中:

help:
    @echo "\nTARGETS:\n"
    @make -qpRr | egrep -e '^[a-z].*:$$' | sed -e 's~:~~g' | sort
    @echo ""

Run Code Online (Sandbox Code Playgroud)
  • make -qpRr=make --question --print-data-base --no-builtin-variables --no-builtin-rules
  • egrep -e '^[a-z].*:$$':搜索以小写字母开头并以“:”结尾的行
  • sed -e 's~:~~g': 删除“:”

然后运行:

make help
Run Code Online (Sandbox Code Playgroud)

这对我有用


PD:更多信息请访问...

make --help
Run Code Online (Sandbox Code Playgroud)