内核源码获取与配置:从kernel.org到你的开发板

做嵌入式Linux开发,第一步就是拿到内核源码。这事儿听起来简单,但里面坑不少。我见过不少新手直接从网盘下载一个“万能内核包”,结果编译出来板子死活起不来——说白了,版本不对,配置也不对。

这一章,我们就从最正统的源头开始:kernel.org。我会带你走一遍获取源码、理解目录结构、搞懂Kconfig/Makefile这套配置系统,最后亲手用make menuconfig做一次图形化配置。

从kernel.org获取Linux内核源码

官方下载地址就一个:https://www.kernel.org。进去之后你会看到几个版本分类:

版本类型 说明 适用场景
Mainline 主线最新版,Linus Torvalds直接维护 尝鲜、新硬件支持、学习
Stable 主线基础上修bug的稳定版 产品开发首选
Longterm 长期支持版,维护周期数年 嵌入式产品、工业设备
Next 开发中的代码,可能不稳定 内核开发者、测试

我个人习惯用Longterm版本做嵌入式项目。比如现在常用的5.10.y或6.1.y,社区支持好,驱动也全。你想想看,产品一卖就是三五年,选个长期支持版省心得多。

下载命令很简单:

# 以6.1.80为例
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.80.tar.xz

# 解压
tar -xf linux-6.1.80.tar.xz
cd linux-6.1.80/
我的习惯:下载后先校验sha256sum。曾经有一次下载包损坏,编译到一半报错,排查了半天才发现是源码问题。现在每次下载完我都跑一遍 sha256sum --check,几秒钟的事,能省几小时。

内核源码目录结构解析

解压完你会看到几十个目录。第一次接触的人可能会懵——这么多文件夹,从哪看起?

别急,核心目录其实就这几个:

目录 作用 我重点关注什么
arch/ 体系结构相关代码 arch/arm/、arch/arm64/、arch/x86/
drivers/ 设备驱动,占源码一半以上 drivers/net/、drivers/i2c/、drivers/spi/
fs/ 文件系统实现 fs/ext4/、fs/proc/、fs/sysfs/
include/ 内核头文件 include/linux/、include/uapi/
kernel/ 核心调度、进程管理 调试时经常看kernel/panic.c
mm/ 内存管理 调内存泄漏时必看
net/ 网络协议栈 net/ipv4/、net/wireless/
scripts/ 编译、配置辅助脚本 scripts/kconfig/ 配置系统核心

嗯,这里要注意:arch/下面每个CPU架构都有自己的一套启动代码、内存布局、中断处理。你做嵌入式,ARM或RISC-V的话,大部分时间都在arch/arm/或arch/arm64/里折腾。

我举个例子。有一次调试一个ARM板子的启动卡死问题,最后定位到是arch/arm/mach-xxx/下面的板级初始化代码里,GPIO复用配置错了。这种问题,不懂目录结构根本无从下手。

配置系统(Kconfig/Makefile)原理

内核的配置系统,说白了就是一套“选择题生成器”。Kconfig定义题目,Makefile根据答案决定编译什么。

Kconfig:定义“有什么选项”

每个目录下都有一个Kconfig文件。比如drivers/i2c/Kconfig里会写:

config I2C_CHARDEV
    tristate "I2C device interface"
    help
      Say Y here to enable I2C character device interface.
      这个选项允许用户空间通过/dev/i2c-N访问I2C设备。

这里tristate表示三种状态:Y(编译进内核)、M(编译成模块)、N(不编译)。

Kconfig还支持depends on(依赖)、select(自动选中)、default(默认值)等关键字。我在项目中遇到过最坑的情况是:选了一个驱动,它自动select了另一个驱动,结果那个驱动依赖的硬件不存在,编译出来内核直接panic。

避坑指南:我曾经在配置I2C子系统时,随手选了“I2C SMBus support”,结果它自动依赖了ACPI。我的ARM板子根本没有ACPI,编译报错查了半天。所以看到select关键字,一定要追查它选了什么东西。

Makefile:决定“怎么编译”

Kconfig定义完选项,Makefile根据配置结果决定编译行为:

# drivers/i2c/Makefile
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o

如果CONFIG_I2C_CHARDEV=y,就编译i2c-dev.o并链接进内核;如果是m,就编译成独立的.ko模块;如果是n,就跳过。

这个机制非常优雅。你想想看,几千个驱动,每个都按这个规则来,配置系统自动管理依赖和编译顺序。

make menuconfig 图形化配置实战

理论说完了,上手实操。配置内核最常用的命令就是make menuconfig。

准备工作

先确保安装了ncurses库:

sudo apt-get install libncurses-dev

然后进入内核源码目录,执行:

make menuconfig

你会看到一个蓝底白字的图形界面。操作很简单:

  • 方向键:上下移动
  • Enter:进入子菜单
  • Y:选中(编译进内核)
  • M:选中为模块
  • N:取消选中
  • ?:查看帮助
  • /:搜索选项

实战:配置一个最小化ARM内核

假设我们要为ARM Cortex-A7的板子配置内核:

  1. 选择架构:进入General setup → Cross-compiler tool prefix,填arm-linux-gnueabihf-
  2. 选择CPU类型:System Type → 选择你的SoC厂商(比如ARM Ltd. → ARMv7 based platforms)
  3. 使能必要的驱动:Device Drivers → 勾选I2C、SPI、GPIO、MMC/SD等
  4. 文件系统:File systems → 勾选ext4、proc、sysfs
  5. 网络:Networking support → 勾选TCP/IP、Ethernet

配置完成后,按Tab键选择Save,默认保存为.config文件。

核心知识点:.config文件就是内核配置的“答案本”。每一行都是一个CONFIG_XXX=y/m/n。你可以直接编辑这个文件,但更推荐用menuconfig,因为它会自动处理依赖关系。

配置系统核心流程

下面这张图展示了从Kconfig到最终编译的完整链路:

内核配置系统工作流程 内核配置系统工作流程 Kconfig 文件 make menuconfig .config 文件 Makefile 文件 make 编译 vmlinux / zImage .ko 模块 关键说明: 1. Kconfig 定义选项的“菜单结构”和依赖关系 2. menuconfig 读取 Kconfig,生成用户界面,输出 .config 3. Makefile 读取 .config 中的 CONFIG_* 变量,决定编译哪些文件

常用配置技巧

  • 搜索功能:按/键输入关键字,比如搜I2C,会列出所有相关选项及其路径。我在调试一个触摸屏驱动时,就是靠搜索找到CONFIG_TOUCHSCREEN_GT9XX的。
  • 快速加载默认配置:make defconfig生成架构默认配置;make tinyconfig生成最小配置。
  • 保存配置片段:make savedefconfig会把当前配置精简成最小化版本,方便版本管理。
我的工作流:先 make defconfig 生成基础配置,再用 make menuconfig 微调。最后 make savedefconfig 把精简配置提交到Git仓库。这样同事拉下来后,make defconfig 再 make 就能复现我的环境。

小结

这一章我们走通了内核源码的获取、目录结构、配置系统原理和实战操作。核心就三件事:从kernel.org拿源码、看懂Kconfig/Makefile的配合、用menuconfig生成.config。