【问题标题】:GNU make 4.1: Missing separator when $(if ...) is true in a defined functionGNU make 4.1:当 $(if ...) 在定义的函数中为真时缺少分隔符
【发布时间】:2017-11-22 08:26:16
【问题描述】:

当在 shell 命令的输出中找不到字符串时,我试图在 Makefile 中生成错误。 shell 命令依赖于一个参数,因此整个事情都在一个定义的函数中。这是一个极简主义的例子:

define check_in_abcdefg
$(eval TMP := $(shell echo abcdefg))
$(if $(findstring $(1),$(TMP)),,$(error $(1) not in $(TMP)))
endef

$(call check_in_abcdefg,def)

all:
    @echo Hello, world!

在这种情况下,我希望这个 Makefile 输出 Hello, world!,但如果我用这个替换调用行,我希望它输出 xyz not in abcdefg

$(call check_in_abcdefg,xyz)

问题是使用def 检查我有这个输出:

Makefile:6: *** 缺少分隔符。停下来。

第 6 行是$(call check_in_abcdefg,def)

为什么$(if ...) 条件为真时语法检查失败,因为它实际上是空的?

请注意,虚拟目标 all 中的 echo 命令正确地前面有一个制表符,而不是四个空格。我正在运行GNU make 4.1.90 built for Windows32,而新版本的GNU make 似乎不会发生这种情况。我正在寻找任何可以帮助我使用 GNU make 4.1.90

的答案

【问题讨论】:

  • 我无法重现您的问题(x86_64-pc-msys 上的 GNU Make 4.2.1)。
  • @FelixPalmen 感谢您的尝试,实际上我只是尝试使用 GNU make 4.2 并且它似乎有效。我不知道为什么这会在 4.1.90 版本中失败,不幸的是它是在我的上下文中全局部署的。
  • 我使用 GNU Make 4.1 x86_64-pc-linux-gnu,当第 3 行计算为 true 时,我有同样的错误。如果指定了某些内容,该问题似乎会得到解决,例如:$(if $(findstring $(1), $(TMP), $(errror $(1) is in $(TMP)), $(error $(1) is not in $(TMP))) 有效。希望这可以帮助
  • @Hollyol 感谢您的尝试,但是这对我来说并不适用,因为问题发生在之后。在您的情况下,它不会发生,因为make 在错误处停止,但是如果您输入信息而不是失败:$(if $(findstring $(1),$(TMP)),$(info OK),$(error $(1) not in $(TMP)))。这将显示OK,后跟*** missing separator. Stop.
  • 4.1.90 是内部发布版本(这就是“90”的意思;所有“9x”版本都是内部版本)。任何人都将它用于生产用途真的很糟糕。无法知道您为什么会看到这种行为,因为无法知道您使用的是什么实际代码。可能会在下一个版本之前在同一版本中引入然后修复的各种错误,所有版本均为“4.1.90”,其中大多数未在 NEWS 等中明确指出。

标签: makefile gnu-make


【解决方案1】:

我不确定为什么较旧的 make 版本会在这里阻塞,但您可以像这样使用一个大的 $(eval ) 使其工作:

define check_in_abcdefg
$(eval
  TMP := $$(shell echo abcdefg)
  ifeq ($$(findstring $$(1),$$(TMP)),)
      $$(error $$(1) not in $$(TMP))
  endif
)
endef

$(call check_in_abcdefg,def)

all:
        @echo Hello, world!

【讨论】:

  • 非常感谢,这非常有效。看到@MadScientist 对此问题的看法仍然很有趣。我在GNU make 4.2的更改日志中没有看到任何相关内容
  • 为了完整性:请注意缩进是空格而不是制表符,因为它不是规则。将标签放在这里会使xyz 失败。
【解决方案2】:

要回答为什么 GNU make 4.1 会抛出这个错误的问题:那个版本的 GNU make 错误地处理了换行符。在您的示例中:

define check_in_abcdefg
$(eval TMP := $(shell echo abcdefg))
$(if $(findstring $(1),$(TMP)),,$(error $(1) not in $(TMP)))
endef

$(call check_in_abcdefg,def)

已定义宏的第一行(eval)扩展为空字符串,第二行(if)也是如此。因此,call 扩展为单个换行符。

那个版本的 GNU make 没有正确地忽略这个换行符,而是抛出一个错误。您可以通过删除换行符来更改您的 makefile 以在旧版本中工作:

define check_in_abcdefg
$(eval TMP := $(shell echo abcdefg))$(if $(findstring $(1),$(TMP)),,$(error $(1) not in $(TMP)))
endef

$(call check_in_abcdefg,def)

【讨论】:

  • 感谢您对这个有趣的解释(以及您在 GNU make 上所做的工作)。如果我们不更新到 4.2 或更新版本,我会尽量记住这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-01
  • 2012-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-13
相关资源
最近更新 更多