首页 > 解决方案 > 多变量赋值的Makefile问题

问题描述

我在 Makefile 中多次分配相同的变量时遇到问题。我正在制作一种模块化的 makefile,我只处理组件而不是每个源文件和包含目录。这第一个解决方案工作正常

MainRootDir = Components/Main
include               $(RootDir)/$(MainRootDir)/Main.mak
Debug_Includes +=    $(addprefix $(MainRootDir)/,$(Main_Includes))
Debug_ASM_Sources += $(addprefix $(MainRootDir)/,$(Main_ASM_Static))
Debug_CC_Sources +=  $(addprefix $(MainRootDir)/,$(Main_CC_Static))
Debug_ASM_Sources += $(addprefix $(CfgDir)/,     $(Main_ASM_Config))
Debug_CC_Sources +=  $(addprefix $(CfgDir)/,     $(Main_CC_Config))

AdderRootDir = Components/Adder
include               $(RootDir)/$(AdderRootDir)/Adder.mak
Debug_Includes +=    $(addprefix $(AdderRootDir)/,$(Adder_Includes))
Debug_ASM_Sources += $(addprefix $(AdderRootDir)/,$(Adder_ASM_Static))
Debug_CC_Sources +=  $(addprefix $(AdderRootDir)/,$(Adder_CC_Static))
Debug_ASM_Sources += $(addprefix $(CfgDir)/,      $(Adder_ASM_Config))
Debug_CC_Sources +=  $(addprefix $(CfgDir)/,      $(Adder_CC_Config))

但是,如果我尝试通过在每次添加软件组件之前定义变量和重新分配新值来标准化块,它就会停止工作:

SwcName = Main
SwcRootDir = Components/$(SwcName)
include               $(RootDir)/$(SwcRootDir)/$(SwcName).mak
Debug_Includes +=    $(addprefix $(SwcRootDir)/,$($(SwcName)_Includes))
Debug_ASM_Sources += $(addprefix $(SwcRootDir)/,$($(SwcName)_ASM_Static))
Debug_CC_Sources +=  $(addprefix $(SwcRootDir)/,$($(SwcName)_CC_Static))
Debug_ASM_Sources += $(addprefix $(CfgDir)/,    $($(SwcName)_ASM_Config))
Debug_CC_Sources +=  $(addprefix $(CfgDir)/,    $($(SwcName)_CC_Config))
 
SwcName = Adder
SwcRootDir = Components/$(SwcName)
include               $(RootDir)/$(SwcRootDir)/$(SwcName).mak
Debug_Includes +=    $(addprefix $(SwcRootDir)/,$($(SwcName)_Includes))
Debug_ASM_Sources += $(addprefix $(SwcRootDir)/,$($(SwcName)_ASM_Static))
Debug_CC_Sources +=  $(addprefix $(SwcRootDir)/,$($(SwcName)_CC_Static))
Debug_ASM_Sources += $(addprefix $(CfgDir)/,    $($(SwcName)_ASM_Config))
Debug_CC_Sources +=  $(addprefix $(CfgDir)/,    $($(SwcName)_CC_Config))

问题是组件 Main 的源文件被定义了多次。就好像加法器块也在用值 Main 扩展 SwcName。

知道如何防止这种情况吗?

标签: makefilegnu-make

解决方案


您正在使用递归扩展变量 ( var = ...),这是默认值。因此,make 推迟对赋值右侧的评估,直到真正需要变量的值。例子:

a = 1
b += $(a)
a = 2
b += $(a)

.PHONY: all
all:
    @echo $(b)

将打印2 2而不是1 2您期望的,因为 make 实际存储在变量中的b$(a) $(a),它仅在将配方传递all给 shell 之前对其进行评估。并且当时a只有一个值:它被分配的最后一个值,即2.

您可以使用简单的扩展变量 ( var := ...),而不是:

b :=
a := 1
b += $(a)
a := 2
b += $(a)

.PHONY: all
all:
    @echo $(b)

这将打印1 2. 不要忘记明显无用的b :=:它告诉 make 这b不是一个递归扩展变量,而是一个简单扩展的变量。与默认形式不同,分配给简单扩展变量的值在定义时进行评估,它的扩展不会延迟到需要变量的值时。

但是像你展示的那样重复大部分代码并不是最优的。确实,人类经常需要重复事情,但计算机几乎从来都不是最佳选择。如果您使用的是 GNU make,按照Tripleee的建议,您可以使用一种用户定义的函数:

Debug_Includes :=
Debug_ASM_Sources :=
...

# $(1) is the current SwcName
define MY_FUNC
SwcRootDir := Components/$(1)
include $$(RootDir)/$$(SwcRootDir)/$$(1).mak
Debug_Includes += $$(addprefix $$(SwcRootDir)/,$$($(1)_Includes))
Debug_ASM_Sources += $$(addprefix $$(SwcRootDir)/,$$($$(1)_ASM_Static))
...
endef

进而:

$(foreach SwcName,Main Adder,$(eval $(call MY_FUNC,$(SwcName))))

不要忘记$$宏定义中的。他们是需要的。有关完整说明,请参阅GNU make 手册


推荐阅读