如何将Makefile中的%通配符规则标记为phony伪目标?
通配符Make规则标记伪目标的正确方法
核心问题成因
GNU Make 的 .PHONY 指令完全不支持通配符模式匹配,它接收的所有参数都会被当作字面目标名处理。你写的 .PHONY: %-tangnano-prog 只会把那个字符串本身(也就是名字真的叫 %-tangnano-prog 的目标)标记为伪目标,对所有符合 *-tangnano-prog 模式的具体目标(比如 blinky-tangnano-prog)没有任何标记效果。
这就解释了为什么你 touch 生成 blinky-tangnano-prog 实体文件后,Make 会把它当成普通文件做时间戳校验,发现它比依赖的 .fs 构建产物新,就直接提示“目标已是最新”,跳过了上传命令。
可靠的解决方法
- 最通用的经典写法:引入 FORCE 强制依赖
这是 Make 生态处理“模式规则不生成实体文件”的标准实现,不需要依赖特殊解析逻辑,不管目标是被命令行直接调用、还是被其他上层规则依赖,都能保证规则每次执行,效果和伪目标完全等价。
代码示例:
原理:只要规则依赖的目标本身是伪目标,Make 就会判定当前规则的目标始终需要重建,完全跳过对目标文件的存在性、时间戳检查。哪怕你生成了同名的空文件,也不会出现跳过执行的问题。# 定义通用强制依赖,本身标记为伪目标 .PHONY: FORCE clean all # 给原有通配符规则追加FORCE依赖 %-tangnano-prog: %-tangnano.fs FORCE openFPGALoader -b tangnano $^ - 严格走
.PHONY标记的写法:动态收集匹配目标
如果你希望严格使用原生伪目标机制,可以在 Make 解析阶段从命令行参数中筛选出符合模式的具体目标名,再加入伪目标列表:
代码示例:
注意:这个方案只对用户在命令行直接指定的目标生效。如果其他 Make 规则要依赖某个 prog 目标,收集逻辑无法覆盖到这类间接调用的目标,还是会被同名实体文件干扰。# 筛选命令行传入的所有符合prog命名规则的目标 USER_SPECIFIED_PROG := $(filter %-tangnano-prog,$(MAKECMDGOALS)) # 将筛选出的具体目标加入伪目标列表 .PHONY: $(USER_SPECIFIED_PROG) clean all # 原有通配符规则 %-tangnano-prog: %-tangnano.fs openFPGALoader -b tangnano $^
效果验证
用任意一种方案修改完成后,重新执行之前的测试流程:
touch blinky-tangnano-prog make blinky-tangnano-prog
不会再出现“目标已是最新”的提示,会正常触发FPGA上传命令。
内容的提问来源于stack exchange,提问作者Pepijn
相关产品推荐
相关产品推荐

