第2章:内核源码获取与配置系统
做嵌入式Linux开发,第一步就是拿到内核源码,然后把它配好。这事儿听起来简单,但里面坑不少。我见过不少新手,源码下载下来就急着编译,结果跑不起来,回头一看——配置压根没搞对。这一章,咱们就把源码获取和配置系统这摊事儿捋清楚。
2.1 从kernel.org获取源码
官方源码站就是 kernel.org。别去其他地方乱下,我吃过这个亏——有一次从第三方站点下了个包,编译到一半报错,查了半天发现是被篡改过的源码。
2.1.1 选择合适的内核版本
内核版本号分三部分:主版本号.次版本号.修订号。比如 5.10.120:
| 字段 | 含义 | 说明 |
|---|---|---|
| 5 | 主版本 | 大版本迭代,架构级变化 |
| 10 | 次版本 | 偶数=稳定版,奇数=开发版 |
| 120 | 修订号 | bug修复、安全补丁 |
我个人习惯选 LTS(长期支持) 版本。比如 5.10.x、5.15.x、6.1.x。产品开发用LTS最稳,社区会持续维护好几年。
2.1.2 下载与校验
下载命令很简单:
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.120.tar.xz
但别忘了校验。我建议你养成习惯,下载完立刻做这一步:
# 下载签名文件
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.120.tar.sign
# 导入内核维护者公钥
gpg --locate-keys torvalds@kernel.org gregkh@kernel.org
# 校验
xz -cd linux-5.10.120.tar.xz | gpg --verify linux-5.10.120.tar.sign -
2.2 内核配置系统初探:Kconfig与Makefile
内核的配置系统由两套机制组成:Kconfig 定义配置选项,Makefile 根据配置决定编译什么。说白了,Kconfig是菜单,Makefile是厨师。
2.2.1 Kconfig语法速览
每个驱动目录下都有 Kconfig 文件。打开看看:
# drivers/i2c/Kconfig 片段
config I2C
tristate "I2C support"
help
I2C is a low-speed serial bus protocol...
config I2C_CHARDEV
tristate "I2C device interface"
depends on I2C
help
Provides /dev/i2c-N interface...
关键字段:
- tristate:三态——不编译/编译进内核/编译为模块
- bool:二态——不编译/编译进内核
- depends on:依赖关系,父选项没选,子选项出不来
- select:反向依赖,选了它会自动选上另一个
2.2.2 Makefile如何配合Kconfig
Kconfig定义完选项,Makefile根据配置变量决定编译:
# drivers/i2c/Makefile
obj-$(CONFIG_I2C) += i2c-core.o
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
这里的 CONFIG_I2C 就是 Kconfig 里定义的配置宏。如果配置为 y,就编译进内核;配置为 m,就编译成模块;没配置就不编译。
2.3 menuconfig图形化配置
手动改 .config 文件太容易出错了。我建议你用 menuconfig,它是个基于ncurses的图形界面:
make menuconfig
界面分三栏:
- 左侧:菜单树,按功能分类
- 中间:选项说明
- 下方:快捷键提示
常用操作:
| 按键 | 功能 |
|---|---|
| Y | 编译进内核(*) |
| M | 编译为模块(M) |
| N | 不编译(空) |
| / | 搜索选项 |
| ? | 查看帮助 |
2.4 defconfig与配置文件管理
每次从头配内核太累了。实际项目中,我们都是基于 defconfig 来做的。
2.4.1 什么是defconfig
defconfig 是内核源码里预置的默认配置,放在 arch/<架构>/configs/ 目录下:
# 查看ARM64的默认配置
ls arch/arm64/configs/
defconfig # 通用默认
# 或者针对某款开发板
ls arch/arm/configs/
imx_v7_defconfig # i.MX7
bcm2835_defconfig # Raspberry Pi
使用方式:
make ARCH=arm64 defconfig
# 或者指定某款板子
make ARCH=arm imx_v7_defconfig
2.4.2 配置文件管理实战
我管理配置文件的流程是这样的:
- 基于defconfig生成初始配置
- 用menuconfig做定制修改
- 保存最终配置
# 第一步:生成基础配置
make ARCH=arm64 defconfig
# 第二步:手动调整
make ARCH=arm64 menuconfig
# 第三步:保存差异(只保存你改过的部分)
make ARCH=arm64 savedefconfig
# 生成 defconfig 文件,只包含与默认不同的选项
my_board_defconfig,放到项目目录下管理。不要直接改内核源码里的 defconfig,否则下次升级内核版本时你的配置就丢了。
2.4.3 配置文件的碎片化问题
产品开发中,经常需要管理多个配置变体。比如:
- 开发版:开启所有调试选项
- 量产版:关闭调试,开启优化
- 安全版:开启加密和SELinux
我建议用 配置文件片段(fragment) 来管理:
# debug.fragment
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_INFO=y
# production.fragment
CONFIG_DEBUG_KERNEL=n
CONFIG_DEBUG_INFO=n
# 合并配置
scripts/kconfig/merge_config.sh -m \
arch/arm64/configs/defconfig \
debug.fragment
这样,基础配置和差异化配置分开管理,清晰又灵活。
2.5 本章知识体系
下面这张图把内核配置的完整流程串起来了: