第三章 Linux内核源码获取与配置:版本选择、下载与裁剪实战
做BSP开发这些年,我见过太多人在内核版本选择上栽跟头。有人追新追到驱动全崩,有人死守老版本结果新硬件不支持。说白了,选内核版本就像选工具——不是越新越好,是越合适越好。
这一章,咱们把内核源码获取和配置这件事彻底讲透。从版本策略到下载解压,再到Kconfig/Makefile的配置体系,最后上手menuconfig做一次真正的裁剪实战。
3.1 内核版本选择策略:别盲目追新
我个人的习惯是:先看硬件,再看社区,最后看长期支持。你想想看,一个BSP项目少说跑两三年,选个短期版本那不是给自己挖坑吗?
| 版本类型 | 特点 | 适用场景 |
|---|---|---|
| 长期支持版(LTS) | 维护周期4-6年,稳定可靠 | 产品级BSP首选 |
| 主线版(Mainline) | 最新特性,两周更新一次 | 原型验证、新硬件适配 |
| 稳定版(Stable) | 基于主线,修复关键bug | 短期项目或快速迭代 |
| 实时版(RT) | 抢占式调度,低延迟 | 工业控制、音视频处理 |
我的经验之谈:做BSP裁剪,优先选最新的LTS版本。比如现在6.1 LTS和6.6 LTS都是好选择。别碰那些刚发布不到三个月的主线版本——我在项目里吃过这个亏,驱动还没适配完,内核API又变了。
3.2 内核源码下载与解压
源码获取其实就两条路:从kernel.org下载官方包,或者从git仓库克隆。我建议初学者先下载tar包,省去git历史占用的空间。
# 方式一:下载tar包(推荐)
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.8.tar.xz
tar -xf linux-6.6.8.tar.xz
cd linux-6.6.8
# 方式二:git克隆(适合需要追踪历史)
git clone --depth 1 --branch v6.6.8 \
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
小技巧:下载时加个--depth 1参数,只拉取最新代码,省流量也省时间。我每次做新项目都这么干,除非需要看某个驱动的提交历史。
解压之后,你会在根目录看到一堆文件夹。别慌,核心的就这几个:
- arch/ — 架构相关代码,ARM、RISC-V、x86都在这里
- drivers/ — 设备驱动,BSP裁剪的主战场
- kernel/ — 核心调度、进程管理
- fs/ — 文件系统实现
- net/ — 网络协议栈
3.3 内核配置系统:Kconfig与Makefile
内核的配置系统,说白了就是一套「选择题」框架。Kconfig定义题目,Makefile根据答案决定编译什么。这两兄弟配合得天衣无缝。
3.3.1 Kconfig语法速览
Kconfig文件里,每个配置项都是一个选项。我挑个最常见的例子:
config CONFIG_DRIVER_UART
bool "UART Driver Support"
default y
help
Enable this to support UART communication.
Say Y if your board uses serial console.
这里bool表示开关型选项,要么编译要么不编译。default y就是默认开启。还有tristate类型,支持编译成模块(.ko文件)。
注意:Kconfig里depends on和select这两个关键字最容易搞混。depends on是依赖关系——A依赖B,B没选A就不可见。select是反向选择——选了A自动选B。我曾经因为用错select导致内核编译出一堆不需要的驱动,镜像大了30%。
3.3.2 Makefile如何配合
Kconfig定义完选项,Makefile根据CONFIG_*变量决定编译行为:
# 如果CONFIG_DRIVER_UART=y,编译进内核
obj-$(CONFIG_DRIVER_UART) += uart.o
# 如果=m,编译成模块
obj-$(CONFIG_DRIVER_UART) += uart.o
# 如果=n,不编译
嗯,这里要注意:obj-y是编译进内核镜像,obj-m是编译成可加载模块。裁剪的时候,能用模块就别编译进内核,这样镜像小,启动快。
3.4 menuconfig图形化配置实战
好了,理论说完了,咱们上手干一次。menuconfig是内核配置的图形界面,基于ncurses库。执行起来很简单:
make menuconfig
你会看到一个蓝底白字的菜单界面。上下键移动,回车进入子菜单,空格切换选项状态。Y是编译进内核,M是编译成模块,N是不编译。
我一般按这个顺序裁剪:
- General setup — 保留本地版本、控制组,关掉不用的审计和调试
- Processor type and features — 选对CPU型号,关掉SMP如果单核
- Device Drivers — 这是大头,只留板子上有的外设驱动
- File systems — 只留需要的文件系统,比如ext4、proc、sysfs
- Networking support — 不需要网络就整个关掉,能省不少空间
实战案例:我之前做一个IoT网关项目,板子是ARM Cortex-A7,256MB Flash。默认配置编译出来内核镜像12MB,根本放不下。我花了半天时间,把不需要的驱动全砍掉,网络协议栈只留TCP/IP,文件系统只留squashfs和proc。最后镜像压缩后只有2.3MB,完美塞进去。
裁剪的时候,有个小技巧:用/键搜索配置项。比如你想找SPI驱动,按/输入SPI,它会列出所有相关选项和路径。这比一层层翻菜单快多了。
3.5 知识体系总览
下面这张图,把内核源码获取到配置裁剪的整个流程串起来了。我建议你保存下来,每次做BSP项目时对照着走一遍。
3.6 避坑指南
最后,分享几个我踩过的坑,你遇到了能少走弯路:
- 不要直接改
.config文件 — 手动改容易格式错误,用menuconfig最安全 - 保存旧配置 — 每次裁剪前备份
.config,改崩了能恢复 - 交叉编译别忘指定架构 — 做ARM BSP时,记得
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig - 依赖链检查 — 关掉某个驱动前,看看有没有其他模块依赖它
我曾经犯过的错:有一次裁剪网络子系统,图省事直接把NET整个关了。结果内核编译是成功了,但板子启动后连控制台都打不开——因为串口驱动依赖网络子系统的某些基础设施。从那以后,我每次裁剪都会先make savedefconfig生成精简配置,再手动检查一遍依赖。