如何在makefile中打印出变量


246

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

我阅读了显示“ $ PATH”字符串的Make文件回显,然后尝试执行以下操作:

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

两者都给我

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

谁知道为什么它对我不起作用?

Answers:


221

您可以使用以下方法(使用名为“ 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在stdout上打印,以使您知道要shell做什么
  • 外壳Hello world在标准输出上打印。

2
应该是(点).PHONY而不是PHONY?
哈马第

171

按照GNU Make手册并在下面的答案中也用'bobbogo'指出,您可以使用信息 / 警告 / 错误来显示文本。

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

要打印变量,

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

“错误”将停止化妆执行,显示错误字符串后


哇,不知道这个。比echo更好,后者在日志中复制了命令。
deepelement


44

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

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

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,但重要的是它不使用外壳程序,因此您不必担心外壳程序引用规则。
  • @true只是为了提供规则命令。否则, make也会输出print-blah is up to date。我觉得@true这很明确,这是无人值守。

运行它,你得到

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

这不能为问题提供答案。要批评或要求作者澄清,请在其帖子下方发表评论-您随时可以对自己的帖子发表评论,一旦您拥有足够的声誉,就可以在任何帖子中发表评论。- 来自评论
Dragon Energy

感谢您的审查。我了解,一旦我有足够的声誉就可以发表评论,但与此同时我该怎么办?我相信我的答案可以带来更多价值,所以我不应该添加它吗?
Jim Nasby '16

1
我建议将其重写为一个独立的答案,与您要评论的答案竞争,而不是将其表述为对该答案的不当评论。
查尔斯·达菲

@JimNasby是的,Charles建议的。实际上,从一开始就删除“对不起,没有足够的代表发表评论”之类的部分可能会有所帮助,因为这是一个危险信号。如果您将其变成一个完整的答案(可以随意编辑),它应该做得很好。干杯。
Dragon Energy

太好了-这是一个更好的答案。:)
查尔斯·达菲

6

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


2
我尝试了'@echo $(NDK_PROJECT_PATH)',但仍然收到错误消息“ build-local.mk:102:***缺少分隔符。停止。”。我在'echo'之后只有1个空格,在'@echo'之前没有空格或制表符。
迈克尔,

您确定错误来自此行吗?这条线是规则吗?她可能必须缩进...

6

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

myTarget: myDependencies
        @echo hi

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


4

make -n; 它显示了变量的值。

生成文件...

all:
        @echo $(NDK_PROJECT_PATH)

命令:

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

输出:

echo /opt/ndk/project

不过,这非常有用,我--just-print在“ 代替执行”中
Fredrick Gauss,

3

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

all
    @echo NDK_PROJECT_PATH=$(NDK_PROJECT_PATH)

done:
        @echo "All done"

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

麻烦的是,该行的开头all应该有一个冒号:或等号,=以表明它是目标行或宏行,而两者都没有,因此缺少分隔符。

回显变量值的操作必须与目标(可能是虚拟目标或PHONEY目标)相关联。并且该目标行上必须有一个冒号。如果在示例中添加一个:after allmakefile然后用制表符替换下一行中的前导空白,它将正常运行。

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


3

无需修改Makefile。

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

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

2

问题是回声仅在执行块下起作用。即“ xx:”之后的任何内容

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

所以创建一个执行blocl


1

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


0

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

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

您可以使用以下命令在命令行中插入所需的TAB字符: 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

啊,对不起,已修复。在“打印测试”目标末尾缺少冒号。
韦德

实际上,您不需要换行和制表符,分号就足够了:make --eval='print-tests: ; @echo TESTS $(TESTS)' print-tests
bobbogo

0

如果您使用android make(mka)@echo $(NDK_PROJECT_PATH)将不起作用,并且给您错误,如果您尝试在android make中打印变量,请*** missing separator. Stop." 使用此答案

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

对我有用


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.