[TinyLinux-002] 突破极限:3.4MB 的内核是怎样炼成的?
系列简介:TinyLinux 是由 LabHub 发起的“大道至简” Linux 学习项目。我们通过对内核进行“剔骨”级的物理精简,旨在构建一个 100% 透明、可重现的极简实验室。
公众号:LabHub | 项目仓库:https://gitee.com/lynyujiang/tiny-linux.git
🛠 技术看板
- 实验目标:确立“QEMU 专用”原则,通过物理源码剔除与激进配置,将内核体积从 11MB 压榨至 3.4MB。
- 核心知识点:内核源码树结构 / Kconfig 依赖管理 / Stubbing 技术。
- 涉及脚本:
scripts/prune_kernel_source.sh
1. 知识点详注 (Technical Glossary)
- Kconfig:Linux 内核的配置系统脚本。它定义了内核的功能开关、依赖关系以及在
make menuconfig 中看到的菜单结构。 - **Stubbing (打桩)**:一种软件工程技术。当一个模块被删除,但其他模块仍试图调用它时,我们提供一个同名的“空函数”或“空文件”来欺骗编译器,确保链接不报错。
- Vmlinux:编译出来的原始、未压缩的静态内核二进制文件(通常很大,数百 MB)。
- **XZ (LZMA2)**:一种现代高压缩率算法。相比传统的 GZIP,XZ 能够识别更长的数据重复序列,非常适合压缩具有大量重复指令的内核二进制文件。
2. 理论背景 (Deep Theory)
2.1 为什么 Linux 内核如此庞大?
打开 Linux 6.12 的源码目录,你会发现它占据了近 2GB 的空间。其臃肿源于两个“无奈”:
- **全能性 (Universal)**:它必须同时支持 x86, ARM, RISC-V, MIPS 等几十种 CPU 架构。
- **包容性 (Inclusive)**:它内置了数万种驱动,从 90 年代的声卡到最新的 AI 加速卡。
2.2 “外科手术”的逻辑:物理级精简
仅仅在 make menuconfig 中关闭开关(.config)是不够的。即便你关掉了某个驱动,Makefile 依然会扫描相关目录,Kconfig 依然会解析依赖。物理精简的精髓在于:直接删除不参与编译的代码目录。但这会带来灾难性的依赖报错。我们需要利用 Stubbing 技术:
- 删除
drivers/gpu,但必须保留一个空的 Kconfig,否则内核根目录的 drivers/Kconfig 会因为找不到引用而罢工。
3. 源码与脚本深度走读 (Source Code Dive)
3.1 核心脚本:prune_kernel_source.sh
这是 TinyLinux 的“手术刀”。它的核心逻辑是按需剔除。
# 示例:物理剔除除了 x86 以外的所有架构代码
# 我们只保留 x86 核心逻辑,删除 arm, powerpc, s390 等
for arch in $(ls arch/); do
if [ "$arch" != "x86" ] && [ "$arch" != "Kconfig" ]; then
rm -rf "arch/$arch"
# 关键:创建一个空 Makefile 和最小化 Kconfig 防止构建系统崩溃
echo"obj-y :=" > "arch/$arch/Makefile"
echo"config ARCH_$(echo $arch | tr 'a-z' 'A-Z')" > "arch/$arch/Kconfig"
fi
done
3.2 关键配置:CONFIG_EXPERT=y
这个开关是所有精简操作的“上帝模式”。
- 作用:一旦开启,内核会暴露出许多被隐藏的底层组件开关。例如,你可以选择关闭
BUG() 宏支持、关掉内核符号表、甚至是选择不同的 RCU 实现。这是从“通用系统”迈向“嵌入式实验室”的必经之路。
4. 配置详解 (Config & Engineering)
在本阶段,我们执行了以下“切除手术”:
CONFIG_USB=n: 移除整个 USB 协议栈。虽然这让 QEMU 无法识别模拟优盘,但在串口开发模式下,这能节省约 400KB。CONFIG_DRM=n: 彻底拔掉显卡驱动。我们不再需要显示器,一切交互通过 ttyS0 进行。- 内核压缩切换:
# 将 bzImage 压缩算法改为 XZ
CONFIG_KERNEL_XZ=y
# 放弃 GZIP
# CONFIG_KERNEL_GZIP is not set
5. 工程实验步骤 (Lab Steps)
- 执行源码修剪: 运行项目自带的修剪脚本(注意:此操作不可逆,请确保有备份)。
./scripts/prune_kernel_source.sh
- 应用 Tiny 配置:
cd kernel && make tinylinux_defconfig
- 编译并观察体积:
make -j$(nproc) bzImage
5.1 观察点 (Observation Points)
重点关注编译输出的最后一行。bzImage 的大小应该从之前的 11MB 骤降至 3.4MB 左右。同时,尝试使用 du -sh kernel 查看源码树大小,你会发现它从 1.7GB 缩减到了 600MB 以内。
5.2 避坑指南
- 现象:
make 报错 No rule to make target 'samples/Makefile'。 - 原因: 物理删除了
samples/ 目录,但顶层 Makefile 仍试图进入该目录。 - 对策: 在
samples/ 目录下创建一个内容为空的 Makefile 文件,欺骗构建系统。
6. 验证与重现
- 检出命令:
git checkout 9b0ecf51e
- 预期输出:Success! Kernel: .../output/target/bzImagels -lh ...bzImage -> 3.4MB
7. 总结与延伸
通过本章,我们不仅实现了内核体积的飞跃,更掌握了 Linux 内核构建系统的底层逻辑。思考题: 既然我们可以物理删除源码,那我们能否把内核中所有的 printk 字符串也物理删除来进一步减小体积?这会对系统调试带来什么后果?
🌟 互动与支持
如果你觉得这个项目对理解 Linux 底层有帮助,请不要吝啬你的支持:
- 点赞 & 在看:点击右下角,让更多极客看到这个“活的代码教科书”。
- 关注 LabHub:第一时间获取 TinyLinux 的最新“手术”报告。
- Star 项目:点击 Gitee 仓库地址 给我们一个五星好评!
本文由 LabHub 团队原创,转载请注明出处。