如何在makefile中打印出变量

问题描述 投票:202回答:14

在我的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."

任何人都知道为什么它不适合我?

makefile gnu-make
14个回答
187
投票

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

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

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

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

现在,这里发生的是将整个配方($(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...)的扩张是空洞的
  • Make留下echo Hello world 首先在stdout上打印echo Hello world,让你知道它将要求shell做什么
  • 外壳在stdout上打印Hello world

1
投票

要打印变量的值,您可以使用:

rule:
<tab>@echo $(VAR_NAME)

当规则运行时,变量将被打印。


1
投票

这可以通用方式完成,在调试复杂的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

1
投票

无需修改Makefile。

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

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

0
投票

如果您不想修改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

0
投票

如果你使用android make(mka)@echo $(NDK_PROJECT_PATH)将不起作用并给你错误*** missing separator. Stop."使用this answer如果你试图在android make中打印变量

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

这对我有用


0
投票

如果我想查看变量值,我通常会回显一个错误。(只有当你想看到它时才会看到它。它会停止执行。)

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


131
投票

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

将以下规则添加到Makefile:

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

然后,如果要查找makefile变量的值,只需:

make print-VARIABLE

它将返回:

VARIABLE = the_value_of_the_variable

128
投票

正如上面答案中的'bobbogo'所指出的并且根据GNU Make manual,您可以使用信息/警告/错误来显示文本。

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

要打印变量,

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

当你使用'error'时,make执行将在显示错误字符串后停止


39
投票

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

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

每当制作流程时输出VAR="<value of VAR>"。这种行为是非常依赖于位置的,所以你必须确保$(info)扩展发生在可能修改$(VAR)的所有内容已经发生之后!

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

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

运行它,你得到

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

6
投票

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


6
投票

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

myTarget: myDependencies
        @echo hi

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


4
投票

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

Makefile中...

all:
        @echo $(NDK_PROJECT_PATH)

命令:

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

输出:

echo /opt/ndk/project

3
投票

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

all
    @echo NDK_PROJECT_PATH=$(NDK_PROJECT_PATH)

done:
        @echo "All done"

@echo "All done"之前有一个标签(虽然done:规则和行动在很大程度上是多余的),但不是在@echo PATH=$(PATH)之前。

麻烦的是,启动all的行应该有一个冒号:或等于=来表示它是一个目标行或一个宏行,并且它没有,所以缺少分隔符。

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

你可能在原来的makefile第102行附近有一个类似的问题。如果在回显操作失败之前显示了5个非空白的非注释行,则可能完成诊断。但是,自从2013年5月提出这个问题以来,现在仍然无法使用破碎的makefile(2014年8月),所以这个答案无法正式验证。它只能用于说明问题发生的合理方式。


2
投票

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

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

所以创建一个执行块

© www.soinside.com 2019 - 2024. All rights reserved.