如何在makefile中打印出一个变量

Posted

技术标签:

【中文标题】如何在makefile中打印出一个变量【英文标题】:How to print out a variable in makefile 【发布时间】:2013-05-04 06:42:50 【问题描述】:

在我的 makefile 中,我有一个变量 'NDK_PROJECT_PATH',我的问题是如何在编译时将其打印出来?

我阅读了Make file echo displaying "$PATH" string 并尝试过:

@echo $(NDK_PROJECT_PATH)
@echo $(value NDK_PROJECT_PATH)

两个都给我

"build-local.mk:102: *** missing separator.  Stop."

有人知道为什么它不适合我吗?

【问题讨论】:

【参考方案1】:

您可以在 make 文件中创建一个 vars 规则,如下所示:

dispvar = echo $(1)=$($(1)) ; echo

.PHONY: vars
vars:
    @$(call dispvar,SOMEVAR1)
    @$(call dispvar,SOMEVAR2)

这里有一些更强大的方法可以转储所有变量:gnu make: list the values of all variables (or "macros") in a particular run。

【讨论】:

【参考方案2】:

根据GNU Make manual 并在以下答案中由“bobbogo”指出, 您可以使用 info / warning / error 来显示文字。

$(error   text…)
$(warning text…)
$(info    text…)

要打印变量,

$(error   VAR is $(VAR))
$(warning VAR is $(VAR))
$(info    VAR is $(VAR))

'error' 将在显示错误字符串后停止 make 执行

【讨论】:

哇,不知道这个。比 echo 好得多,它会在日志中复制命令。【参考方案3】:

如果我想查看变量值,我通常会报错。(仅当您想查看该值时。它将停止执行。)

@echo $(错误 NDK_PROJECT_PATH= $(NDK_PROJECT_PATH))

【讨论】:

【参考方案4】:

您可以使用此方法(使用名为“var”的变量)在读取 makefile 时打印出变量(假设 GNU make,因为您已适当地标记了此问题):

$(info $$var is [$var])

您可以将此构造添加到任何配方中,以查看 make 将传递给 shell:

.PHONY: all
all: ; $(info $$var is [$var])echo Hello world

现在,这里发生的是 make 将整个配方 ($(info $$var is [$var])echo Hello world) 存储为单个递归扩展变量。当 make 决定运行配方时(例如,当您告诉它构建 all 时),它会扩展变量,然后将每个结果行分别传递给 shell。

所以,痛苦的细节:

扩展$(info $$var is [$var])echo Hello world 为此,它首先扩展$(info $$var is [$var]) $$ 变为文字 $ $var 变成 :-)(比如说) 副作用是$var is [:-)] 出现在标准输出中 $(info...) 的扩展虽然是空的 留下echo Hello world 首先在标准输出上打印echo Hello world,让你知道它会要求shell做什么 shell 在标准输出上打印Hello world

【讨论】:

应该是(点).PHONY 而不是 PHONY?【参考方案5】:

无需修改 Makefile。

$ cat printvars.mak
print-%:
        @echo '$*=$($*)'

$ cd /to/Makefile/dir
$ make -f ~/printvars.mak -f Makefile print-VARIABLE

【讨论】:

【参考方案6】:

如果你只是想要一些输出,你想单独使用$(info)。您可以在 Makefile 中的任何位置执行此操作,它会在评估该行时显示:

$(info VAR="$(VAR)")

每当 make 处理该行时将输出VAR="<value of VAR>"。此行为非常依赖于位置,因此您必须确保 $(info) 扩展发生在所有可以修改 $(VAR) 的事情已经发生之后!

一个更通用的选项是创建一个特殊的规则来打印变量的值。一般来说,规则是在分配变量后执行的,因此这将显示实际使用的值。 (虽然,它是possible for a rule to change a variable。)良好的格式将有助于阐明变量的设置,$(flavor) 函数会告诉您某物是什么类型的变量。所以在这条规则中:

print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true
$* 扩展为 % pattern 在规则中匹配的词干。 $($*) 扩展为名称由 $* 给出的变量的值。 [] 清楚地描述了变量扩展。 您也可以使用 "" 或类似名称。 $(flavor $*) 告诉你它是什么类型的变量。注意:$(flavor) 接受一个变量 name,而不是它的扩展。 所以如果你说make print-LDFLAGS,你会得到$(flavor LDFLAGS), 这就是你想要的。 $(info text) 提供输出。 Make 在其标准输出上打印 text 作为扩展的副作用。 $(info) 的扩展虽然是空的。 你可以把它想象成@echo, 但重要的是它不使用外壳, 因此您不必担心 shell 引用规则。 @true 只是为规则提供命令。 没有那个, make 也会输出print-blah is up to date。我觉得@true 更清楚地表明它是禁止操作的。

运行它,你得到

$ make print-LDFLAGS
LDFLAGS is a recursive variable set to [-L/Users/...]

【讨论】:

这没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方发表评论 - 您可以随时评论自己的帖子,一旦您有足够的reputation,您就可以comment on any post。 - From Review 感谢您的评论。我知道一旦我有足够的声誉,我可以发表评论,但我应该在此期间做什么?我相信我的答案提供了额外的价值,所以我不应该添加它吗? 我建议将其重写为与您正在评论的答案竞争的独立答案,而不是将其表述为对该答案的不合适的评论。 @JimNasby 是的,查尔斯的建议。实际上,简单地删除“抱歉没有足够的代表发表评论”之类的部分可能会有所帮助,因为它是一个危险信号。如果你把它变成一个完整的答案(可以随心所欲地编辑它),它应该做得很好。干杯。 非常好——现在这是一个更好的答案。 :)【参考方案7】:

如果您使用 android make (mka) @echo $(NDK_PROJECT_PATH) 将无法正常工作并给您错误 *** missing separator. Stop." 如果您尝试在 android make 中打印变量,请使用 this answer

NDK_PROJECT_PATH := some_value
$(warning $(NDK_PROJECT_PATH))

对我有用

【讨论】:

【参考方案8】:

如果不想修改Makefile本身,可以使用--eval添加新目标,然后执行新目标,例如

make --eval='print-tests: @echo TESTS $(TESTS) ' print-tests

您可以使用CTRL-V, TAB在命令行中插入所需的TAB字符

上面的 Makefile 示例:

all: do-something

TESTS=
TESTS+='a'
TESTS+='b'
TESTS+='c'

do-something:
        @echo "doing something"
        @echo "running tests $(TESTS)"
        @exit 1

【讨论】:

我正在尝试运行您的脚本,但出现错误make: *** missing separator. Stop. 啊,抱歉,已修复。 “打印测试”目标末尾缺少冒号。 其实你不需要换行和制表符,分号就足够了:make --eval='print-tests: ; @echo TESTS $(TESTS)' print-tests【参考方案9】:

这可以通过通用方式完成,并且在调试复杂的 makefile 时非常有用。按照another answer 中描述的相同技术,您可以将以下内容插入到任何makefile 中:

# if the first command line argument is "print"
ifeq ($(firstword $(MAKECMDGOALS)),print)

  # take the rest of the arguments as variable names
  VAR_NAMES := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))

  # turn them into do-nothing targets
  $(eval $(VAR_NAMES):;@:))

  # then print them
  .PHONY: print
  print:
          @$(foreach var,$(VAR_NAMES),\
            echo '$(var) = $($(var))';)
endif

然后你可以做“make print”来转储任何变量的值:

$ make print CXXFLAGS
CXXFLAGS = -g -Wall

【讨论】:

【参考方案10】:

问题是 echo 只能在执行块下工作。即“xx:”之后的任何内容

所以第一个执行块之上的任何东西都只是初始化,所以不能使用任何执行命令。

所以创建一个执行块

【讨论】:

【参考方案11】:

来自“Mr. Make post” https://www.cmcros-s-roads.com/article/printing-value-makefile-variable

将以下规则添加到您的 Makefile:

print-%  : ; @echo $* = $($*)

那么,如果你想找出某个makefile变量的值,只需:

make print-VARIABLE

它会返回:

VARIABLE = the_value_of_the_variable

【讨论】:

你解释得比作者好。竖起大拇指!【参考方案12】:

运行make -n;它显示了变量的值..

生成文件...

all:
        @echo $(NDK_PROJECT_PATH)

命令:

export NDK_PROJECT_PATH=/opt/ndk/project
make -n 

输出:

echo /opt/ndk/project

【讨论】:

这非常有用,我使用 --just-print 在 Instead of Execution 中是一样的【参考方案13】:

makefile 将生成“缺少分隔符”错误消息:

all
    @echo NDK_PROJECT_PATH=$(NDK_PROJECT_PATH)

done:
        @echo "All done"

@echo "All done" 之前有一个标签(尽管done: 规则和操作在很大程度上是多余的),但@echo PATH=$(PATH) 之前没有。

问题在于以all 开头的行应该有一个冒号: 或一个等于= 以表明它是目标行或宏行,而两者都没有,所以缺少分隔符.

回显变量值的操作必须与目标相关联,可能是虚拟目标或 PHONEY 目标。并且该目标行上必须有一个冒号。如果您在示例makefile 中的all 之后添加:,并将下一行的前导空格替换为制表符,它将正常工作。

您可能在原始makefile 的第 102 行附近有类似的问题。如果您在失败的回显操作之前显示 5 个非空白、非注释行,则可能可以完成诊断。但是,由于该问题是在 2013 年 5 月提出的,因此损坏的 makefile 现在不太可能仍然可用(2014 年 8 月),因此无法正式验证此答案。它只能用来说明问题发生的合理方式。

【讨论】:

【参考方案14】:

make 的所有版本都要求命令行以 TAB(而不是空格)作为行中的第一个字符缩进。如果您向我们展示了整个规则,而不仅仅是有问题的两行,我们可以给出更清晰的答案,但应该是这样的:

myTarget: myDependencies
        @echo hi

第二行的第一个字符必须是 TAB。

【讨论】:

【参考方案15】:

@echo $(NDK_PROJECT_PATH) 是这样做的好方法。 我不认为错误来自那里。 通常,当您输入错误的意图时会出现此错误:我认为您应该有一个制表符的空格。

【讨论】:

我试过'@echo $(NDK_PROJECT_PATH)',我仍然收到错误“build-local.mk:102: *** missing separator. Stop.”。我在“echo”之后只有 1 个空格,“@echo”之前没有空格或制表符。 你确定错误来自这一行吗?这条线是规则吗?她可能必须缩进......

以上是关于如何在makefile中打印出一个变量的主要内容,如果未能解决你的问题,请参考以下文章

如何在makefile中获取shell环境变量?

如何在Makefile中打印消息?

如何在makefile中添加打印信息

在多个 Makefile 中包含 Makefile 和 Echo 变量

如何让makefile 执行的时候打印所有命令

如何调试makefile变量