You need to enable JavaScript to run this app. GNU Makefile 多目录源文件编译中filter函数的必要性探究
优惠活动
大模型
产品
解决方案
定价
更多

GNU Makefile 多目录源文件编译中filter函数的必要性探究

核心认知偏差

你对patsubst函数的规则存在关键误解:patsubst并不会丢弃输入文本中不匹配指定模式的内容,它的实际处理逻辑是——对输入里所有空白分隔的单词逐次判断:匹配模式就按规则替换,不匹配就原样保留在输出结果中,不会自动过滤。

无filter时的实际执行过程

你修改后的Makefile里,foreach循环会依次遍历easy、medium两个源目录,每次循环会对全量SOURCES列表执行一遍patsubst转换,每一步的实际输出如下:

  • 第一次循环,dir = easy
    • 传入patsubst的输入是全量SOURCES:easy/a.cpp medium/b.cpp
    • 匹配规则是easy/%.cpp,替换规则是build/%.out
    • 逐词处理结果:
      • easy/a.cpp 匹配规则,替换为build/a.out
      • medium/b.cpp 不匹配当前规则,原样保留
    • 本次循环输出:build/a.out medium/b.cpp
  • 第二次循环,dir = medium
    • 传入patsubst的输入还是全量SOURCES:easy/a.cpp medium/b.cpp
    • 匹配规则切换为medium/%.cpp,替换规则是build/%.out
    • 逐词处理结果:
      • medium/b.cpp 匹配规则,替换为build/b.out
      • easy/a.cpp 不匹配当前规则,原样保留
    • 本次循环输出:easy/a.cpp build/b.out
  • 两次循环的输出直接拼接,最终得到错误的TARGETS:build/a.out medium/b.cpp easy/a.cpp build/b.out,和你实际运行看到的结果完全吻合。
filter的作用逻辑

filter函数的功能是从输入文本中提前筛出符合指定模式的条目,直接删除所有不匹配的内容,从源头避免不匹配的文件流入patsubst的处理流程。
加上filter后,每次循环的处理逻辑会变成:

  • 当dir = easy时,先通过filter easy/%,$(SOURCES)从全量源文件里筛出所有属于easy目录的文件,输入到patsubst的文本就只剩easy/a.cpp,处理后输出build/a.out,没有其他残留文件
  • 当dir = medium时,先筛出所有属于medium目录的文件,输入到patsubst的文本只剩medium/b.cpp,处理后输出build/b.out
  • 两次循环的结果拼接后,就得到了完全符合预期的TARGETS列表:build/a.out build/b.out
常见误区提醒

很多人初用Make内置函数都会踩这个坑:误以为patsubst会自动过滤输入里不匹配模式的条目,实际上它只会对匹配的项做规则替换,不匹配的项会原封不动留在输出结果里。在多目录批量路径转换的场景下,如果不提前用filter把不属于当前循环目录的文件筛掉,就会出现多余的源文件残留进目标列表的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.08 10:06:08