4. Linux 内核源码结构:内核配置与构建体系

在进行 ARM 平台内核移植时,深入理解 Linux 内核源码的组织结构、配置系统与构建机制是必备技能。本章将系统性地剖析内核源码目录树、Kconfig/Makefile 体系以及内核配置系统的工作流程,为后续的设备树配置与内核裁剪打下坚实基础。

4.1 内核源码目录树分析

Linux 内核源码采用模块化、层次化的目录结构,顶层目录按功能子系统划分。下表列出了 ARM 平台移植中最为关键的目录及其作用:

目录名 功能描述 移植关注度
arch/ 体系结构相关代码,包含 arm/、arm64/ 子目录 极高
drivers/ 设备驱动框架与具体驱动实现 高
include/ 内核头文件,含 dt-bindings/ 设备树绑定 高
kernel/ 核心调度、进程管理、中断等基础框架 中
mm/ 内存管理子系统 中
Documentation/ 内核文档,含设备树绑定说明 参考
scripts/ 编译脚本、设备树编译工具 (dtc) 工具依赖
实战提示:ARM 平台移植时,arch/arm/mach-xxx/ 和 arch/arm/boot/dts/ 是修改最频繁的目录。前者存放板级初始化代码,后者存放设备树源文件。

下图展示了内核源码顶层目录之间的依赖关系与数据流:

Linux 内核源码顶层目录关系图 Linux 内核源码顶层目录关系与数据流 arch/ (体系结构) drivers/ (驱动) kernel/ (核心) mm/ (内存管理) include/ (头文件) scripts/ (工具脚本) 说明:arch/ 是移植入口,通过 Kconfig 选择驱动与核心模块,最终由 scripts/ 完成编译与设备树生成

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 时,编译为可加载模块。

关键机制:Kconfig 与 Makefile 通过 .config 文件中的 CONFIG_* 变量建立联系。修改 Kconfig 后必须运行 make menuconfig 重新生成 .config,Makefile 才能识别新的配置。

下图展示了 Kconfig 与 Makefile 的协作流程:

Kconfig 与 Makefile 协作流程图 Kconfig 与 Makefile 协作流程 Kconfig 文件 make menuconfig .config 文件 Makefile 读取 编译输出 (.o/.ko) 虚线表示 .config 被 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 平台生成并定制内核配置:

  1. 加载默认配置:make ARCH=arm vexpress_defconfig
  2. 进入菜单配置:make ARCH=arm menuconfig
  3. 裁剪驱动:进入 Device Drivers → GPIO Support,取消不需要的 GPIO 控制器
  4. 保存配置:退出时选择 Save,覆盖 .config
  5. 生成精简配置: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 等工具进行内核裁剪