GNU Make:列出特定运行中所有变量(或“宏”)的值

59

当运行make时,如何列出Makefile中所有变量(也称为宏)的当前值?

例如,如果Makefile中有以下内容:

CUR-DIR := $(shell /bin/pwd)
LOG-DIR := $(CUR-DIR)/make-logs

那么我想让它告诉我:

CUR-DIR = /home/johv/src/test
LOG-DIR = /home/johv/src/test/make-logs
8个回答

54

GNU make提供了.VARIABLES变量,其中包含所有全局变量的名称。但是,这也包括内置变量(如MAKEFLAGS)。如果您需要排除内置变量,则可能需要进行一些过滤,例如以下示例中所示。

以下makefile使用info命令打印用户定义的变量(CUR-DIRLOG-DIR):

# Place this line at the top of your Makefile
VARS_OLD := $(.VARIABLES)

# Define your variables
CUR-DIR := $(shell pwd)
LOG-DIR := $(CUR-DIR)/make-logs

# Put this at the point where you want to see the variable values
$(foreach v,                                        \
      $(filter-out $(VARS_OLD) VARS_OLD,$(.VARIABLES)), \
      $(info $(v) = $($(v))))

我该如何运行它?将其放入“Makefile”中并运行“make”,我只会得到“make:***没有目标。停止。” - johv
2
抱歉,我忘了提到,如果你的GNU make版本是3.80或更低,这个答案不适用。 - Ise Wisteria
啊,是的,我用的是3.80版本。在3.81版本中它可以工作。另外,我在问题中改成了CUR-DIR。 - johv
1
如何将内容写入文件而不是仅打印输出? - Jason S
2
@JasonS,请让你的shell来处理它。make > variables.txt - JSBձոգչ
显示剩余6条评论

39

感谢 @Ise Wisteria,这个内容被压缩了,适用于具有多个makefile(Buildroot)的大型项目中的所有变量。

$(foreach v, $(.VARIABLES), $(info $(v) = $($(v))))

输出: BR2_GCC_TARGET_TUNE = "cortex-a8" ...

如果您遇到如下错误: insufficient number of arguments (1) to function 'addprefix',这个项目可能存在一些损坏的变量... 我已经修剪了变量列表,并只显示一个前缀为BR2_的部分。

$(foreach v, $(filter BR2_%,$(.VARIABLES)), $(info $(v) = $($(v))))

1
非常感谢!这正是我绝望地寻找的答案 :) - YCN-

37

最终我是这样实现的:

gmake -pn | grep -A1 "^# makefile"| grep -v "^#\|^--" | sort | uniq > makevars.txt

它给出:

CUR-DIR := /home/johv/src/test
LOG-DIR := /home/johv/src/test/make-logs
MAKEFILE_LIST :=  Makefile
MAKEFLAGS = pn
SHELL = /bin/sh
VARS_OLD := [...]

gmake -pn 非常冗长,看起来有点像这样:

# environment
GNOME2_PATH = /usr/local:/opt/gnome:/usr:/usr/local:/opt/gnome:/usr
# automatic
@F = $(notdir $@)
# makefile
SHELL = /bin/sh
# default
RM = rm -f

1
并非所有系统都有 gmake - Fredrick Gauss
@FredrickGauss gmakemake 的符号链接。您可以删除 g,脚本将正常工作。 - Alex Khonko
1
谢谢@AlexKhonko,你推断出了这个问题的答案 :) - Fredrick Gauss

13

不保存所有.VARIABLES并过滤它们也可以实现。

此外,如果您的makefile中修改了其中一个原始.VARIABLES,那么两个最受欢迎的答案都无法捕获它。

查看$(origin)函数。该目标过滤并打印在makefile中定义的所有变量:

print_file_vars:
    $(foreach v, $(.VARIABLES), $(if $(filter file,$(origin $(v))), $(info $(v)=$($(v)))))

这样我只会得到几个额外的变量:CURDIR SHELL MAKEFILE_LIST .DEFAULT_GOAL MAKEFLAGS

可以将file替换为environmentcommand line,以打印相应类型的变量。


工作得很棒!天才! - Samuel
这个非常棒。这应该是被接受的答案。 - Moulick

4

这里有很多好的答案,但是如果您的某些变量是递归flavor,使用$($(v))可能会出现问题。这就是为什么应该使用$(value $(v))

这个变体稍微改进了一下,按名称对变量进行排序,并使输出更易读。

dump:
    $(foreach v, \
        $(shell echo "$(filter-out .VARIABLES,$(.VARIABLES))" | tr ' ' '\n' | sort), \
        $(info $(shell printf "%-20s" "$(v)")= $(value $(v))) \
    )

1
感谢@kevinf提供的foreach解决方案--如果想将此列表导出为某种机器可读文件,则在使用echo或printf时,由于Make无法正确引用数据,因此不平衡的引号或换行符会带来麻烦--需要使用$(file ...)函数将数据写入以避免sh/bash抱怨无效语法。例如,在您的规则中使用以下内容--它会打印变量名称、定义和扩展值:
$(file > $(MAKEFILE_ENV_FILE),)
$(foreach v, $(.VARIABLES), \
    $(file >> $(MAKEFILE_ENV_FILE),$(v)) \
    $(file >> $(MAKEFILE_ENV_FILE),    := $(value $(v))) \
    $(file >> $(MAKEFILE_ENV_FILE),    == $($(v))) \
    $(file >> $(MAKEFILE_ENV_FILE),) \
)

这仍然不能始终区分带有双换行符的恶意变量和两个变量,为此,现在需要在$(file >> NAME,TEXT)内的每个逗号后面添加足够唯一的分隔符,以便始终区分它们。

将MAKEFILE_ENV_FILE设置为某个文件名,例如:

MAKEFILE_ENV_FILE := $(abspath $(lastword $(MAKEFILE_LIST))).env

1
感谢 @kevinf 提供的好主意。我建议进行微小的更改,以防止 .VARIABLES 自身在变量列表中打印出来: < p > < code > $(foreach v, $(filter-out .VARIABLES,$(.VARIABLES)), $(info $(v) = $($(v))))


1

这个方案是 Ise Wisterias Solution 的改进:

./Makefile:

ARG_VARS_0 := $(.VARIABLES)
#############################
# Documented Arguments START
#############################

EXAMPLE_ARG_0 :=
EXAMPLE_ARG_1 := ./some/path

#############################
# Documented Arguments END
#############################
ARG_VARS_1 := $(.VARIABLES)
# filter out any words starting with '%':
ARG_VARS_0_FIXED := $(filter-out \%%,$(ARG_VARS_0))
ARG_VARS_1_FIXED := $(filter-out \%%,$(ARG_VARS_1))
ARG_VARS := $(filter-out $(ARG_VARS_0_FIXED) ARG_VARS_0,$(ARG_VARS_1_FIXED))

.PHONY: list_vars print_vars # ...

list_vars:
    $(foreach v,$(ARG_VARS),$(info $(v)))

print_vars:
    $(foreach v,$(ARG_VARS),$(info $(v) = $($(v))))

在终端上列出makefile的参数。
$ make list_vars
> EXAMPLE_ARG_0
> EXAMPLE_ARG_1

在终端上打印 Makefile 参数的默认值:

$ make print_vars
> EXAMPLE_ARG_0 =
> EXAMPLE_ARG_1 = ./some/path

有趣的是,使用“%”是必要的,因为.VARIABLES有时包含奇怪的内容,比如%D %F *D *F +D +F ...。以%开头的单词可能会导致问题(例如,某些变量可能无法打印)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接