当尝试读取带有嵌套逻辑的makefile时,这一直困扰着我, Make 不允许缩进的 if 语句。为什么会这样,并且有一个好的方法来解决此限制,并且仍然具有可读的Makefile?
更新:我现在意识到这个问题是基于错误的前提,但是我相信,将其留在这里对于任何犯过与我相同的错误的人可能都是有价值的。
答案 0 :(得分:2)
我不知道您为什么会感到不支持缩进条件。在以下示例中使用它们时,它们似乎确实可以正常工作:
.PHONY: all
all:
CONFIGS :=
ifeq ($(CONFIG1),1)
$(info CONFIG1 selected)
CONFIGS += config1
all: config1
config1:
@echo $@
ifeq ($(CONFIG2),1)
$(info CONFIG2 selected)
CONFIGS += config2
all: config2
config2:
@echo $@
else
$(info CONFIG2 not selected)
endif
else
$(info CONFIG1 NOT selected)
endif
all:
@echo "all: $(CONFIGS)"
注意:在我的示例中,TABS可能无法在复制和粘贴后保存下来。因此,您必须重新输入它们以获取食谱。
试运行:
$ make
CONFIG1 NOT selected
all:
$ make CONFIG1=1
CONFIG1 selected
CONFIG2 not selected
config1
all: config1
$ make CONFIG1=1 CONFIG2=1
CONFIG1 selected
CONFIG2 selected
config1
config2
all: config1 config2
在某些情况下,压痕会导致问题。引用GNU make manual:
配方是
make
执行的动作。配方可能在同一行或每行都具有多个命令。 请注意:,您需要在每个配方行的开头添加一个制表符!这是一个模糊的地方,引起了人们的注意。
随着GNU make在一条规则后将所有TAB缩进行纳入该规则的配方,对于make CONFIG1=1
,以下操作将失败:
.PHONY: all
all:
CONFIGS :=
config1:
# TAB in the following line
@echo $@
# the following lines are indented with TABs
ifeq ($(CONFIG1),1)
CONFIGS += config1
test1:
@echo $@
endif
ifeq ($(CONFIG1),1)
all: config1
endif
all:
# TAB in the following line
@echo "all: $(CONFIGS)"
$ make CONFIG1=1
config1
ifeq (1,1)
/bin/sh: -c: line 0: syntax error near unexpected token `1,1'
/bin/sh: -c: line 0: `ifeq (1,1)'
make: *** [Makefile:9: config1] Error 1
.RECIPEPREFIX
设置为非空白字符,例如>
,并用它来指示配方行。 1 除非您有一个显示TAB和SPACE之间差异的编辑器,否则选择2可能会使您发疯。我建议改为使用替代项1 ...
以下内容适用于make CONFIG2=1
:
.PHONY: all
all:
CONFIGS :=
config2:
# TAB in the following line
@echo $@
# the following lines are indented with SPACES
ifeq ($(CONFIG2),1)
CONFIGS += config2
test2:
# 2 TABs in the following line
@echo $@
endif
ifeq ($(CONFIG2),1)
all: config2
endif
all:
# TAB in the following line
@echo "all: $(CONFIGS)"
$ make CONFIG2=1
config2
all: config2
1 ,您可能会想像这样将.RECIPEPREFIX
设置为SPACE:
_empty :=
_space := $(_empty) $(_empty)
.RECIPEPREFIX := $(_space)
,然后将编辑器切换为仅使用SPACE。但这使情况变得更糟,也就是说,make
现在无法区分普通缩进和配方缩进。如果您在上面的示例中进行尝试,您会注意到,现在对于启用缩进规则之一的任何调用都将失败。
答案 1 :(得分:0)
在别人的帮助下,我现在意识到我的问题是在错误的前提下提出的。 Makefile绝对 do 允许缩进的if语句,或者缩进的条件语句更加精确。他们不允许的条件-至少是开箱即用的-是附条件的标签。这是因为默认情况下, Make 将 tab 解释为特别有意义的字符。几乎所有以制表符开头的行都被解释为recipe的一部分。因此,任何 not 都不打算作为配方一部分的行(如条件语句)应 not 以制表符开头。
至于回答了我的问题的一部分,问他们为什么选择使用制表符,为什么我没有找到答案。也许设计师打算有条件地减少使用条件。
关于变通办法,在这里我将尝试描述一对夫妇。
如果您没有显示空白字符的编辑器,那么第一个解决方案就是一个痛苦的痛苦,但是如果这样做,最简单的方法可能就是添加一些空格缩进您的非配方代码。不过,这是一个非常骇人的解决方法,建议不要这样做。
另一种解决方案(由@Stefan Becker提供)是将special variable,.RECIPEPREFIX
设置为制表符以外的字符。这是我尝试过的一个示例:
.RECIPEPREFIX := >
# Now, all recipes will begin with the > character rather than a tab.
things = something another_thing something_else nothing
nothing = true
something: another_thing something_else
# See how each line of a recipe now begins with >.
# You can see I also added a tab after the >.
# These tabs doesn't mean anything to Make; it's just for readability.
> $(info Making $@.)
> @touch $@
another_thing:
> $(info Making $@.)
# See also how lines like comments can be tabbed,
# but no longer add anything meaningful to recipes.
> @touch $@
something_else:
> $(info Making $@.)
> @touch $@
# And just to prove the situation with conditionals is resolved...
# See how the @touch command begins with the new RECIPEPREFIX
# but the conditionals don't.
ifeq ($(nothing),true)
> $(info Also making nothing, because nothing is true.)
> @touch nothing
endif
.PHONY: everything_clean
everything_clean:
> $(info Cleaning up everything.)
> rm -f $(things)
值得记住的一件事是,配方行必须开始并使用新的RECIPEPREFIX
。就是说,这样的 不会起作用:
something: another_thing something_else
# Remember that the RECIPEPREFIX must come first.
# Indenting your recipe lines first and then using the RECIPEPRIFX will not work.
>$(info Making $@.)
>@touch $@