4、内核配置与编译:Linux内核源码管理、内核配置选项、内核编译与安装
说到Linux内核,很多刚入行的朋友会觉得它很神秘。其实说白了,内核就是一个大号的程序,负责管理硬件、调度任务、提供系统调用。咱们做嵌入式系统,内核的配置和编译是绕不开的一关。
我个人习惯把内核配置比作「搭积木」。你需要什么功能,就选上什么模块。不需要的,坚决去掉。为什么?因为嵌入式设备的资源就那么点,你塞一堆没用的驱动进去,不光浪费空间,还可能引发奇怪的问题。
4.1 内核源码管理
先聊聊源码怎么管。我见过不少团队,内核源码直接丢在Buildroot的dl目录下,每次清理就没了。这其实是个坑。
我的做法是:单独建一个内核源码仓库,用Git管理。Buildroot里通过BR2_LINUX_KERNEL_CUSTOM_REPO_URL指向这个仓库。这样好处很明显——你可以打tag、做分支、回退版本,甚至对比不同板子的内核差异。
核心要点:内核源码不要依赖Buildroot自动下载,自己维护一份干净的源码树。
具体来说,Buildroot支持以下几种内核源码来源:
| 来源方式 | 配置项 | 适用场景 |
|---|---|---|
| 官方内核tarball | BR2_LINUX_KERNEL_CUSTOM_VERSION | 快速原型验证 |
| Git仓库 | BR2_LINUX_KERNEL_CUSTOM_GIT | 团队协作开发 |
| 本地路径 | BR2_LINUX_KERNEL_CUSTOM_LOCAL | 调试和测试 |
| 补丁集 | BR2_LINUX_KERNEL_PATCH | 适配特定硬件 |
嗯,这里要注意:如果你用本地路径,Buildroot不会自动清理编译产物。我曾经因为这个踩过坑——改了配置没重新make,结果烧进去的内核还是旧的。
4.2 内核配置选项
配置内核,最常用的命令就是:
make linux-menuconfig
这个命令会打开一个基于ncurses的图形界面。你想想看,几千个配置选项,要是没有图形界面,光靠手敲make config,那得疯掉。
配置选项大致分三类:
- Y(built-in):编译进内核镜像,直接可用。适合必须的功能,比如根文件系统驱动。
- M(module):编译成独立模块,需要时再加载。适合不常用的驱动,比如USB网卡。
- N(not set):不编译。省空间、省时间。
我的经验:嵌入式设备尽量多用Y,少用M。因为模块加载需要文件系统支持,万一根文件系统还没挂载,模块就加载不了。这就成了「先有鸡还是先有蛋」的问题。
配置过程中,有几个关键路径你必须知道:
General setup— 内核基础设置,比如版本号、压缩方式System Type— CPU架构和平台选择,ARM、MIPS、RISC-V都在这里Device Drivers— 设备驱动,这是最庞大的部分File systems— 文件系统支持,ext4、squashfs、overlayfs等Kernel hacking— 调试选项,产品发布前记得关掉
我曾经接手过一个项目,前任工程师把Kernel hacking里的所有调试选项都打开了。结果内核镜像大了30%,启动速度慢了将近一倍。嗯,这就是典型的「配置洁癖」缺失。
4.3 内核编译与安装
配置好了,接下来就是编译。Buildroot里编译内核很简单:
make linux
或者直接全量编译:
make
但这里有个细节——编译内核时,Buildroot会先检查配置是否变化。如果没变,它不会重新编译。这本来是好事,但有时候你改了设备树文件(dts),Buildroot却不知道。
注意:修改设备树后,务必执行 make linux-rebuild 强制重新编译内核。否则你改的设备树不会生效。
编译完成后,内核镜像和模块会被安装到指定目录。默认路径是:
output/images/
├── zImage # 压缩后的内核镜像
├── vmlinux # 未压缩的内核(带调试信息)
├── *.dtb # 设备树二进制文件
└── ...
模块则安装到:
output/target/lib/modules/<内核版本>/
我个人习惯在编译完成后,手动检查一下镜像大小:
ls -lh output/images/zImage
如果发现镜像异常大,我会回头看看配置里是不是不小心打开了什么不该开的东西。比如,我曾经发现某个项目的内核镜像有12MB,查了半天,原来是打开了CONFIG_DEBUG_INFO,把调试符号都编译进去了。
4.4 内核配置的避坑指南
最后,分享几个我这些年总结出来的经验:
- 不要直接修改
.config文件。用make linux-menuconfig来改,否则格式容易乱。 - 保存配置快照。每次调通一个功能,就把
.config备份一下。我习惯命名为config_<日期>_<功能>。 - 关注内核日志。编译时如果有warning,不要忽略。我曾经忽略了一个驱动编译警告,结果那个驱动在特定硬件上根本跑不起来。
- 善用
make linux-savedefconfig。这个命令会生成一个精简版的配置文件,只保留非默认选项。非常适合做配置的版本管理。
一句话总结:内核配置是门手艺活,多配、多试、多总结,慢慢就有感觉了。
最后说一句:内核配置没有银弹。每个项目都有自己的特殊性。多动手、多踩坑,慢慢你就能找到最适合自己项目的配置方案。