多变量赋值的 Makefile 问题
Makefile issue with multiple variable assignment
我在 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组件的源文件定义了多次。
就好像 Adder 块也在扩展 SwcName 的值 Main.
知道如何防止这种情况吗?
您正在使用默认的递归扩展变量 (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))))
不要忘记宏定义中的$$
。他们是需要的。有关完整说明,请参阅 the GNU make manual。
这是recursive vs simply expanded variables的事情。我猜 Debug_Includes
之前没有用 :=
初始化,这意味着它默认是一个递归扩展的变量。因此设置为$(RootDir)/$(SwcRootDir)/$(SwcName).mak
,内部变量只有在被引用时才会展开(此时SwcRootDir
会变成Components/$(SwcName)
)。
尝试在文件顶部使用 :=
初始化您的变量,使它们变得简单。然后它们会立即被赋值,内部变量会被设置为定义时的值。
我在 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组件的源文件定义了多次。 就好像 Adder 块也在扩展 SwcName 的值 Main.
知道如何防止这种情况吗?
您正在使用默认的递归扩展变量 (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))))
不要忘记宏定义中的$$
。他们是需要的。有关完整说明,请参阅 the GNU make manual。
这是recursive vs simply expanded variables的事情。我猜 Debug_Includes
之前没有用 :=
初始化,这意味着它默认是一个递归扩展的变量。因此设置为$(RootDir)/$(SwcRootDir)/$(SwcName).mak
,内部变量只有在被引用时才会展开(此时SwcRootDir
会变成Components/$(SwcName)
)。
尝试在文件顶部使用 :=
初始化您的变量,使它们变得简单。然后它们会立即被赋值,内部变量会被设置为定义时的值。