| name | linux-kernel-trim |
| description | 嵌入式 Linux 内核配置裁剪与优化。分析内核 .config 或 defconfig,识别不必要的子系统/驱动/功能,生成精简 defconfig 和详细裁剪报告。当用户提到以下内容时触发:Linux kernel trimming, kernel size reduction, kernel config optimization, minimize kernel, reduce kernel footprint, embedded Linux kernel customization, defconfig cleanup, disable unused kernel features, vmlinux size, kernel image too large, 内核裁剪, 内核精简, 内核瘦身, 内核配置优化, 去掉不需要的模块, 减小内核体积, 内核太大, 裁剪内核驱动, 精简Linux。当用户有嵌入式 Linux SDK 并希望减小 Flash/RAM 占用时也应触发,即使没有明确说'裁剪'。 |
Linux 内核裁剪
分析嵌入式 Linux 内核配置,根据硬件和功能需求识别可移除的子系统/驱动/功能,输出精简后的 defconfig 和结构化裁剪报告。
工作流
阶段 1:定位内核源码
用户的 SDK 结构事先未知,主动扫描 SDK 找到所需一切,尽量不用路径问题打扰用户。
步骤 1 — 找到内核源码树:
find <sdk_root> -maxdepth 5 -name "Kconfig" -path "*/kernel/*" 2>/dev/null
find <sdk_root> -maxdepth 5 -name "Makefile" -exec grep -l "^VERSION\s*=" {} \; 2>/dev/null
确认候选目录下有 arch/、drivers/、kernel/、Kconfig。
步骤 1.5 — 获取内核版本:
对于混合/厂商 SDK,最可靠的方式:
cd <kernel_root>
make kernelversion
输出精确版本号(如 5.10.110)。记录下来——LTS 版本决定了哪些 Kconfig 选项存在、哪些子系统可用。不同 LTS 分支(5.4、5.10、5.15、6.1、6.6)的 Kconfig 布局不同,部分选项跨版本有重命名/移除/新增。知道确切版本才能避免推荐不存在的选项。
步骤 2 — 找到板级 defconfig:
搜索常见位置:
arch/<arch>/configs/*_defconfig
vendor/ 或 device/ 目录下的 *_defconfig 或 *.config
- 构建系统配置目录(Buildroot:
configs/,Yocto: meta-*/recipes-kernel/)
步骤 3 — 找到设备树源文件:
find <kernel_root>/arch/ -name "*.dts" -o -name "*.dtsi" | grep -i <board_keyword>
设备树是关键——它准确描述了板子上有哪些硬件。
如果任何一项找到多个候选,询问用户确认。否则直接使用找到的结果。
阶段 2:了解目标
先自主读取 SDK构建硬件和功能画像,再向用户确认。
自动推断(在询问用户之前完成):
- 解析板级设备树(
.dts / .dtsi)——提取所有 compatible 字符串,盘点板上外设
- 读取现有 defconfig——分类已开启的选项
- 检查板级构建系统线索(BSP README、板级配置文件、Makefile 变量)
- 查找启动日志或 dmesg 记录(有时会存在 SDK 文档中)
向用户展示发现:"根据设备树和 defconfig 的分析,这块板子的硬件情况如下:[列表]。请确认或纠正。"
硬件画像 — 从 defconfig / 设备树推断或询问用户:
- SoC 架构(ARM、ARM64、RISC-V、MIPS、x86...)
- 存储类型及容量(NOR/NAND/eMMC,总 Flash 大小)
- RAM 大小
- 网络接口(以太网、WiFi、BLE、蜂窝、无)
- 显示(LCD/OLED/无)
- USB(host/device/OTG/无)
- 音频(I2S/codec/无)
- 其他外设(CAN、SPI 传感器、GPS、NFC...)
功能需求 — 产品实际需要什么:
- 需要的文件系统类型(ext4、squashfs、jffs2、overlayfs...)
- 网络协议(TCP/IP、蓝牙、WiFi 协议栈、NFS...)
- 安全特性(dm-crypt、SELinux、dm-verity、内核 TLS...)
- 量产版是否需要调试特性(printk 能否最小化?ftrace 能否去掉?)
- 是否需要模块加载,还是纯 built-in?
- 电源管理需求
记录为结构化清单——不在此清单中的子系统都是移除候选。
阶段 3:分析当前配置
读取当前 .config 或 defconfig,按以下 11 个分析维度系统性排查。每个维度列出当前已启用项,与阶段 2 的需求交叉对比,标记可移除项。
维度 1:架构与平台(CONFIG_ARCH_*)
- 确认只启用了目标 SoC 的架构和机型
- 移除同架构下其他 SoC 家族的支持(如 i.MX6 板子上关掉 CONFIG_ARCH_SUNXI、CONFIG_ARCH_ROCKCHIP 等)
- 检查 CONFIG_SMP——单核 SoC 不需要
维度 2:引导与启动(CONFIG_EFI、CONFIG_CMDLINE、initramfs)
- 引导方式:用的 EFI、U-Boot 还是裸机启动?关掉没用的引导协议支持
- Initramfs:CONFIG_BLK_DEV_INITRD 是否需要?如果 rootfs 直接挂载,initramfs 是额外开销
- CONFIG_CMDLINE_EXTEND vs CONFIG_CMDLINE_FROM_BOOTLOADER——与实际 bootloader 匹配
- 早期控制台(CONFIG_EARLY_PRINTK)——调试保留,量产移除
维度 3:设备树与板级硬件
- 解析板级
.dts/.dtsi,提取所有 compatible 字符串
- 与已启用的驱动交叉对比——设备树中没有匹配
compatible 的驱动是移除候选
- 检查
status = "disabled" 的节点——对应驱动肯定可移除
- 目标 SoC 的 pin controller、clock driver、interrupt controller 必须保留
维度 4:存储与文件系统
- Block 层:板子用块设备吗?纯 NOR Flash 小板可能连 CONFIG_BLOCK 都不需要
- 文件系统盘点:只保留 rootfs 和数据分区实际用的(如 squashfs + overlayfs + tmpfs + proc + sys)
- MTD 子系统:仅在裸 NOR/NAND 时需要;eMMC 走 block 层
- 移除所有未用的文件系统类型(btrfs、xfs、ntfs、nfs、cifs、ext2 等)
维度 5:网络协议栈
- 完全无网络:
# CONFIG_NET is not set(单项最大收益,~500KB-1MB)
- 需要网络但可精简:去掉未用协议(IPv6、SCTP、DCCP、DECnet、ATM、ISDN 等)
- Netfilter/iptables:没有防火墙/NAT 需求则移除
- 无线协议栈(cfg80211/mac80211):没有 WiFi 芯片则移除
- 蓝牙协议栈:没有 BT 芯片则移除
- CAN:仅车载场景保留
维度 6:多媒体与硬件加速器
- DRM/GPU(CONFIG_DRM):无屏设备移除(~300-500KB)
- 声音/ALSA(CONFIG_SOUND):无音频硬件则移除
- V4L2/media(CONFIG_MEDIA_SUPPORT):无摄像头/视频输入则移除
- Framebuffer(CONFIG_FB):已被 DRM 取代的遗留接口
- 硬件加密加速器:仅在 SoC 有加速器且使用时保留
维度 7:总线与外部接口
- USB(CONFIG_USB_SUPPORT):无 USB 口则整体移除;否则只保留需要的 HCI(xHCI/EHCI/DWC2/DWC3)和 class 驱动
- PCI(CONFIG_PCI):多数嵌入式 SoC 没有 PCI——移除后所有 PCI 驱动一并消失
- SDIO/MMC:用 SD 卡或 eMMC 则保留
- SPI/I2C:通常保留(传感器、PMIC),但精简总线下未用的设备驱动
- PCIe、SATA、NVMe:嵌入式罕见,通常可移除
维度 8:驱动
- 按
drivers/ 子目录逐个过:
drivers/input/:移除鼠标、游戏手柄、未用键盘类型
drivers/hwmon/:无硬件监控则移除
drivers/leds/:只保留板上 LED 控制器
drivers/rtc/:只保留板上 RTC 芯片
drivers/watchdog/:嵌入式通常保留(但只留板上看门狗驱动)
drivers/thermal/:SoC 有温控区则保留;否则可移除
drivers/iio/:工业 I/O——只保留实际存在的传感器
- 每个驱动分类以设备树
compatible 字符串为准
维度 9:电源管理与低功耗
- CONFIG_PM、CONFIG_SUSPEND、CONFIG_HIBERNATION——产品有睡眠模式则保留 PM/suspend;休眠(hibernation)嵌入式极少用
- CONFIG_CPU_FREQ:需要动态调频调压则保留
- CONFIG_CPU_IDLE:电池供电设备保留
- Runtime PM(CONFIG_PM_RUNTIME):通常为外设保留
- 移除休眠、基于 swap 的睡眠、笔记本特有的 PM 功能
维度 10:系统调用与功能组件
- CONFIG_CGROUPS:systemd 和容器需要;BusyBox init 可移除
- CONFIG_NAMESPACES:容器需要;否则可移除
- CONFIG_PERF_EVENTS、CONFIG_BPF_SYSCALL:调试/分析,量产可移除
- CONFIG_AUDIT:无 SELinux/安全审计则移除
- CONFIG_USERFAULTFD、CONFIG_RSEQ:现代用户空间特性——检查用户空间是否需要
- Crypto 子系统:精简到实际使用的算法(AES、SHA256、CRC32 是常见必留项)
维度 11:模块机制
- CONFIG_MODULES:如果产品纯 built-in(运行时不加载 .ko),关闭模块机制可节省代码和模块加载器(~30KB)
- CONFIG_MODULE_UNLOAD:如果用了模块但不需要运行时卸载,可关闭
- CONFIG_MODVERSIONS:仅树外模块或 ABI 兼容性需要;否则可移除
11 个维度分析完成后:
- 与阶段 2 的需求交叉对比——标记每一个没有匹配需求的已启用项
- 对于不确定产品是否需要的配置项,明确询问用户,而不是猜测。展示该选项控制什么、关闭的代价,让用户决定
- 如果已有编译输出,估算当前内核大小:
size vmlinux
ls -lh arch/<arch>/boot/*Image*
阶段 4:生成裁剪方案
按风险和收益分层组织建议:
Tier 1 — 安全移除(高置信度)
根据硬件画像明确不需要的:
- 不存在的硬件对应的驱动(如无屏时 CONFIG_DRM_*)
- 未使用的文件系统类型(如只用 squashfs+ext4 时的 CONFIG_BTRFS)
- 不需要的网络协议(如 CONFIG_BATMAN_ADV、CONFIG_DECNET)
- 过时子系统(WiFi-only 设备上的 CONFIG_HAMRADIO、CONFIG_ISDN、CONFIG_ATM)
- 量产不需要的调试特性(CONFIG_DEBUG_INFO、CONFIG_FTRACE、CONFIG_KPROBES、CONFIG_MAGIC_SYSRQ)
Tier 2 — 需要确认的移除(中等风险)
可能不需要但有隐含依赖的:
- CONFIG_CGROUPS、CONFIG_NAMESPACES(容器场景需要)
- 电源管理子特性(部分 PM 选项是架构强制的)
- 实际未用的加密算法
- 调度器特性(CONFIG_RT_GROUP_SCHED、CONFIG_FAIR_GROUP_SCHED)
Tier 3 — 激进优化(收益显著,需充分测试)
- CONFIG_PRINTK=n(省 ~100KB 但失去所有内核日志)
- CONFIG_BUG=n(省空间但失去 BUG/WARN 信息)
- CONFIG_EMBEDDED=y(解锁更多精简选项)
- CONFIG_CC_OPTIMIZE_FOR_SIZE=y(牺牲速度换体积)
- CONFIG_SLOB 分配器(比 SLUB 更小,适合极小系统)
- CONFIG_KERNEL_XZ 或 CONFIG_KERNEL_LZ4 压缩
- 降低 CONFIG_LOG_BUF_SHIFT
每条建议提供:
- 配置项:精确的 Kconfig 符号
- 当前值:y/m/n
- 建议值:n(或新值)
- 理由:为什么可以安全移除
- 体积影响:预估节省量
- 风险:错误移除可能导致什么问题
检查点:用户确认
应用任何改动之前,以可读格式向用户展示完整裁剪方案:
- Tier 1 项(安全移除)——表格列出
- Tier 2 项(需确认)——表格列出,每项需用户决定
- Tier 3 项(激进优化)——列出并解释权衡
询问用户确认应用哪些层级。等待用户回复后再继续,未经明确同意不得执行改动。
阶段 5:应用改动
生成裁剪配置片段并应用:
-
创建裁剪片段(trim.config):
# Tier 1: 安全移除
# CONFIG_DRM is not set
# CONFIG_SOUND is not set
# CONFIG_HAMRADIO is not set
...
# Tier 2: 用户确认的移除
# CONFIG_CGROUPS is not set
...
# 体积优化
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_KERNEL_XZ=y
-
使用 merge_config.sh 应用(内核自带工具):
cd <kernel_source>
make <board>_defconfig
scripts/kconfig/merge_config.sh .config <path>/trim.config
-
解决依赖 — 运行 make olddefconfig 自动解决 Kconfig 依赖问题。然后 diff 前后 .config 检查意外副作用(关掉一个选项可能自动关掉用户需要的东西)。
-
保存为新 defconfig:
make savedefconfig
cp defconfig arch/<arch>/configs/<board>_trimmed_defconfig
-
验证编译通过:
make -j$(nproc) 2>&1 | tee build.log
如果编译失败,分析错误——通常是缺少依赖需要重新开启。
阶段 6:度量结果并出报告
编译成功后,对比大小:
ls -lh arch/<arch>/boot/*Image*
size vmlinux
scripts/bloat-o-meter vmlinux.old vmlinux
生成裁剪报告(见下方报告模板)。
报告模板
# Linux 内核裁剪报告
## 目标
- **开发板**:<板名>
- **SoC**:<SoC 名称>
- **内核版本**:<x.y.z>
- **原始 defconfig**:<路径>
## 体积对比
| 指标 | 裁剪前 | 裁剪后 | 节省 |
|------|--------|--------|------|
| vmlinux text | | | |
| vmlinux data | | | |
| 压缩镜像 | | | |
## 已应用的改动
### Tier 1:安全移除
| 配置项 | 原值 | 新值 | 理由 | 预估节省 |
|--------|------|------|------|----------|
| CONFIG_DRM | y | n | 无显示 | ~200KB |
| ... | | | | |
### Tier 2:确认后移除
| 配置项 | 原值 | 新值 | 理由 | 预估节省 |
|--------|------|------|------|----------|
| ... | | | | |
### Tier 3:激进优化
| 配置项 | 原值 | 新值 | 理由 | 预估节省 |
|--------|------|------|------|----------|
| ... | | | | |
## 依赖解决
列出 `olddefconfig` 自动改变的选项及原因。
## 风险与测试建议
- 裁剪后需要功能测试的项
- 边界情况可能需要重新开启的功能
## 生成的文件
- `<board>_trimmed_defconfig` — 新 defconfig
- `trim.config` — 裁剪片段(可复用)
核心原则
-
阅读源码,不要猜测。 推荐移除某个配置项之前,先查看它的 Kconfig help 文本(grep -A 20 "config OPTION_NAME" <path>/Kconfig),理解它控制什么。有些选项有不明显的依赖关系。
-
设备树是硬件的真实来源。 板级 .dts/.dtsi 中没有引用的外设,对应驱动可以安全移除。但部分驱动即使没有 DT 节点也是需要的(平台驱动、纯软件子系统)。
-
迭代式裁剪。 不要一次全裁完。先应用 Tier 1,编译测试。再 Tier 2。再 Tier 3。每轮迭代应能生产出可启动的内核。
-
保留原始配置。 始终保持原始 defconfig 不动。在旁边生成新的 *_trimmed_defconfig。裁剪片段应为独立文件,确保过程可复现、可审计。
-
体积估算。 内核文档和实际经验提供粗略估算。精确数字唯一可靠的方法是编译对比。拿不准时,两个版本都编译再量。
-
不确定就问。 对于任何不确定是否需要的功能,不要猜测或默认移除——向用户展示该选项的作用和移除后果,让用户做决定。这比事后调试一个无法启动的内核要高效得多。
-
嵌入式常见大收益:
- 关闭所有未用文件系统(每个 50-200KB)
- 无屏设备关闭 DRM/GPU 栈(~300-500KB)
- 无音频关闭声音子系统(~100-300KB)
- 无 USB 关闭 USB 支持(~100-200KB)
- 不需要 IPv6 则关闭(~100KB)
- 关闭调试特性(CONFIG_DEBUG_INFO 单项可省数 MB vmlinux 体积)
- CONFIG_CC_OPTIMIZE_FOR_SIZE=y(~5-10% 缩减)
- 选择更小的压缩格式(XZ 最小,LZ4 启动最快)
参考文档