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

如何在GNU Make中结合SECONDEXPANSION实现规则通配?

问题根源

当结合.SECONDEXPANSION使用$(PROJECT).%模式规则时,若$(PROJECT)是延迟展开变量(用=定义)或在规则解析阶段未完成赋值,第一次展开目标模式时$(PROJECT)不会被替换,导致Make无法识别%作为后缀匹配符,规则失效。即使$(PROJECT)是立即赋值变量,若依赖中需要引用后缀对应的变量(如$(foo_DEPS)),也需确保二次展开时能正确捕获%对应的后缀。

正确替换方法

1. 若$(PROJECT)为立即赋值变量(静态值)

直接使用$(PROJECT).%作为模式,结合二次展开引用后缀变量:

# 立即赋值PROJECT,确保第一次展开时能替换
PROJECT := myapp

# 定义对应后缀的依赖变量
foo_DEPS := src/foo.c src/common.c
bar_DEPS := src/bar.c src/common.c

.SECONDEXPANSION:
# 模式规则匹配myapp.foo、myapp.bar等目标
$(PROJECT).%: $$($$*_DEPS)
    @echo 编译目标: $@
    gcc -o $@ $^

关键逻辑:

  • PROJECT用:=立即赋值,第一次展开目标模式时替换为myapp.%,%正确匹配后缀(foo/bar)
  • 依赖中的$$($$*_DEPS)经过二次展开:第一次展开为$($*_DEPS),第二次展开时$*被替换为当前后缀(foo/bar),最终得到$(foo_DEPS)或$(bar_DEPS)

2. 若$(PROJECT)为延迟展开变量(动态值)

使用$(eval)动态生成模式规则,确保PROJECT赋值后再解析规则:

# 延迟赋值PROJECT(后续可能修改)
PROJECT = myapp

foo_DEPS := src/foo.c src/common.c
bar_DEPS := src/bar.c src/common.c

# 定义规则模板
define PROJECT_TEMPLATE
$(PROJECT).%: $$($$*_DEPS)
    @echo 编译目标: $@
    gcc -o $@ $^
endef

.SECONDEXPANSION:
# 动态生成规则,此时PROJECT已完成赋值
$(eval $(PROJECT_TEMPLATE))

$(eval)会在Makefile解析到该行时执行,此时PROJECT的最新值会被替换到模板中,生成正确的myapp.%模式规则。

3. 若$(PROJECT)是多项目列表

用$(foreach)遍历项目,生成每个项目的模式规则:

PROJECTS := app1 app2

foo_DEPS := src/foo.c src/common.c
bar_DEPS := src/bar.c src/common.c

.SECONDEXPANSION:
# 为每个项目生成对应的模式规则
$(foreach proj,$(PROJECTS),$(proj).%): $$($$*_DEPS)
    @echo 编译目标: $@
    gcc -o $@ $^

$(foreach)会展开为app1.% app2.%,每个都是独立的模式规则,分别匹配app1.foo、app2.bar等目标。

验证方法

执行make myapp.foo或make myapp.bar,若能正确加载对应依赖并执行编译命令,说明规则生效。

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 07:35:16