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

Make中filter-out语句为何未达预期?(make 3.81)

关于Makefile中filter-out语句的问题

问题场景

我正在阅读make手册解析现有Makefile,卡在了包含filter-out的语句:

KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG)

其中KERNEL_ELF = target/aarch64-unknown-none-softfloat/release/kernel,因此filter-out部分实际为:

$(filter-out %: ,$(file < target/aarch64-unknown-none-softfloat/release/kernel.d))

我原本认为这段代码会读取target/aarch64-unknown-none-softfloat/release/kernel.d文件,过滤掉所有以: 结尾的字符串。该文件内容如下:

/Users/simgar/projects/rust-raspberrypi-OS-tutorials/01_wait_forever/target/aarch64-unknown-none-softfloat/release/kernel: /Users/simgar/projects/rust-raspberrypi-OS-tutorials/01_wait_forever/build.rs /Users/simgar/projects/rust-raspberrypi-OS-tutorials/01_wait_forever/src/_arch/aarch64/cpu/boot.rs /Users/simgar/projects/rust-raspberrypi-OS-tutorials/01_wait_forever/src/_arch/aarch64/cpu/boot.s /Users/simgar/projects/rust-raspberrypi-OS-tutorials/01_wait_forever/src/bsp/raspberrypi/kernel.ld /Users/simgar/projects/rust-raspberrypi-OS-tutorials/01_wait_forever/src/bsp/raspberrypi.rs /Users/simgar/projects/rust-raspberrypi-OS-tutorials/01_wait_forever/src/bsp.rs /Users/simgar/projects/rust-raspberrypi-OS-tutorials/01_wait_forever/src/cpu/boot.rs /Users/simgar/projects/rust-raspberrypi-OS-tutorials/01_wait_forever/src/cpu.rs /Users/simgar/projects/rust-raspberrypi-OS-tutorials/01_wait_forever/src/main.rs /Users/simgar/projects/rust-raspberrypi-OS-tutorials/01_wait_forever/src/panic_wait.rs

我预期得到除第一个路径外的所有内容,但实际结果为空。请问正确预期是什么?我的推理哪里出错了?(注:make版本为3.81)


问题分析与解决

1. 核心问题:file函数不兼容你的make版本

file函数是GNU Make 4.0及以上版本才新增的特性,而你使用的是3.81版本。在3.81中,$(file < ...)会被当作未定义的变量展开,结果是空字符串。因此整个filter-out处理的是空内容,最终输出自然为空。

2. 过滤规则的逻辑偏差

即便使用支持file函数的高版本make,你的过滤规则%: 也无法达到预期:

  • Make的通配符%匹配的是空格分隔的单个单词,文件里的第一个元素是/path/to/kernel:(冒号后是空格分隔符,不属于这个单词本身)
  • 你写的%: 试图匹配以: 结尾的字符串,但实际上第一个单词是以:结尾,正确的过滤规则应该是%:(不带空格)

3. 适配make 3.81的正确写法

在3.81中,要读取.d文件并提取依赖列表,可以借助shell函数调用sed命令:

KERNEL_ELF_DEPS = $(shell sed 's/^[^:]*: //' $(KERNEL_ELF).d) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG)

sed 's/^[^:]*: //'会删除行首到第一个: 的所有内容,直接保留后面的依赖文件列表,这是make 3.81完全支持的方式。

如果后续升级到GNU Make 4.0+,修正过滤规则后的写法如下:

KERNEL_ELF_DEPS = $(filter-out %:,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG)

去掉%: 中的空格,就能正确匹配带冒号的目标文件名单词,过滤后得到预期的依赖列表。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 03:55:19