2. Linux 内核源码结构:获取方式、顶层目录与构建体系

理解 Linux 内核源码的组织方式是进行内核配置与嵌入式系统构建的第一步。本章将系统介绍内核源码的获取途径、顶层目录的功能划分,以及支撑整个内核配置与编译的 Makefile 与 Kconfig 体系。

2.1 内核源码获取方式

获取 Linux 内核源码主要有两种官方途径:通过 kernel.org 下载稳定发布包,或通过 Git 仓库 克隆完整的开发历史。两种方式各有适用场景。

获取方式 命令 / 示例 适用场景 特点
kernel.org 压缩包
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.tar.xz
tar -xf linux-6.6.tar.xz
嵌入式产品发布、固定版本构建 体积小、版本固定、无需网络
Git 克隆主线仓库
git clone \
  https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
内核开发、跟踪最新补丁 完整历史、可切换分支、占用空间大
Git 克隆稳定仓库
git clone \
  https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
长期维护(LTS)项目 包含稳定分支与补丁集
实践建议: 对于嵌入式 Linux 产品开发,推荐从 kernel.org 下载 LTS 版本的 tar.xz 包,解压后纳入版本管理。这样可保证构建环境可复现,且避免克隆整个 Git 历史(通常超过 3GB)。

2.2 顶层目录结构

Linux 内核源码的顶层目录结构清晰反映了其模块化设计思想。每个顶层目录对应一个核心子系统或构建基础设施。以下是最关键的目录及其功能说明。

Linux 内核顶层目录结构图 Linux 内核顶层目录结构 arch/ 体系结构相关代码 drivers/ 设备驱动 fs/ 文件系统 include/ 内核头文件 kernel/ 核心调度/进程管理 mm/ 内存管理 net/ 网络协议栈 ipc/ 进程间通信 security/ 安全模块 crypto/ 加密 API block/ 块设备层 lib/ 内核库函数 scripts/ tools/ 构建脚本与工具 Documentation/ 内核文档 samples/ usr/ 示例代码与 initramfs 说明: 每个顶层目录下都包含一个 Kconfig 文件(定义配置选项)和一个 Makefile(定义编译规则)。 嵌入式开发者最常修改的目录是 arch/arm 或 arch/arm64(板级支持)以及 drivers/(外设驱动)。

2.3 关键目录详解

2.3.1 arch/ — 体系结构相关代码

该目录按 CPU 架构划分子目录,如 arch/arm/、arch/arm64/、arch/x86/、arch/riscv/。每个子目录下包含:

  • boot/:引导代码(如压缩后的内核入口)
  • kernel/:架构特定的核心代码(如中断处理、信号)
  • mm/:架构特定的内存管理(如页表操作)
  • mach-xxx/:特定 SoC 的板级支持代码(旧式 ARM)
  • dts/:设备树源文件(Device Tree Source)

2.3.2 drivers/ — 设备驱动

这是内核中最大的目录,按设备类型划分子目录:

  • drivers/gpio/、drivers/i2c/、drivers/spi/ — 总线协议驱动
  • drivers/net/、drivers/mmc/、drivers/usb/ — 外设接口驱动
  • drivers/clk/、drivers/pinctrl/ — 时钟与引脚控制
  • drivers/input/、drivers/media/ — 输入与多媒体设备

2.3.3 fs/ — 文件系统

包含所有内核支持的文件系统实现:

  • fs/ext4/、fs/btrfs/、fs/xfs/ — 本地磁盘文件系统
  • fs/squashfs/、fs/jffs2/、fs/ubifs/ — 嵌入式只读与闪存文件系统
  • fs/proc/、fs/sysfs/、fs/debugfs/ — 虚拟文件系统
  • fs/nfs/、fs/cifs/ — 网络文件系统

2.3.4 include/ — 内核头文件

头文件分为两类:

  • include/linux/ — 内核内部使用的通用头文件(如 include/linux/gpio.h)
  • include/uapi/ — 用户空间 API 头文件(如 include/uapi/linux/ioctl.h)
  • include/asm-generic/ — 体系结构无关的汇编头文件模板

2.4 Makefile 与 Kconfig 体系

Linux 内核的配置与编译系统由 Kconfig(配置语言)和 Makefile(编译规则)两大组件构成。它们共同实现了从配置选项到最终内核镜像的完整构建流程。

Kconfig / Makefile 构建流程 Kconfig + Makefile 构建流程 Kconfig 文件 定义配置选项与依赖 配置工具 make menuconfig / defconfig .config 最终配置结果 Makefile obj-y / obj-m 条件编译 编译过程 make / make modules vmlinux / zImage 内核镜像与模块 读取配置 核心机制: Kconfig 定义“有什么选项”,Makefile 定义“怎么编译”。.config 中的 CONFIG_XXX=y/m/n 控制 Makefile 中的 obj-$(CONFIG_XXX) 展开。 例如:CONFIG_GPIO_SYSFS=y → drivers/gpio/Makefile 中的 obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o 被编译。

2.4.1 Kconfig 语法示例

每个子目录下的 Kconfig 文件定义了该目录的配置选项。以下是一个典型的 GPIO 控制器驱动配置:

# drivers/gpio/Kconfig 片段
config GPIO_PL061
    tristate "ARM PrimeCell PL061 GPIO support"
    depends on ARM_AMBA
    help
      Say yes here to support the ARM PrimeCell PL061 GPIO device.
      This driver can also be built as a module.

关键语法元素:

  • tristate:三态选项(y=编译进内核,m=编译为模块,n=不编译)
  • bool:布尔选项(只能 y 或 n)
  • depends on:依赖关系,只有前置条件满足时该选项才可见
  • select:反向选择,选中当前选项时自动选中另一个选项
  • help:帮助文本,在 menuconfig 界面中显示

2.4.2 Makefile 条件编译规则

与 Kconfig 对应的 Makefile 使用 obj-$(CONFIG_XXX) 模式实现条件编译:

# drivers/gpio/Makefile 片段
# 基础对象
obj-y                          += gpiolib.o
obj-$(CONFIG_GPIOLIB)          += gpiolib-devres.o

# 条件编译:根据 CONFIG 决定是否编译
obj-$(CONFIG_GPIO_PL061)       += gpio-pl061.o
obj-$(CONFIG_GPIO_SYSFS)       += gpiolib-sysfs.o
obj-$(CONFIG_GPIO_CDEV)        += gpiolib-cdev.o

# 如果 CONFIG_GPIO_PL061=y,则 gpio-pl061.o 被编译进内核
# 如果 CONFIG_GPIO_PL061=m,则 gpio-pl061.o 被编译为独立模块
# 如果 CONFIG_GPIO_PL061=n,则 gpio-pl061.o 不被编译
嵌入式开发要点: 在移植内核到新板卡时,开发者通常需要:
  1. 在 arch/arm/mach-xxx/ 或设备树中添加板级描述
  2. 在 drivers/ 下添加或修改外设驱动
  3. 在对应目录的 Kconfig 中添加新配置选项
  4. 在对应目录的 Makefile 中添加 obj-$(CONFIG_XXX) 编译规则
  5. 通过 make menuconfig 或 make defconfig 生成 .config

2.5 配置生成与编译命令速查

命令 功能 输出文件
make menuconfig 基于 ncurses 的交互式配置界面 .config
make defconfig 使用架构默认配置生成 .config .config
make ARCH=arm defconfig 指定 ARM 架构的默认配置 .config
make savedefconfig 将当前 .config 精简为最小 defconfig defconfig
make olddefconfig 基于现有 .config 更新,新选项使用默认值 .config
make -j$(nproc) 编译内核与模块 vmlinux, zImage, *.ko
make modules_install 安装内核模块到 /lib/modules/ 模块文件
常见陷阱: 在嵌入式开发中,make defconfig 生成的配置通常过于庞大(包含大量不需要的驱动)。建议基于目标硬件从零开始裁剪,或使用 vendor 提供的 defconfig 文件(如 arch/arm/configs/imx_v7_defconfig)作为起点。

2.6 本章小结

  • 内核源码可通过 kernel.org 下载稳定包或 Git 克隆 获取,嵌入式项目推荐使用 LTS 版本的 tar.xz 包。
  • 顶层目录中,arch/、drivers/、fs/、include/、kernel/ 是嵌入式开发最常打交道的目录。
  • Kconfig 定义配置选项的层次结构与依赖关系,Makefile 根据 .config 中的 CONFIG_XXX 值决定编译哪些源文件。
  • 掌握 obj-$(CONFIG_XXX) 条件编译模式是理解内核构建体系的关键。