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

为何通配符在静态模式规则的先决条件中无法生效?

问题背景

目录结构

src/whatever/foo
Makefile

Makefile示例

out/bar : src/*/foo
    @echo $^

# ----> 正常执行,输出:   src/whatever/foo


out/foo : out/% : src/*/%
    @echo $^

# ----> 错误:     No rule to make target 'src/*/foo'

执行make out/foo为何无法正常工作?通配符在静态模式规则中的表现为何与普通规则不同?

有相关讨论提到“通配符在静态模式规则中不受支持”,但GNU Make手册中未找到明确说明。

已知可以通过$$(wildcard...)结合.SECONDEXPANSION让示例正常运行,但为何必须这么做?

编辑1

这可能和文件名/模式的区别有关。以下写法同样无法生效:

out2/foo : out2/% : $(wildcard src/*/%)
    @echo $^
### ----> 错误,无输出

尽管按手册说明,wildcard函数应能展开参数中的星号(手册称其为“文件名模式”)。

问题解答

1. 普通规则与静态模式规则的通配符处理逻辑差异

普通规则的依赖列表(比如src/*/foo)会在读取Makefile阶段自动触发通配符展开——make会直接扫描文件系统,把*替换成匹配的目录/文件名,所以src/*/foo能正确展开为src/whatever/foo。

但静态模式规则的结构是目标列表: 模式: 依赖模式,这里的src/*/%属于依赖模式,make会把它当作一个带模式占位符%的模板,而不是普通的文件名通配符。在解析静态模式规则时,make不会自动展开这里的*,而是把src/*/%整体当作一个包含%的模式字符串,试图寻找匹配src/*/%格式的文件——但实际文件是src/whatever/foo,*在这里不是通配符,而是字面量,自然找不到对应的文件,所以报错。

2. 直接用$(wildcard src/*/%)无效的原因

$(wildcard ...)是在读取Makefile阶段执行的,此时%还没有被替换成具体的stem(这里是foo),src/*/%中的%会被当作字面量字符处理。而你的文件系统里没有src/*/%这种格式的文件,所以wildcard返回空,依赖列表为空,执行时自然没有输出。

3. 为何需要.SECONDEXPANSION和$$(wildcard...)

.SECONDEXPANSION会让make对规则的依赖进行二次展开:第一次展开在读取Makefile阶段,第二次展开在匹配到具体目标、确定stem之后。

使用$$(wildcard...)时,第一次展开会把$$变成$,得到$(wildcard src/*/foo);等到二次展开阶段,%已经被替换成了实际的stemfoo,此时wildcard函数才会正确扫描文件系统,展开src/*/foo为真实存在的文件路径,依赖才能正确匹配。

内容的提问来源于stack exchange,提问作者L. Bruce

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.11 12:42:45