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。这个命令会生成一个精简版的配置文件,只保留非默认选项。非常适合做配置的版本管理。

一句话总结:内核配置是门手艺活,多配、多试、多总结,慢慢就有感觉了。

内核配置与编译核心流程 内核源码管理 Git仓库 / 本地路径 内核配置 make linux-menuconfig 内核编译 make linux 配置选项类型 • Y (built-in) — 编译进内核 • M (module) — 编译为模块 • N (not set) — 不编译 嵌入式多用Y,少用M 关键配置路径 • General setup — 基础设置 • System Type — CPU架构 • Device Drivers — 设备驱动 • File systems — 文件系统 编译产物 • zImage — 压缩内核镜像 • vmlinux — 未压缩内核 • *.dtb — 设备树文件 • 内核模块 (.ko) 安装到 output/images/ 模块安装到 output/target/lib/modules/ ⚠ 常见坑点 修改设备树后需 make linux-rebuild | 不要直接编辑 .config 文件

最后说一句:内核配置没有银弹。每个项目都有自己的特殊性。多动手、多踩坑,慢慢你就能找到最适合自己项目的配置方案。

专注资料整理