如何在makefile中打印变量

363

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

有人知道为什么对我不起作用吗?

16个回答

320
你可以使用以下方法(假设你已经正确标记了这个问题并且正在使用GNU make)在读取makefile时打印变量(假设变量名为"var"):

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

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

您可以将此结构添加到任何配方中,以查看将传递给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...) 的展开为空
  • Make 剩下echo Hello world
    • Make首先在标准输出上打印echo Hello world,让你知道它将要让shell做什么
  • Shell 在标准输出上打印Hello world

5
应该将 PHONY 改为 .PHONY 吗? - hammadian

309
根据GNU Make手册和下面回答中'bobbogo'指出的,你可以使用info / warning / error来显示文本。
$(error   text…)
$(warning text…)
$(info    text…)

打印变量:
$(error   VAR is $(VAR))
$(warning VAR is $(VAR))
$(info    VAR is $(VAR))

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

4
哇,没想到这个。比起 Echo 在日志中重复命令的方式要好得多。 - deepelement
@deepelement 你只需要在 echo 前面加上 '@',就不会在日志中打印出来。 - Ultimation

175

60

如果你只是想要一些输出,那么你可以单独使用 $(info)。你可以在 Makefile 的任何位置这样做,它将在该行被评估时显示:

如果您只需要一些输出,您可以在Makefile中任何位置使用 $(info) ,它将在该行被评估时显示:

$(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) 提供输出。 maketext 打印到标准输出作为扩展的副作用。 但是,$(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/...]

13

所有版本的make都要求命令行在行首使用TAB(不是空格)进行缩进。如果您向我们展示完整的规则而不仅仅是问题中的两行,我们可以给出更清晰的答案,但应该类似于:

myTarget: myDependencies
        @echo hi

第二行的第一个字符必须是制表符(TAB)。


8

@echo $(NDK_PROJECT_PATH)是一个好的方法。 我不认为错误来自那里。 通常当您输入错误缩进时,会出现此错误:我认为您在应该有制表符的地方使用了空格。


4
我尝试了 "@echo $(NDK_PROJECT_PATH)",但仍然出现错误 "build-local.mk:102: *** missing separator. Stop."。在 'echo' 后只有一个空格,在 '@echo' 前面没有空格或制表符。 - michael
你确定错误来自这一行吗?这一行在规则中吗?她很可能需要缩进... - user1746732

7

无需修改Makefile文件。

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

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

4
问题在于echo仅在执行块下工作,即“xx:”后面的任何内容。因此,在第一个执行块之上的所有内容都只是初始化,因此不能使用任何执行命令。因此,请创建一个执行块。

4

运行 make -n 命令;它会显示变量的值...

Makefile...

all:
        @echo $(NDK_PROJECT_PATH)

指令:

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

输出:

echo /opt/ndk/project

这非常有用,我使用--just-print代替执行中的相同。 - Fredrick Gauss

4

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

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

您可以使用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

我正在尝试运行你的脚本,但是出现了错误“make: *** missing separator. Stop。” - Rinaldi Segecin
啊,抱歉,已修复。"print-tests"目标末尾缺少冒号。 - Wade
1
实际上,您不需要换行和制表符,只需一个分号即可:make --eval ='print-tests:;@echo TESTS $(TESTS)'print-tests - bobbogo

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