makefile - 多变量赋值的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。
知道如何防止这种情况吗?
解决方案
您正在使用递归扩展变量 ( 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 手册。
推荐阅读
- google-chrome-extension - Chrome 扩展程序:在扩展程序中导航时会自动创建新的历史记录
- python - Pandas:写入 Excel 在 Databricks 中不起作用
- algorithm - 我可以在扩展 (a + b) % k 时忽略最后一个 k 吗?
- r - 无法在 R-4.0.5 上安装 dplyr
- javascript - 如何使用浏览器和 Facebook 会话发送发布请求
- reactjs - Sentry:使用 React 时启用可读的堆栈跟踪
- installation - 在 Mac OS X 11.2.2 上使用 Anaconda 安装 PyGMO 期间的冲突
- c# - 在视图 C# MVC 中计算年龄
- android - Firebase身份验证未经许可更新用户配置文件
- r - 在 R 中执行详尽搜索的最快方法是什么