2. 内核编译基础
内核编译是嵌入式开发和内核调试的起点。只有掌握了从源码获取到生成可执行镜像的完整链路,才能在后续章节中精准定位启动异常。本章聚焦于四个核心步骤:获取源码、配置内核、编译内核、编译设备树。
2.1 获取Linux内核源码
获取内核源码有三种主流方式,根据使用场景选择合适的方法:
| 方式 | 命令/示例 | 适用场景 | 特点 |
|---|---|---|---|
| 主线发布版 | wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.tar.xz |
标准开发、学习 | 稳定、经过广泛测试 |
| Git 克隆 | git clone --depth=1 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git |
跟踪最新主线、贡献补丁 | 可获取完整历史,--depth=1 减少下载量 |
| 发行版源码包 | apt-get source linux-image-$(uname -r) |
基于当前系统配置编译 | 包含发行版特定补丁和配置 |
建议: 对于本课程,推荐使用
git clone --depth=1 获取最新稳定主线,既能保证代码新鲜度,又能节省磁盘空间和下载时间。
解压或克隆完成后,进入源码根目录:
cd linux-6.6
# 或
cd linux
2.2 配置内核(make menuconfig)
内核配置决定了哪些功能、驱动和特性被编译进内核。配置系统基于 Kconfig(Kernel Configuration)语言,提供多种配置界面。
2.2.1 配置界面选择
| 命令 | 界面类型 | 依赖 | 推荐场景 |
|---|---|---|---|
make menuconfig |
文本菜单(ncurses) | libncurses-dev |
SSH 远程、无图形环境 |
make xconfig |
图形界面(Qt) | qtbase5-dev |
本地桌面环境,搜索方便 |
make nconfig |
文本菜单(ncurses 增强) | libncurses-dev |
比 menuconfig 更快的搜索 |
make defconfig |
默认配置(无交互) | 无 | 快速生成基础配置 |
2.2.2 配置操作流程
- 清理旧配置(可选):
make mrproper - 生成默认配置:
make defconfig或make ARCH=arm64 defconfig - 启动菜单配置:
make menuconfig - 保存退出:选择
Save,默认保存为.config
关键操作: 在 menuconfig 界面中,使用
/ 键可以搜索配置项名称或描述,支持模糊匹配。例如搜索 EXT4 可以快速定位文件系统相关选项。
2.2.3 配置项三态
| 符号 | 含义 | 编译结果 |
|---|---|---|
[*] 或 y |
编译进内核(built-in) | 直接链接到 vmlinux |
[M] 或 m |
编译为模块(module) | 生成 .ko 文件,动态加载 |
[ ] 或 n |
不编译 | 完全排除 |
调试提示: 在调试启动异常时,建议将关键驱动(如串口、存储控制器)设置为
[*] 编译进内核,避免因模块加载失败导致无法输出调试信息。
2.3 编译内核(make bzImage)
bzImage 是 x86 架构下压缩后的内核镜像,也是 QEMU 调试中最常用的内核格式。对于 ARM64 架构,对应的是 Image 或 Image.gz。
2.3.1 编译命令
# x86 架构
make bzImage -j$(nproc)
# ARM64 架构
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image -j$(nproc)
参数说明:
-j$(nproc):并行编译,使用所有 CPU 核心加速。CROSS_COMPILE=:交叉编译工具链前缀,仅跨平台编译时需要。ARCH=:指定目标架构,如x86_64、arm64、arm。
2.3.2 编译产物
| 文件 | 路径 | 说明 |
|---|---|---|
vmlinux |
源码根目录 | 未压缩的原始内核,包含调试符号 |
bzImage |
arch/x86/boot/bzImage |
x86 压缩内核镜像,QEMU 直接加载 |
Image |
arch/arm64/boot/Image |
ARM64 未压缩内核镜像 |
System.map |
源码根目录 | 符号地址映射表,调试辅助 |
调试技巧: 保留
vmlinux 文件,它包含完整的调试符号(DWARF 信息),GDB 调试时必须使用 vmlinux 而非 bzImage。
2.4 编译设备树(dtbs)
设备树(Device Tree)是描述硬件拓扑和资源的数据结构,在 ARM、RISC-V 等非 x86 架构中替代了传统的 ACPI 或硬编码板级文件。QEMU 模拟的 virt 平台、vexpress 平台都需要设备树来告知内核硬件布局。
2.4.1 设备树编译命令
# 编译所有设备树
make dtbs
# 编译指定设备树(以 ARM64 virt 平台为例)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs
# 编译单个设备树文件
make ARCH=arm64 qemu-virt.dtb
2.4.2 设备树文件类型
| 扩展名 | 格式 | 说明 |
|---|---|---|
.dts |
Device Tree Source | 可读的文本源文件 |
.dtsi |
Device Tree Source Include | 公共头文件,被 .dts 包含 |
.dtb |
Device Tree Blob | 编译后的二进制文件,QEMU 加载 |
.dtbo |
Device Tree Blob Overlay | 运行时覆盖片段 |
2.4.3 设备树在 QEMU 中的使用
QEMU 启动时通过 -dtb 参数指定设备树文件:
qemu-system-aarch64 \
-machine virt \
-cpu cortex-a57 \
-kernel arch/arm64/boot/Image \
-dtb arch/arm64/boot/dts/qemu/qemu-virt.dtb \
-append "console=ttyAMA0" \
-nographic
常见错误: 如果 QEMU 启动后内核无任何输出,首先检查是否提供了正确的
-dtb 文件。缺少设备树或设备树与机器类型不匹配,会导致内核无法识别串口、内存等基础硬件,从而完全静默。
2.5 内核编译与设备树关系总览
下图展示了从源码到 QEMU 启动镜像的完整编译链路:
2.6 常见编译错误与解决
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
ncurses development packages not found |
缺少 ncurses 库 | sudo apt install libncurses-dev |
No rule to make target 'debian/certs/signing_key.pem' |
模块签名证书缺失 | make modules_prepare 或关闭 CONFIG_MODULE_SIG |
arch/arm64/Makefile: No such file or directory |
ARCH 参数错误 | 检查 ARCH=arm64 拼写,确认源码支持该架构 |
Kernel: arch/x86/boot/bzImage is ready 但 QEMU 无法启动 |
设备树缺失或不匹配 | 使用 -dtb 参数指定正确的 .dtb 文件 |
2.7 本章小结
- 获取源码:推荐
git clone --depth=1获取最新主线。 - 配置内核:
make menuconfig是远程调试的首选配置方式,注意三态选择对调试的影响。 - 编译内核:
make bzImage -j$(nproc)生成压缩内核镜像,保留vmlinux用于 GDB 调试。 - 编译设备树:
make dtbs生成.dtb文件,QEMU 启动时必须通过-dtb参数加载。 - 调试准备:确保
vmlinux、bzImage、.dtb三个文件齐全且版本一致。