3. Linux 内核编译:从源码到镜像的完整旅程
说实话,内核编译这件事,很多初学者一听就觉得头大。我当年第一次接触时也差不多——对着满屏的配置选项发懵,编译一次等半小时,最后还起不来。但你别怕,这东西说白了就是一套流程,走通了就顺了。
这一章,我带你把整个流程捋一遍:源码从哪来、怎么配、怎么编、最后生成什么。每一步我都会告诉你实际项目中容易踩的坑。
3.1 内核源码获取
RK3568 的内核源码,官方推荐从 Rockchip 的 GitHub 仓库拉取。我个人习惯用 git clone,因为后续切分支、打补丁都方便。
核心仓库地址:
https://github.com/rockchip-linux/kernel.git
建议拉取 rk356x 或 linux-5.10.y 分支。
具体操作:
- 克隆仓库:
git clone https://github.com/rockchip-linux/kernel.git -b rk356x - 进入目录:
cd kernel - 查看分支:
git branch -a,确认当前在 rk356x 上
我的经验:别用 master 分支。Rockchip 的 master 经常是旧版,rk356x 才是针对性的。我之前有一次图省事拉了 master,结果编译出来的内核在板子上死活起不来,查了两天才发现是 DTS 不匹配。
3.2 内核配置
源码到手后,下一步就是配置。配置决定了你的内核支持哪些功能、驱动、文件系统。说白了,就是告诉编译器:「我要这些东西,不要那些东西」。
RK3568 官方提供了一套默认配置,存放在 arch/arm64/configs/ 下。我常用的命令是:
make ARCH=arm64 rockchip_linux_defconfig
这条命令会生成一个 .config 文件,里面是几千个配置选项。嗯,你没看错,几千个。但别慌,大部分默认值已经对了。
3.2.1 常用配置命令
| 命令 | 作用 | 适用场景 |
|---|---|---|
make menuconfig |
基于 ncurses 的图形化菜单 | 日常修改,最常用 |
make defconfig |
使用架构默认配置 | 快速生成基础配置 |
make savedefconfig |
将当前配置精简保存 | 生成最小化 defconfig |
make oldconfig |
基于旧配置更新新选项 | 内核版本升级时使用 |
注意:如果你在 menuconfig 里改了配置,记得保存退出。我曾经有一次改完直接关终端,结果白改了一小时。
3.2.2 配置要点
对于 RK3568 驱动开发,你至少需要关注以下几类配置:
- 设备树(Device Tree):
CONFIG_ARCH_ROCKCHIP=y,这是基础 - GPIO 驱动:
CONFIG_GPIO_ROCKCHIP=y - I2C/SPI 总线:根据你的外设选择
- Pinctrl:
CONFIG_PINCTRL_ROCKCHIP=y - 时钟框架:
CONFIG_COMMON_CLK_ROCKCHIP=y
你想想看,如果这些基础配置没开,你后面写的驱动根本编译不进去。我在项目里见过有人折腾了一周,最后发现是 CONFIG_I2C_ROCKCHIP 没开——这种低级错误,犯一次就够了。
3.3 编译流程
配置搞定后,就是编译。RK3568 是 64 位 ARM 架构,所以需要指定交叉编译工具链。我一般这样写:
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make -j$(nproc) Image dtbs modules
解释一下:
ARCH=arm64:指定架构CROSS_COMPILE:交叉编译工具链前缀-j$(nproc):用所有 CPU 核心并行编译,快很多Image:生成内核镜像dtbs:编译设备树二进制文件modules:编译内核模块
完整编译脚本示例:
#!/bin/bash
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin
make rockchip_linux_defconfig
make -j$(nproc) Image dtbs modules 2>&1 | tee build.log
第一次编译大概需要 10-20 分钟,取决于你的机器性能。我建议你泡杯咖啡,或者看看文档,别干等。
3.3.1 编译产物
编译完成后,你会得到以下关键文件:
| 文件 | 路径 | 说明 |
|---|---|---|
Image |
arch/arm64/boot/Image |
内核镜像,未压缩 |
Image.gz |
arch/arm64/boot/Image.gz |
压缩后的内核镜像 |
*.dtb |
arch/arm64/boot/dts/rockchip/ |
设备树二进制文件 |
*.ko |
各驱动目录下 | 内核模块文件 |
避坑指南:我曾经有一次编译完只拷贝了 Image,忘了拷贝 .dtb 文件,结果板子启动时内核 panic,提示找不到根文件系统。后来才意识到,设备树里定义了内存布局和串口地址,没有它内核连控制台都打不开。
3.4 生成镜像文件
编译出来的 Image 和 .dtb 还不能直接烧录到板子上。RK3568 的启动流程需要特定的镜像格式。通常我们需要打包成 boot.img 或 recovery.img。
Rockchip 官方提供了打包工具 mkbootimg,用法如下:
mkbootimg --kernel arch/arm64/boot/Image \
--ramdisk ramdisk.img \
--dtb arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtb \
--pagesize 2048 \
--base 0x00200000 \
-o boot.img
参数说明:
--kernel:内核镜像路径--ramdisk:根文件系统镜像(可选)--dtb:设备树文件--pagesize:页大小,RK3568 通常为 2048--base:内存基地址,RK3568 为 0x00200000-o:输出文件名
重要:--base 参数必须与内核配置中的 CONFIG_PAGE_OFFSET 一致,否则内核无法正确解压。我见过有人把 base 写成 0x00000000,结果内核加载后直接跑飞。
3.5 知识结构总览
下面这张图,把整个内核编译的流程和产物关系画清楚了。你可以把它当作一张「地图」,每次编译前扫一眼,心里就有数了。
3.6 常见问题与排查
编译过程中,你可能会遇到各种报错。我整理了几个高频问题:
| 问题 | 原因 | 解决方法 |
|---|---|---|
arm-linux-gnueabihf-gcc: not found |
交叉编译工具链未安装或未加入 PATH | 安装 Linaro GCC,或检查 export PATH |
Kernel panic - not syncing: VFS |
根文件系统未找到或设备树错误 | 检查 .dtb 是否匹配,ramdisk 是否正确 |
make[1]: *** No rule to make target 'Image' |
架构未指定或配置未生成 | 先执行 make rockchip_linux_defconfig |
DTC: dts->dtb on file "xxx.dts" 报错 |
设备树语法错误 | 检查 DTS 文件中的括号、分号、标签 |
我的建议:第一次编译时,把 build.log 保存下来。出错了先看最后 50 行,大部分错误信息都在那里。别从头翻到尾,那是浪费时间。
3.7 小结
这一章我们走完了内核编译的完整流程:从 git clone 拉源码,到 menuconfig 配置,再到 make 编译,最后用 mkbootimg 打包成可烧录的镜像。每一步我都给了你实际项目中的经验和坑。
你可能会觉得步骤有点多,但多做几次就熟了。内核编译这件事,说白了就是「配置-编译-打包」三个环节,每个环节都有对应的工具和产物。只要理解了它们之间的关系,后面写驱动、调试的时候,你就知道该改哪里、编哪里、烧哪里了。