4. Linux 内核源码结构:内核配置与构建体系
在进行 ARM 平台内核移植时,深入理解 Linux 内核源码的组织结构、配置系统与构建机制是必备技能。本章将系统性地剖析内核源码目录树、Kconfig/Makefile 体系以及内核配置系统的工作流程,为后续的设备树配置与内核裁剪打下坚实基础。
4.1 内核源码目录树分析
Linux 内核源码采用模块化、层次化的目录结构,顶层目录按功能子系统划分。下表列出了 ARM 平台移植中最为关键的目录及其作用:
| 目录名 | 功能描述 | 移植关注度 |
|---|---|---|
arch/ |
体系结构相关代码,包含 arm/、arm64/ 子目录 |
极高 |
drivers/ |
设备驱动框架与具体驱动实现 | 高 |
include/ |
内核头文件,含 dt-bindings/ 设备树绑定 |
高 |
kernel/ |
核心调度、进程管理、中断等基础框架 | 中 |
mm/ |
内存管理子系统 | 中 |
Documentation/ |
内核文档,含设备树绑定说明 | 参考 |
scripts/ |
编译脚本、设备树编译工具 (dtc) |
工具依赖 |
arch/arm/mach-xxx/ 和 arch/arm/boot/dts/ 是修改最频繁的目录。前者存放板级初始化代码,后者存放设备树源文件。
下图展示了内核源码顶层目录之间的依赖关系与数据流:
4.2 Kconfig 与 Makefile 机制
内核的配置与编译系统由 Kconfig 和 Makefile 两大核心文件驱动。Kconfig 定义配置选项的菜单结构,Makefile 根据配置结果决定哪些文件参与编译。
4.2.1 Kconfig 语法与结构
Kconfig 文件采用树形菜单结构,每个配置选项由关键字引导。以下是一个典型的 ARM 平台驱动 Kconfig 条目:
config GPIO_PL061
bool "PrimeCell PL061 GPIO support"
depends on ARM_AMBA
default y if ARCH_VEXPRESS
help
Say yes here to support the PrimeCell PL061 GPIO device.
This driver can also be built as a module.
Kconfig 常用关键字及其含义:
| 关键字 | 作用 | 示例 |
|---|---|---|
config |
定义一个配置选项 | config ARCH_VEXPRESS |
bool/tristate |
选项类型(布尔/三态) | tristate "PL061 driver" |
depends on |
依赖关系 | depends on ARM |
select |
反向选择(强制依赖) | select GPIOLIB |
default |
默认值 | default y |
help |
帮助文本 | help\n This driver... |
4.2.2 Makefile 条件编译
Makefile 通过读取 .config 文件中的变量,决定目标文件的编译方式:
# drivers/gpio/Makefile 示例
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
当 CONFIG_GPIO_PL061=y 时,gpio-pl061.o 被编译并链接进内核;当 =m 时,编译为可加载模块。
.config 文件中的 CONFIG_* 变量建立联系。修改 Kconfig 后必须运行 make menuconfig 重新生成 .config,Makefile 才能识别新的配置。
下图展示了 Kconfig 与 Makefile 的协作流程:
4.3 内核配置系统
内核配置系统提供多种前端界面,满足不同场景需求。下表对比了常用配置工具:
| 命令 | 界面类型 | 适用场景 | 依赖 |
|---|---|---|---|
make menuconfig |
文本菜单 (ncurses) | 开发板本地配置 | libncurses-dev |
make xconfig |
图形界面 (Qt) | 桌面环境配置 | qt5-dev |
make defconfig |
默认配置 | 快速生成基础配置 | 无 |
make savedefconfig |
精简配置 | 生成最小化 .config | 无 |
4.3.1 配置依赖与冲突处理
Kconfig 通过 depends on 和 select 管理依赖关系。当出现依赖不满足时,配置系统会自动灰化或隐藏相关选项。以下是一个典型的依赖链:
config ARCH_VEXPRESS
bool "ARM Ltd. Versatile Express"
select ARM_AMBA
select ARM_TIMER_SP804
select GPIO_PL061 if GPIOLIB
config GPIO_PL061
tristate "PrimeCell PL061 GPIO"
depends on ARM_AMBA
select GPIOLIB
A select B 且 B select A 会导致配置死锁。内核配置系统会检测此类错误并报错,但排查起来较为耗时。
4.3.2 配置实战:为 ARM 平台生成最小配置
以下步骤演示如何为 ARM Versatile Express 平台生成并定制内核配置:
- 加载默认配置:
make ARCH=arm vexpress_defconfig - 进入菜单配置:
make ARCH=arm menuconfig - 裁剪驱动:进入
Device Drivers → GPIO Support,取消不需要的 GPIO 控制器 - 保存配置:退出时选择
Save,覆盖.config - 生成精简配置:
make ARCH=arm savedefconfig,得到defconfig文件
配置完成后,.config 文件中的典型条目如下:
CONFIG_ARM=y
CONFIG_ARCH_VEXPRESS=y
CONFIG_ARM_AMBA=y
CONFIG_GPIO_PL061=y
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
# CONFIG_GPIO_DWAPB is not set
4.4 本章小结
本章深入剖析了 Linux 内核源码的目录结构、Kconfig/Makefile 机制以及配置系统。掌握这些知识后,你应能:
- 快速定位 ARM 平台移植相关的源码目录
- 理解 Kconfig 依赖关系并正确配置驱动选项
- 使用 Makefile 条件编译机制控制代码生成
- 熟练运用
menuconfig等工具进行内核裁剪