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

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

我读使文件回显显示"$PATH"字符串,我试着:

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

两者都给了我

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

有人知道为什么对我没用吗?

505906 次浏览

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

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

myTarget: myDependencies
@echo hi

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

你可以在读取makefile时打印出变量(假设你已经适当地标记了这个问题),使用这个方法(使用一个名为“var”的变量):

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

你可以把这个构造添加到任何recipe中,看看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}变成:-) (say)
    • 副作用是$var is [:-)]出现在标准输出
    • $(info...)的展开是空的
    • 李< / ul > < / >
    • Make剩下echo Hello world
      • 首先在stdout上打印echo Hello world,让你知道它将要求shell做什么
      • 李< / ul > < / >
      • shell在stdout上输出Hello world

make -n运行;它告诉你变量的值。

Makefile……

all:
@echo $(NDK_PROJECT_PATH)

命令:

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

输出:

echo /opt/ndk/project

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

all
@echo NDK_PROJECT_PATH=$(NDK_PROJECT_PATH)


done:
@echo "All done"

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

问题是,从all开始的行应该有冒号:或等号=,以表明它是目标行或宏行,但它两者都没有,因此分隔符缺失。

响应变量值的操作必须与目标相关联,可能是虚拟目标或伪目标。目标行上必须有冒号。如果你在例子makefile中的all后面添加一个:,并用制表符替换下一行的前导空格,它将正常工作。

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

from a "Mr. Make post" https://www.cmcrossroads.com/article/printing-value-makefile-variable < / p >

在Makefile中添加以下规则:

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

然后,如果你想找出makefile变量的值,只需:

make print-VARIABLE

它会返回:

VARIABLE = the_value_of_the_variable

你可以在你的make文件中创建一个vars规则,像这样:

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


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

有一些更健壮的方法来转储所有变量:Gnu make:列出特定运行中所有变量(或“宏”)的值

根据GNU制作手册,也由'bobbogo'在下面的答案中指出, 你可以使用信息 / 警告 / 错误来显示文本

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

要打印变量,

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

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

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

因此,第一个执行块以上的任何内容都只是初始化,因此不能使用任何执行命令。

因此,创建一个执行块

如果你只是想要一些输出,你想单独使用$(info)。你可以在Makefile的任何地方这样做,它会显示这一行何时被求值:

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

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

一个更通用的选项是创建一个特殊的规则来打印变量的值。一般来说,规则是在变量赋值之后执行的,因此这将显示实际使用的值。(尽管,它是规则更改变量的可能性。)良好的格式将有助于阐明变量的设置,而$(flavor)函数将告诉你某个变量是什么类型。所以在这个规则中:

print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true
  • $*扩展到规则中% 模式匹配的茎。
  • $($*)展开为由$*给出的变量的值。
  • []清楚地描述了变量展开。 你也可以使用""或类似的方法
  • $(flavor $*)告诉你变量的类型。注意:$(flavor) 接受变量的名字,而不是它的展开。 所以如果你说make print-LDFLAGS,你会得到$(flavor LDFLAGS), 这就是你想要的。
  • $(info text)输出。 使在其标准输出上打印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/...]

这可以以通用的方式完成,并且在调试复杂的makefile时非常有用。按照另一个答案中描述的相同技术,你可以将以下内容插入到任何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

如果你不想修改Makefile本身,你可以使用--eval来添加一个新目标,然后执行这个新目标。

< p > <代码>使- eval = ' print-tests: @echo TESTS $(TESTS) “print-tests < /代码> < / p >

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

上面的Makefile示例:

all: do-something


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


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

如果你使用android make (mka) @echo $(NDK_PROJECT_PATH)将无法工作,并给出错误*** missing separator. Stop." 如果你试图在android中打印变量,请使用这个答案 make

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

这对我很有用

不需要修改Makefile。

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


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

如果我想查看变量值,我通常会返回一个错误。(除非你想看看价值。它将停止执行。)

@echo $(NDK_PROJECT_PATH = $(NDK_PROJECT_PATH))