You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何延迟Makefile中$*的替换时机?

如何延迟Makefile中$*的替换时机?

这个问题我之前折腾Makefile的时候也碰到过!核心问题出在Make的变量展开机制上:你定义BUILD_CMD的时候,Make会立即解析变量里的所有特殊字符,这时候$*还没有对应的模式目标匹配值(比如你执行make bcm2836-source时的bcm2836),所以直接展开成空字符串了,难怪输出目录不对。你之前试的\$*没用,是因为它只是让Make把$*作为普通字符保留下来,但变量的展开时机还是在解析阶段,这时候$*依然没有有效值。

给你两个最实用的解决办法,选哪个看你的习惯:

方法一:启用二次展开(Secondary Expansion)

Make的二次展开特性可以让目标和依赖在匹配到具体模式之后,再重新展开一次变量和命令,刚好能解决你的问题。

步骤很简单:

  1. 在Makefile开头加上开启二次展开的声明
  2. 把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函数的延迟展开特性。

修改方式:

  1. 把BUILD_CMD里的$(OUTPUT_DIR)/$*改成$(OUTPUT_DIR)/$1($1表示call函数传递的第一个参数)
  2. 在目标命令里用$(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 14:37:59