第2章 内核编译环境搭建:交叉编译工具链配置、Buildroot与Yocto选择、内核Kconfig与Makefile基础
做Rockchip平台的内核开发,第一步就是搭环境。这事听起来简单,但我在项目里见过太多人在这上面栽跟头——工具链版本不对、编译选项配错、Kconfig依赖搞混,一折腾就是半天。今天咱们就把这块彻底捋清楚。
2.1 交叉编译工具链配置
交叉编译,说白了就是在你的x86电脑上编译出能在ARM芯片上跑的程序。Rockchip平台用的是ARM64架构,所以我们需要一套aarch64的交叉工具链。
2.1.1 工具链的选择
我个人习惯用Linaro提供的预编译工具链,稳定且社区支持好。Rockchip官方SDK里也默认推荐这套。
| 工具链来源 | 适用场景 | 我的建议 |
|---|---|---|
| Linaro GCC | 通用内核编译、驱动开发 | 首选,兼容性最好 |
| ARM官方GNU工具链 | 裸机或RTOS开发 | 内核开发不推荐 |
| Buildroot自编译 | 定制化根文件系统 | 适合深度定制场景 |
| Yocto SDK | 企业级项目 | 学习曲线陡,但功能强大 |
2.1.2 环境变量配置
下载解压后,关键一步是配环境变量。我习惯把工具链路径加到 ~/.bashrc 里:
export CROSS_COMPILE=aarch64-linux-gnu-
export ARCH=arm64
export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin
这里有个坑——CROSS_COMPILE 变量末尾的短横线不能丢。少了它,Makefile就找不到对应的gcc、ld等工具。我刚开始做RK3399时就被这个坑过,编译报错"找不到编译器",查了半天才发现是少了个短横线。
2.1.3 验证工具链
配好之后,跑一下验证:
aarch64-linux-gnu-gcc --version
aarch64-linux-gnu-gcc -v 2>&1 | grep Target
看到输出里有 aarch64-linux-gnu 字样,说明工具链就绪了。
2.2 Buildroot与Yocto的选择
做嵌入式Linux,根文件系统怎么搞?Buildroot和Yocto是两大主流方案。很多初学者纠结选哪个,我直接说结论:看项目复杂度。
2.2.1 核心差异对比
| 维度 | Buildroot | Yocto |
|---|---|---|
| 构建速度 | 快(分钟级) | 慢(小时级) |
| 学习曲线 | 平缓 | 陡峭 |
| 包管理 | 简单,menuconfig配置 | 复杂,BitBake + recipes |
| 定制灵活性 | 中等 | 极高 |
| 企业级支持 | 社区为主 | 商业支持完善 |
| Rockchip适配 | 官方SDK默认用Buildroot | 需要自己写BSP层 |
2.2.2 我的选择建议
- 个人学习、原型验证、小批量产品 → 选Buildroot。Rockchip官方SDK就是基于Buildroot的,开箱即用。
- 企业级产品、需要定制化发行版、多平台维护 → 选Yocto。虽然重,但后期维护成本低。
- 只想编译内核,不关心根文件系统 → 两个都不用,直接用SDK里的脚本。
我的实战经验:做RK3568的工业平板项目时,客户要求定制OTA升级和包管理,Buildroot搞不定,最后切到了Yocto。迁移过程花了2周,但后续的版本管理确实省心。如果你只是做内核调优,Buildroot完全够用。
2.2.3 Buildroot快速上手
Rockchip SDK里已经集成了Buildroot配置。进入SDK目录,直接:
cd buildroot
make rockchip_rk3588_defconfig
make
第一次编译会下载所有依赖包,耗时取决于网络。我建议用国内镜像源,在 dl/ 目录下配个代理,不然等得心焦。
2.3 内核Kconfig与Makefile基础
这部分是内核配置的核心。你想想看,Linux内核有上万行代码,怎么控制哪些功能编译进去?靠的就是Kconfig和Makefile这套机制。
2.3.1 Kconfig语法速览
Kconfig定义了内核功能的开关。每个驱动目录下都有一个 Kconfig 文件,结构类似这样:
config ROCKCHIP_I2S
tristate "Rockchip I2S controller driver"
depends on ARCH_ROCKCHIP
select SND_SOC_GENERIC_DMAENGINE
help
Say Y here to enable Rockchip I2S controller driver.
This driver supports I2S interface for audio playback and capture.
关键字段解释:
tristate:三态选择——Y(编译进内核)、M(编译为模块)、N(不编译)depends on:依赖关系,不满足条件则选项不可见select:反向依赖,选中此项时自动选中其他选项help:帮助信息,写清楚驱动用途
depends on DRM,导致编译出来的模块加载时报符号缺失。记住:depends on 是编译时的硬约束,不能省。
2.3.2 Makefile的编译逻辑
Kconfig定义完开关,Makefile负责执行编译。对应上面的I2S驱动,Makefile里这样写:
obj-$(CONFIG_ROCKCHIP_I2S) += rockchip_i2s.o
当 CONFIG_ROCKCHIP_I2S 为y时,等价于 obj-y += rockchip_i2s.o,文件被编译进内核。为m时,编译成模块 rockchip_i2s.ko。
多文件驱动怎么办?比如一个驱动由 core.c 和 dma.c 组成:
rockchip_i2s-objs := core.o dma.o
obj-$(CONFIG_ROCKCHIP_I2S) += rockchip_i2s.o
2.3.3 内核配置实战
进入内核源码目录,执行:
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
这会打开一个图形化配置界面。我习惯按以下顺序操作:
- 先加载默认配置:
make rockchip_linux_defconfig - 再用
menuconfig微调,按/键搜索功能 - 保存为
.config,备份一份到arch/arm64/configs/下
make savedefconfig 可以生成精简版的配置文件,只保留非默认值的选项。提交到Git时用这个,代码review的人会感谢你。
2.4 本章知识体系总览
下面这张图把本章的核心逻辑串起来了,你可以对照着梳理自己的环境搭建流程:
2.5 常见问题与避坑
最后,我把这些年遇到的高频问题列出来,你碰到了可以直接对照排查:
| 问题现象 | 根因 | 解决方案 |
|---|---|---|
编译报错 aarch64-linux-gnu-gcc: not found |
环境变量未生效或路径错误 | 检查 ~/.bashrc 中的PATH,执行 source ~/.bashrc |
| menuconfig中找不到Rockchip相关选项 | ARCH未设置为arm64 | 确认 export ARCH=arm64 已执行 |
编译内核时报 undefined reference |
Kconfig依赖关系缺失 | 检查 depends on 和 select 是否完整 |
| Buildroot下载包极慢 | 未配置国内镜像源 | 修改 dl/ 目录下的下载链接为国内镜像 |
| Yocto第一次构建耗时超过8小时 | 未使用共享状态缓存 | 配置 SSTATE_DIR 指向共享缓存目录 |
我的忠告:环境搭建这件事,别想着一步到位。先跑通一个最小系统,再逐步加功能。我见过太多人一上来就想配个完美的内核,结果卡在环境上两周,项目进度全耽误了。先让内核跑起来,再谈优化。