我正试图在Gnu Make中实现包含守卫。在这个Makefile中,第一个包含是OK的,而第二个包含失败并报错。
ifndef INCLUDED
INCLUDED = 1
$(info Including)
define macro
ifneq ($(1),)
define inner_macro
macro content...
endef
else
define inner_macro
endef
endif
endef
endif
同样的效果可以通过在包含前显式地给出INCLUDED = 1
来模拟,例如在命令行中。
Gentoo下的Gnu Make 4.1显示Makefile:14: *** missing separator. Stop.
,而Debian Wheezy下的Gnu Make 3.81显示Makefile:14: *** extraneous `endef'. Stop.
。在第一个包含中,它们都说:
Including
make: *** No targets. Stop.
如果我在第一次包含之后尝试$(eval $(call macro,whatever))
,它将按预期定义inner_macro
。
我分别使用make INCLUDED=1
和make
命令得到所描述的行为。
当我清除环境并禁用内置规则和变量:env -i make -rR INCLUDE=1
时,也会发生同样的情况。当我使用-p
来转储数据库时,没有INCLUDED=1
, macro
被定义为应该的样子,但是使用INCLUDED=1
,空的inner_macro
被定义。这在Make的两个版本中是一致的。这提示我,当条件为假时,Make以不同的方式解析Makefile,并认为macro
定义中的else
属于ifndef
。其他条件类型的行为完全相同。
如果我删除inner_macro
的两个定义,问题就解决了。
我阅读了info make conditional syntax
和info make multi-line
(以前的defining
)的手册页,但我没有发现任何警告,我仍然认为我没有做错什么。
- 我的结论正确吗?
- 这是一个bug在Make,还是我调用未定义的行为?
- 我应该如何在Gnu Make中实现包括守卫?
这是一个bug。到萨凡纳去报告。
在未接受的ifdef/ifndef条件中跟踪嵌套的define/endf有问题。如果你不使用嵌套的define/endf,那么它可以工作;例如(显然您可能无法在您的环境中这样做):
ifndef INCLUDED
INCLUDED = 1
$(info Including)
define macro
ifneq ($(1),)
inner_macro = macro content...
else
inner_macro =
endif
endef
endif