如何在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中打印出一个变量的主要内容,如果未能解决你的问题,请参考以下文章