Makefile GNU make 4.1:定义函数中的$(if…)为true时缺少分隔符

Makefile GNU make 4.1:定义函数中的$(if…)为true时缺少分隔符,makefile,gnu-make,Makefile,Gnu Make,当在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

当在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
在这种情况下,但是如果我用这个替换呼叫线路,我希望它在abcdefg中输出xyz而不是:

$(call check_in_abcdefg,xyz)
问题是,通过
def
检查,我有以下输出:

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

其中第6行是
$(调用check\u in\u abcdefg,def)

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


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

的答案,我不知道为什么较旧的
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!

为了回答为什么GNUMake4.1抛出这个错误的问题:GNUMake的那个版本错误地处理了新行。在您的示例中:

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)也扩展为空字符串。因此,
调用
扩展为单个换行符

该版本的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)

我无法重现您的问题(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
时,我有相同的错误。如果指定了某些内容,该问题似乎得到了解决,例如:
$(如果$(findstring$(1),$(TMP),$(error$(1)在$(TMP)中,$(error$(1)不在$(TMP)中)
有效。希望这可以help@Hollyol感谢您的尝试,但是这对我来说并不起作用,因为问题发生在之后。在您的情况下,它不会发生,因为
make
会在错误处停止,但是如果您在失败时放置一个信息:
$(if$(findstring$(1),$(TMP)),$(info OK),$(error$(1)不在$(TMP)中)
。显示
OK
,后跟
***缺少分隔符。停止。
4.1.90是内部版本(这就是“90”的意思;所有“9x”版本都是内部版本)。任何人将其用于生产用途都是非常糟糕的。无法知道您为什么会看到这种行为,因为无法知道您正在使用的实际代码。可能会引入各种错误,然后在下一版本之前在同一版本中修复,所有这些都是版本“4.1.90”,而且大多数都没有在新闻中明确指出,等等。非常感谢,这非常好用。我仍然很有兴趣看到大家对这个问题的看法。我还没有在GNU make 4.2的更改日志中看到任何与完整性相关的内容:注意缩进是空格而不是制表符,因为这不是一个规则。将制表符放在这里将使案例
xyz
失败。感谢您的有趣解释(以及您在
gnumake
上的工作)。如果我们不更新到
4.2
或更新版本,我会尽量记住这一点。