如何延迟Makefile中$*的替换时机?
如何延迟Makefile中$*的替换时机?
这个问题我之前折腾Makefile的时候也碰到过!核心问题出在Make的变量展开机制上:你定义BUILD_CMD的时候,Make会立即解析变量里的所有特殊字符,这时候$*还没有对应的模式目标匹配值(比如你执行make bcm2836-source时的bcm2836),所以直接展开成空字符串了,难怪输出目录不对。你之前试的\$*没用,是因为它只是让Make把$*作为普通字符保留下来,但变量的展开时机还是在解析阶段,这时候$*依然没有有效值。
给你两个最实用的解决办法,选哪个看你的习惯:
方法一:启用二次展开(Secondary Expansion)
Make的二次展开特性可以让目标和依赖在匹配到具体模式之后,再重新展开一次变量和命令,刚好能解决你的问题。
步骤很简单:
- 在Makefile开头加上开启二次展开的声明
- 把
BUILD_CMD里的$*改成$$*(用两个$来转义,让第一次展开后保留$*,等二次展开时再替换成目标的模式部分)
修改后的代码示例:
# 开启二次展开,一定要放在变量定义之前 .SECONDEXPANSION: # 假设你的目录定义是这样的,根据实际情况调整 OUTPUT_DIR := ./output PROJECT_DIR := ./project BUILD_CMD := @make O=$(OUTPUT_DIR)/$$* \ BR2_EXTERNAL=$(PROJECT_DIR) \ -C $(PROJECT_DIR)/buildroot %-source: %-config ccache-dir dl-dir $(BUILD_CMD) source
当你执行make bcm2836-source时,二次展开会把$$*替换成bcm2836,O=$(OUTPUT_DIR)/bcm2836就完全正确了。
方法二:用call函数传递参数
如果不想启用二次展开,也可以把$*作为参数传递给BUILD_CMD,利用call函数的延迟展开特性。
修改方式:
- 把
BUILD_CMD里的$(OUTPUT_DIR)/$*改成$(OUTPUT_DIR)/$1($1表示call函数传递的第一个参数) - 在目标命令里用
$(call BUILD_CMD,$*)来调用,把当前目标的$*作为参数传进去
代码示例:
OUTPUT_DIR := ./output PROJECT_DIR := ./project # 用$1作为参数占位符 BUILD_CMD := @make O=$(OUTPUT_DIR)/$1 \ BR2_EXTERNAL=$(PROJECT_DIR) \ -C $(PROJECT_DIR)/buildroot %-source: %-config ccache-dir dl-dir $(call BUILD_CMD,$*) source
这种方式下,call函数会在目标执行时才展开,$*此时已经有了正确的模式值,传递给BUILD_CMD的$1就会替换成对应的字符串,效果和二次展开一样。
两种方法都能解决你的问题,个人更推荐二次展开,因为它能保持BUILD_CMD的结构和可读性,不需要修改调用方式。
备注:内容来源于stack exchange,提问作者udance4ever
相关产品推荐
相关产品推荐

