3. 内核源码获取与结构分析:从 kernel.org 到 Kconfig/Makefile

好,咱们正式开始动手。这一章我带你做三件事:拿到源码、看懂骨架、摸清构建规则。这三步走顺了,后面裁剪和实时化才有根基。

3.1 从 kernel.org 获取 LTS 版本源码

源码去哪下?kernel.org,没第二个选择。我个人习惯只拿 LTS(Long Term Support) 版本,原因很简单:项目周期长,LTS 有 4-6 年维护,bug 修复和安全补丁持续跟进,不会中途断档。

当前推荐 LTS 版本(2025 年视角)

  • 6.1.x — 新硬件支持好,实时补丁(PREEMPT_RT)已合入主线
  • 5.15.x — 稳定,大量工业嵌入式项目在用
  • 5.10.x — 老项目首选,资源占用低

下载方式很简单,我一般用 wget 直接拉 tarball:

# 以 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

小技巧:下载前先看 sha256sums.asc 校验文件,用 gpg --verify 验证签名。我曾经跳过这步,结果编译到一半发现源码被篡改过… 嗯,从那以后我再也不敢省了。

3.2 顶层目录结构解析

解压完,你看到一堆目录。别慌,我带你走一遍核心的。记住一句话:内核源码是按功能模块组织的,不是按文件大小。

目录 作用 我重点关注什么
arch/ 体系结构相关代码 裁剪时只保留目标 CPU 架构,其余全删
drivers/ 设备驱动,占源码 50% 以上 裁剪主战场,不用的驱动统统去掉
fs/ 文件系统实现 根据根文件系统类型保留对应 fs
kernel/ 核心调度、进程管理、信号等 实时性优化主要动这里
mm/ 内存管理 页面分配、SLAB、VMA 等
net/ 网络协议栈 不需要网络功能的嵌入式设备直接砍掉
include/ 全局头文件 API 定义、数据结构声明
init/ 内核初始化入口 main.c 是起点
scripts/ 编译、配置、分析工具脚本 Kconfig 解析器、模块工具都在这里

你想想看,一个嵌入式设备可能只需要 ARM 架构、几个驱动、一种文件系统。其他目录里的代码,说白了就是编译时的负担。裁剪的核心思路就是:只编译你需要的。

3.3 Kconfig 与 Makefile 系统初探

内核的配置和编译不是靠手写 Makefile 的。它有一套自己的规则:Kconfig 定义“有什么选项”,Makefile 定义“怎么编译”。

3.3.1 Kconfig:配置选项的说明书

每个目录下都有一个 Kconfig 文件。比如 drivers/i2c/Kconfig 里定义了 I2C 子系统的所有开关。格式长这样:

config I2C
    tristate "I2C support"
    depends on HAS_IOMEM
    help
      I2C is a low-speed bus protocol...
      
config I2C_CHARDEV
    tristate "I2C device interface"
    depends on I2C
    help
      Provides a /dev/i2c-N interface...

关键字段:

  • tristate — 三态:Y(编入内核)、M(模块)、N(不编译)
  • depends on — 依赖关系,父选项不选,子选项不可见
  • select — 反向依赖,选了 A 自动选 B

避坑:我曾经在裁剪时把 I2C 设成 N,结果 I2C_CHARDEV 自动消失。但某个传感器驱动依赖 I2C,编译直接报错。所以裁剪时一定要顺着 depends on 链条检查依赖。

3.3.2 Makefile:编译的执行者

同目录下的 Makefile 根据 Kconfig 生成的 .config 决定编译哪些文件。比如:

obj-$(CONFIG_I2C)       += i2c-core.o
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o

如果 CONFIG_I2C=y,i2c-core.o 会被编入内核;如果是 m,则编译成模块 i2c-core.ko;如果是 n,直接跳过。

这套机制的好处是:你只需要改 .config,Makefile 自动适配。不用手动改 Makefile,除非你要加新文件。

3.4 知识结构图:源码获取 → 目录解析 → 构建系统

下面这张图把本章的核心逻辑串起来了。我建议你把它打印出来贴在工位上,每次裁剪时对照着看。

内核源码获取与结构分析知识图 内核源码获取与结构分析 kernel.org 获取 LTS 源码 解压 → 顶层目录结构(arch, drivers, fs, kernel, mm...) Kconfig:定义配置选项 Makefile:执行编译规则 生成 .config → 编译出 vmlinux / modules 裁剪配置 → 实时性优化(后续章节) 核心逻辑:获取 → 理解结构 → 配置裁剪 → 编译优化

3.5 实战建议:第一次怎么上手

别急着改代码。我建议你按这个顺序走一遍:

  1. 下载并解压一个 LTS 版本(比如 6.1.x)
  2. 浏览顶层目录,用 ls -l 看看每个目录的大小
  3. 随便进一个驱动目录(比如 drivers/i2c),打开 Kconfig 和 Makefile 对照着看
  4. 运行 make menuconfig,看看图形界面里的选项怎么对应 Kconfig 里的定义

我的习惯:每次拿到新内核,我都会先 make defconfig 生成默认配置,然后 make menuconfig 手动关掉不需要的架构和驱动。这样能快速感知内核的“体重”。