ChatGPT解决这个技术问题 Extra ChatGPT

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

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

任何人都知道为什么它对我不起作用?


b
bobbogo

您可以使用以下方法(使用名为“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...) 的扩展虽然是空的

$$ 变成文字 $

${var} 变成 :-) (比如说)

副作用是 $var is [:-)] 出现在标准输出上

$(info...) 的扩展虽然是空的

Make 留下 echo Hello world Make 首先在 stdout 上打印 echo Hello world 让你知道它会要求 shell 做什么

首先在 stdout 上打印 echo Hello world,让您知道它会要求 shell 做什么

shell 在标准输出上打印 Hello world。


应该是(点).PHONY 而不是 PHONY?
t
tsenapathy

根据 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' 将在显示错误字符串后停止执行


哇,不知道这个。比 echo 好得多,它在日志中复制命令。
M
Max

来自“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

你解释得比作者好。竖起大拇指!
b
bobbogo

如果您只是想要一些输出,您想单独使用 $(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

$* 扩展为 % 模式在规则中匹配的词干。

$($*) 扩展为名称由 $* 给出的变量的值。

[ 和 ] 清楚地描绘了变量扩展。您也可以使用“和”或类似名称。

$(flavor $*) 告诉你它是什么类型的变量。注意:$(flavor) 采用变量名,而不是其扩展名。所以如果你说 make print-LDFLAGS,你会得到 $(flavor LDFLAGS),这就是你想要的。

$(info text) 提供输出。作为扩展的副作用,在其标准输出上打印文本。 $(info) 的扩展虽然是空的。你可以把它想象成@echo,但重要的是它不使用 shell,所以你不必担心 shell 引用规则。

@true 只是为规则提供命令。没有它,make 也会输出 print-blah 是最新的。我觉得@true 更清楚地表明它是无操作的。

运行它,你得到

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

感谢您的评论。我知道一旦我有足够的声誉,我可以发表评论,但我应该在此期间做什么?我相信我的答案提供了额外的价值,所以我不应该添加它吗?
我建议将其重写为与您正在评论的答案竞争的独立答案,而不是将其表述为对该答案的不合适的评论。
@JimNasby 是的,查尔斯的建议。实际上,简单地删除“抱歉没有足够的代表发表评论”之类的部分可能会有所帮助,因为它是一个危险信号。如果你把它变成一个完整的答案(可以随心所欲地编辑它),它应该做得很好。干杯。
太好了——现在这是一个更好的答案。 :)
M
MadScientist

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

myTarget: myDependencies
        @echo hi

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


佚名

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


我尝试了“@echo $(NDK_PROJECT_PATH)”,但仍然收到错误“build-local.mk:102: *** missing separator. Stop.”。我在“echo”之后只有 1 个空格,“@echo”之前没有空格或制表符。
你确定错误来自这一行吗?这条线是规则吗?她应该是缩进的……
T
Talespin_Kit

无需修改 Makefile。

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

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

J
Jonathan Leffler

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

生成文件...

all:
        @echo $(NDK_PROJECT_PATH)

命令:

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

输出:

echo /opt/ndk/project

不过这非常有用,我使用的 --just-printInstead of Execution 中是一样的
J
Jonathan Leffler

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 月),因此无法正式验证此答案。它只能用于说明问题发生的合理方式。


A
Andy

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

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

所以创建一个执行块


W
Wade

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

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

C
Community

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

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

对我有用


A
Abdul Jaleel

如果我想查看变量值,我通常会报错。(仅当您想查看该值时。它将停止执行。)

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


S
Samuel

您可以在 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