2. 内核源码获取与配置:从kernel.org获取源码、使用git管理内核源码、内核配置系统简介(Kconfig/Makefile)
做嵌入式Linux开发,第一步就是拿到内核源码。这事儿听起来简单,但里面门道不少。我见过不少新手直接从网盘下载一个压缩包就开始搞,结果后面版本混乱、补丁打不上,折腾好几天才发现是源码版本不对。
这一章,咱们就把源码获取和配置系统这两个基本功打扎实。说白了,就是解决两个问题:源码从哪来,以及怎么告诉内核你要什么。
2.1 从kernel.org获取源码
kernel.org 是Linux内核的官方发布站点。所有主线版本、稳定版、长期支持版(LTS)都从这里发布。我个人习惯只从这上面下载,第三方渠道的源码我一般不碰——万一被人动了手脚,查都查不出来。
内核版本号有固定的命名规则,举个例子:
| 版本号 | 含义 | 适用场景 |
|---|---|---|
| 5.10.100 | 主线版本5.10的第100个稳定补丁 | 通用嵌入式系统 |
| 5.10.100-rt50 | 实时抢占(RT)补丁版本 | 工业控制、机器人 |
| 5.4.200 | LTS长期支持版本 | 产品量产、车载系统 |
| 6.1.25 | 较新LTS版本 | 新硬件平台、功能需求多 |
下载方式有两种:
- 直接下载压缩包:在 kernel.org 找到对应版本,点
.tar.xz链接下载。解压后就能用。 - 通过 git 克隆:这个我后面细说。推荐用这种方式,方便后续管理。
2.2 使用git管理内核源码
git 是内核社区的官方版本管理工具。Linus Torvalds 本人就是 git 的创造者,所以内核源码天然就是为 git 设计的。
为什么要用 git?我举个例子。有一次我在给一个工控板移植驱动,需要同时维护三个版本:一个是原厂 BSP 内核,一个是主线内核,还有一个是我自己裁剪后的版本。没有 git,光文件对比就能把人逼疯。
基本操作流程:
# 克隆主线仓库(只克隆最新版本,省时间)
git clone --depth=1 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
# 进入目录
cd linux
# 查看当前版本
git describe --tags
# 切换到指定标签(比如某个稳定版)
git checkout v5.10.100
# 创建自己的开发分支
git checkout -b my_industrial_board_v1
这里有个关键点:--depth=1 是浅克隆,只下载最新一次提交。如果你不需要完整的提交历史,用这个能省大量时间和磁盘空间。我刚开始做嵌入式时不知道这个参数,每次克隆几十 GB 数据,等得心焦。
如果你需要给内核打补丁,git 的 am 和 format-patch 命令是标配:
# 应用补丁
git am 0001-my-driver-fix.patch
# 生成补丁(从当前分支相对于主线的改动)
git format-patch origin/master --stdout > my_changes.patch
2.3 内核配置系统简介(Kconfig/Makefile)
内核配置系统,说白了就是一套菜单系统。你通过它告诉内核:我要哪些功能,不要哪些功能。背后是两个核心文件在起作用:Kconfig 和 Makefile。
2.3.1 Kconfig:定义配置选项
Kconfig 文件定义了配置项的结构、依赖关系和帮助信息。每个内核子系统、驱动模块都有自己的 Kconfig 文件,分散在各个目录下。
看一个实际例子——GPIO 子系统的 Kconfig 片段:
menu "GPIO Support"
config GPIOLIB
bool "GPIO Library Support"
help
This enables support for the GPIO library.
Say Y here if your board has GPIO pins.
config GPIO_SYSFS
bool "GPIO sysfs interface"
depends on GPIOLIB
help
Export GPIO control through sysfs.
Most new systems should use the character device interface instead.
config GPIO_MY_DRIVER
tristate "My Custom GPIO Driver"
depends on GPIOLIB && ARM
help
Driver for custom GPIO controller on ARM platforms.
This can be built as a module.
endmenu
这里有几个关键语法:
bool:要么编译进内核(Y),要么不编译(N)。tristate:三种状态——编译进内核(Y)、编译成模块(M)、不编译(N)。depends on:依赖关系。比如GPIO_SYSFS依赖GPIOLIB,如果没选 GPIOLIB,这个选项根本不会出现。help:帮助信息,配置时按?键能看到。
2.3.2 Makefile:控制编译行为
Makefile 文件根据 Kconfig 的配置结果,决定哪些文件被编译、怎么编译。同样以 GPIO 为例:
# drivers/gpio/Makefile
obj-$(CONFIG_GPIOLIB) += gpiolib.o
obj-$(CONFIG_GPIO_SYSFS) += gpio-sysfs.o
obj-$(CONFIG_GPIO_MY_DRIVER) += gpio-my-driver.o
# 如果是模块,加上模块信息
gpio-my-driver-objs := gpio-my-driver-core.o gpio-my-driver-regs.o
这里的 obj-$(CONFIG_XXX) 是核心语法:
- 如果
CONFIG_GPIOLIB=y,等价于obj-y += gpiolib.o,文件被编译进内核。 - 如果
CONFIG_GPIOLIB=m,等价于obj-m += gpiolib.o,文件被编译成可加载模块(.ko)。 - 如果
CONFIG_GPIOLIB未定义或为n,这一行被忽略。
你想想看,这套机制其实很巧妙。Kconfig 负责问你要不要,Makefile 负责根据你的回答去编译。两者通过 CONFIG_ 前缀的宏定义连接起来。
2.3.3 配置操作流程
实际配置内核时,你不需要手写 Kconfig 或 Makefile。内核提供了一系列配置工具:
# 最常用的菜单式配置
make menuconfig
# 基于当前配置的文本界面
make nconfig
# 使用默认配置(适合快速开始)
make defconfig
# 保存当前配置到文件
make savedefconfig
make menuconfig 是我用得最多的。界面里按 / 可以搜索配置项,按 ? 看帮助,按 空格 切换 Y/M/N。配置完成后,配置结果保存在内核源码根目录的 .config 文件中。
make defconfig 生成默认配置,然后在此基础上 make menuconfig 微调。别从零开始配,那太累了。我刚开始做嵌入式时,试图手配一个最小内核,结果漏了根文件系统驱动,内核启动到一半就 panic 了。
2.4 本章知识结构图
下面这张图把源码获取、git 管理、配置系统三者的关系串起来了:
2.5 小结
这一章我们干了三件事:
- 从 kernel.org 拿到了干净的内核源码。
- 用 git 管理源码,创建了自己的开发分支,学会了打补丁。
- 理解了 Kconfig 和 Makefile 是怎么配合工作的。