列出GNU中的目标/目标,使其在定义中包含变量

时间:2010-06-17 16:16:49

标签: makefile gnu-make

我有一个相当大的makefile,可以通过计算变量中的名称来动态创建多个目标。 (例如foo $(VAR):$(PREREQS))。在扩展这些变量之后,是否有任何方法可以说服gnu make吐出一系列目标?

我希望能够获得aribitrary makefile的目标。我正在尝试为我的shell编写一个完成函数。

15 个答案:

答案 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上运行:

  1. 使用sed从makefile中获取所有目标名称。
  2. `include` makefile以便用它来扩展变量。
  3. 使用`show_%:; echo $$ *`打印所有目标

这将是一项令人印象深刻的工作。你确定这个目标是值得的吗?

答案 14 :(得分:-4)

grep ^[a-z].*\:$ Makefile | sed s,:,,g