100

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

我希望能够获得任意生成文件的目标。我正在尝试为我的 shell 编写一个完成函数。

4

16 回答 16

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

取自 make arg 完成,它就像一个魅力。

于 2012-03-01T22:03:18.617 回答
79

你能解析make -pn(即make --print-data-base --dry-run)的输出吗?它打印出所有变量、规则、隐式规则以及哪些命令将被详细运行。

于 2010-09-03T02:02:12.597 回答
14

我不确定这是否只是一个 gnu 制作的东西,但这很好用:

make help

于 2012-10-11T21:23:28.113 回答
10

一些响应者建议使用make -pn,它将打印规则数据库但不执行任何操作 - 或多或少。这种方法的问题是-n它仍然会调用所有递归 make,并且它仍然做的工作比必要的多得多,因为它会打印出它会在常规构建中调用的每个命令。更有效的解决方案是创建一个简单的 makefile,dummy.mk,包含以下内容:

__all_targets__: ; #no-op

现在调用 make as 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 秒。

于 2011-09-12T16:14:51.960 回答
9

在 GitHub 上查看 make 的bash完成。

于 2011-09-22T20:47:01.370 回答
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 完成脚本)还远远不够。

这不是我链接到的原始脚本,但它更简单,而且速度更快。

于 2012-08-26T16:48:24.773 回答
4

这是基于 Todd Hodes 解决方案的别名代码

alias mtargets='make -qp | awk -F":" "/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split(\$1,A,/ /);for(i in A)print A[i]}"'
于 2015-03-20T06:40:23.550 回答
3

这将给出一个很好的输出:

make -pn | perl -F: -ane 'print "$F[0]\n" if /^\w+\s*:/' | sort
于 2011-07-08T13:22:19.283 回答
3

这里有一个非常好的解决方案,其中包含一些 sed 和 egrep 魔法: https ://gist.github.com/pvdb/777954

于 2013-02-06T08:42:19.967 回答
2

猜猜我参加这个聚会有点晚了,但如果你正在寻找一个特定的命令,你可以试试

make -qp | grep -v '^# ' | grep -v '^[[:space:]]' | grep --only-matching '^.*:'

这主要是有效的,尽管它可能仍然包含一些非目标的东西,比如vpath指令。如果您不依赖make的内置规则,则可以make -qpR用作管道中的第一个命令。

于 2011-03-06T17:31:04.650 回答
1

红宝石解决方案:

`make -qp`.split("\n").select{|l| l =~ /^\w/ && l !~ /=/}.map{|l| l.sub(/:.*/,'')}
于 2012-11-09T07:37:19.603 回答
1

我正在研究solaris 10 anda turbo C shell。给定的解决方案不适用于我的 makefile 项目。即使将上面的命令行更改为 tcsh 语法。但是,我发现您可以使用

remake --tasks | grep -v "clean some static output or just grep tabs on start of line" | awk ´{print $1}´

重制版:

remake --version

GNU Make 3.82+dbg0.8
Built for sparc-sun-sparc2-9

和其他一些不重要的版本数据

于 2015-09-20T05:14:41.733 回答
0

我去寻找同样的问题并想出了这个旋转:

make -pn | sed -rn '/^[^# \t\.%].*:/p'

这将删除所有注释行、模式规则(以制表符开头的行)、所有内在函数(示例.c.o%.o: %.c模式)。

于 2011-09-12T14:04:27.990 回答
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.

于 2017-12-03T16:26:45.600 回答
-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,例如涉及由eval语句构造的规则,您必须编写一些接近Make 模拟器的东西。不切实际的。

要查看简单规则的目标,您可以编写一个充当生成文件扫描器的生成文件,对任意生成文件进行操作:

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

这将是一件令人印象深刻的作品。你确定目标值得付出努力吗?

于 2010-06-17T17:14:09.180 回答
-4
grep ^[a-z].*\:$ Makefile | sed s,:,,g
于 2011-12-20T19:21:24.467 回答