做RK3588开发的人,十有八九都卡在“环境搭建”这一步上。板子还没点亮,先把大半天时间耗在装依赖、解压SDK、踩老坑上了。尤其是Ubuntu 22.04刚上手那阵子,跟SDK里默认适配的18.04/20.04环境存在一堆隐性的兼容差异,一个包版本不对,编译报错能把人整到怀疑人生。这篇东西不整虚的,直接把我在Ubuntu 22.04上撸完瑞芯微RK3588 SDK全流程的经验倒出来,包括离线包的准备思路和下载方案,照着走能省下不少冤枉时间。适合刚拿到RK3588开发板、准备搞系统移植或者做BSP裁剪的兄弟参考。
1. 搭建前的全局认知
1.1 RK3588的SDK生态到底怎么回事
瑞芯微的SDK跟很多芯片厂商的“阉割版demo”不一样,它基本是把整个BSP开源体系都打包进来了。RK3588的SDK主要分两大流派:一个是Android系统为主的全功能SDK,包含kernel、u-boot、Android框架层、以及瑞芯微自研的RGA、MPP多媒体库等;另一个是纯Linux方向的SDK,走的是Buildroot或者Debian路线,适合做边缘计算盒子、工控设备、NAS这类不用Android生态的产品。
我这次搭建以Linux SDK为主线,顺带讲Android12那条线。两条线的底层编译器、环境依赖差别不小,最典型的就是交叉编译工具链——Android用Clang/GCC 4.9那套老古董,Linux SDK用GCC 9/11交叉编译器,混着用会出各种奇葩问题。
1.2 为什么选Ubuntu 22.04
截止我写这篇经验时,瑞芯微官方文档推荐的环境还多是Ubuntu 18.04、20.04,默认GCC版本比较老。但问题是新出的开发板、新的SDK版本,很多工具脚本(比如Python3写的打包脚本)在老版本系统上反而有兼容问题。Ubuntu 22.04的GCC 11.2、Python 3.10、OpenJDK 11基础环境,对编译RK3588的现代BSP更友好,而且22.04的SSH、Samba、USB驱动等配套组件对开发板调试也更省心。
不过这里有个核心矛盾得说透:Ubuntu 22.04是“能用”,但不是“开箱即用”。SDK里的很多脚本写死了老路径、老命令,比如某个脚本调python而不是python3,某个依赖库在老源里有、在新源里改名了。这些坑后面我会逐条展开,你先有个心理预期就行。
1.3 硬件配置焦虑,什么机器能带得动
先给你一个参考标准。我这边用的是一台X86主机,AMD Ryzen 7 5800X、64GB内存、1TB NVMe SSD。RK3588的SDK全量编译(包括Android)是出了名的吃资源,最夸张的时候编译线程一开,内存直接吃到30GB以上,CPU满载半小时起步。如果只编译Linux SDK的内核和根文件系统,16GB内存加4核以上的CPU也能跑,就是慢一点。
磁盘空间一定要准备充足。我解压完Linux SDK是40GB左右,Android SDK解压后能到150GB以上,这还不算编译过程中产生的中间文件。编译完Android后,整个SDK目录膨胀到250GB属于正常操作。建议至少给SDK预留300GB空间,用单独分区挂载更稳妥。
2. Ubuntu 22.04基础环境准备
2.1 系统安装的几条硬建议
Ubuntu 22.04的安装盘制作推荐用Rufus或balenaEtcher,写盘方式选择DD模式,不要选ISO镜像模式,否则容易出现启动引导异常。分区的时候我习惯把SDK目录独立成一个分区,挂载到/home/你的用户名/sdk或者/opt/rk3588,好处是将来系统崩了要重装,SDK数据不受影响,直接重新挂载就能继续用。
系统装完后,第一个动作是换国内软件源。我用的是清华源,顺手更新一下系统:
sudo sed -i 's@//.*archive.ubuntu.com@//mirrors.tuna.tsinghua.edu.cn@g;s@//security.ubuntu.com@//mirrors.tuna.tsinghua.edu.cn@g' /etc/apt/sources.list sudo apt update && sudo apt upgrade -y有个反直觉的点:官方源的某些老版本依赖包,在22.04源里可能已经被替换了。这时候你反而需要保留部分默认源配置,比如focal-updates、focal-security这类兼容源。我遇到过SDK依赖的libncurses5只在老版本源里有,新源只有libncurses6,导致menuconfig无法打开。这种情况后面排查章节细说。
2.2 必装工具链清单
RK3588 SDK编译需要的基础工具我整理了一份清单,直接在终端分批安装即可:
# 基础编译工具 sudo apt install -y git ssh make gcc libssl-dev libncurses5-dev \ libncursesw5-dev g++ lzop u-boot-tools flex bison \ libgcc1 gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu \ bc cpio zip unzip rsync file wget # 后续经常用到的辅助工具 sudo apt install -y python3 python3-pip python3-distutils \ device-tree-compiler libudev-dev libusb-1.0-0 \ libgles2-mesa-dev libgl1-mesa-dev libx11-dev \ libjson-c-dev libssl-dev liblz4-tool注意libncurses5-dev在22.04的默认源里确实没有,需要手动从Ubuntu 20.04源里下载deb包安装,或者启用老版本源。我这边是直接下载了deb包,因为就一个包,手动装反而少折腾:
# 从Ubuntu 20.04仓库下载并手动安装 wget http://archive.ubuntu.com/ubuntu/pool/universe/n/ncurses/libncurses5-dev_6.2-0ubuntu2_amd64.deb sudo dpkg -i libncurses5-dev_6.2-0ubuntu2_amd64.deb2.3 Python环境坑,必踩
Ubuntu 22.04自带Python 3.10,但SDK里部分脚本是用Python 2.7写的,比如老版本Android SDK里的repo工具、mkimage.sh相关脚本。虽然新SDK大多做了Python3适配,但保不齐哪个角落就有遗留。我的方案是安装python2并建立软链接:
# 安装Python2(如果22.04源里没有,用源码编译或者装miniconda的py2环境) sudo apt install -y python2 || true sudo ln -sf /usr/bin/python2.7 /usr/bin/python强烈不建议强行把python默认指向python3,因为好多老脚本里用的是Python2语法,你改了系统默认指向反而更容易暴雷。正确做法是按需切换,哪个脚本需要Python2就在执行前临时export一下。
3. SDK获取与离线包准备
3.1 SDK获取的几条路径
瑞芯微官方SDK一般通过两种方式分发:百度网盘和Git仓库(主要是gitlab.com上的rk3588仓库)。国内开发者大概率走网盘路线,因为官方Git仓库走起来速度感人,一个repo仓库动辄几十GB,同步到一半断连是常态。我搭环境时用的就是离线网盘包,大概30GB的压缩文件,解压后就是完整的SDK目录。
如果你从Git仓库拉取,核心命令是:
mkdir -p ~/rk3588-sdk cd ~/rk3588-sdk repo init -u [SDK仓库地址] -b [分支名] --no-repo-verify repo sync -c --no-tags -j4repo sync这里用-j4可能比-j8更稳,因为瑞芯微的服务器性能一般,并发太多会直接给你断开链接。这个坑我踩过,当时一把梭用-j16,结果拉到一半连接重置,又要重新开始。
3.2 离线包的结构与验证
离线包解压前先看一眼目录结构是否完整。一个标准的RK3588 Linux SDK离线包应该包含以下核心目录:
| 目录名 | 作用 |
|---|---|
kernel/ | 内核源码,通常对应Linux 5.10版本 |
u-boot/ | Bootloader源码 |
buildroot/ | 根文件系统构建系统 |
device/rockchip/ | 板级配置、设备树、分区表配置 |
external/ | 部分外部组件 |
docs/ | 开发文档、芯片手册 |
app/ | 部分应用层程序源码 |
tools/ | 打包工具、烧录工具 |
prebuilts/ | 预编译的工具链和二进制文件 |
解压前先校验一下压缩包的完整性:
# 如果附带md5sum文件,优先用md5校验 md5sum -c rk3588_sdk.md5sum # 解压 tar -xf rk3588_sdk_linux.tar.gz -C ~/sdk千万别跳过校验这一步。我试过一次网盘下载的压缩包,解压到一半报gzip: invalid compressed data,排查半天才发现是下载中断被自动续传软件搞出来的坏包。解压后顺手看一下SDK根目录下的README.md和docs/文件夹,里面通常会写本SDK对应的编译环境要求、已知问题和更新记录,先花10分钟过一遍能省后面2小时。
3.3 目录权限与符号链接检查
SDK解压完成后,检查一遍关键目录是否有可执行权限。因为Windows和Linux混用的情况不少,U盘或NTFS分区解压出来的文件可能丢权限位。
chmod +x build.sh chmod +x make*.sh chmod +x device/rockchip/common/*.sh另一个容易忽略的点是符号链接。SDK内部大量使用relativename形式的符号链接,如果解压过程中这些链接没被正确保留(比如在Windows下用WinRAR解压了zip格式的SDK包),编译时会报一堆莫名其妙的“找不到文件”错误。还有一个简单的检查命令:
find $SDK_DIR -type l -exec test -e {} \; -print | wc -l正常情况这个数字应该接近0(表示没有失效链接),如果输出大量路径,说明符号链接断了,重新检查你的解压方式。
4. 依赖环境搭建的手动与自动方案
4.1 SDK自带一键配置脚本的坑
绝大多数瑞幸的SDK根目录都有一个build.sh,执行./build.sh -h能看到编译选项。但这个脚本不会帮你安装系统依赖,它只负责编译层面的调度。部分版本SDK带了一个envsetup.sh,执行后能配置一些环境变量,比如交叉编译链路径、JAVA_HOME等。我的建议是把它跟当前shell环境绑定,方便后续编译:
source envsetup.sh执行后有没有生效,用echo $RK_BUILD_ROOT验证,能输出路径说明环境变量设置成功。很多新手栽在“明明执行了source,但编译时还是找不到命令”,多半是开了新终端忘了重新source。
4.2 在线安装依赖的完整记录
如果网络条件不错,我推荐用SDK自带的依赖检查脚本来装在线依赖。Linux SDK根目录下有scripts/或者docs/里会提供install_prerequisites.sh之类的脚本,执行一下就能把大部分依赖补齐。
如果不依赖脚本,手动安装的核心依赖清单如下,按顺序执行:
# 基础构建依赖 sudo apt install -y build-essential flex bison libncurses-dev \ device-tree-compiler bc lzop zip unzip \ libssl-dev libgmp-dev libmpc-dev \ gcc-aarch64-linux-gnu g++-aarch64-linux-gnu # 文件系统构建依赖 sudo apt install -y mtd-utils gdisk parted \ dosfstools mtools python3-pyelftools \ libfile-which-perl libswitch-perl # 若编译Android主线: sudo apt install -y openjdk-11-jdk schedtool \ m4 lib32z1 lib32ncurses6 \ lib32stdc++6 lib32gcc-s1 \ libx11-dev lib32readline-dev \ lib32z1-dev重点说下lib32系列,Android编译强制要求32位兼容库,Ubuntu 22.04在64位系统上默认不装这些,缺了会在链接阶段报/usr/bin/ld: skipping incompatible ...错误。第一次编译Android时报了一堆这种错,后来统一装完32位库才恢复正常。
4.3 离线安装方案,无网环境自救指南
很多公司内网开发环境是隔离的,或者开发者本机在复杂网络环境下apt源不稳定。这时候离线包的价值就体现出来了。我用的离线方案是“apt缓存转储+deb包仓库”的组合,核心思路是:在一台能上网的同版本Ubuntu 22.04机器上把所有依赖下好,做成离线安装包传递到目标机器。
制作apt离线包有两种常见方式:
方式一:利用apt缓存目录
# 在可联网的Ubuntu 22.04机器上先执行apt安装 sudo apt install -y [所有需要的包] # 把apt缓存中的所有deb包导出 mkdir -p ~/apt-offline-packages cp /var/cache/apt/archives/*.deb ~/apt-offline-packages/ # 打包带走 tar -czf apt-offline-packages.tar.gz ~/apt-offline-packages目标机器上解压后,用dpkg -i批量安装:
sudo dpkg -i *.deb这里有个坑:dpkg -i处理依赖顺序时容易报“依赖关系未满足”,需要多执行几遍。或者借助apt的--fix-broken修复一次:
sudo apt --fix-broken install -y方式二:用apt-offline工具
这个方案更优雅,apt-offline能生成一个包含所有包名和依赖信息的文件,在联网机器上下载后带回离线机器安装。不过实际体验中,它对多架构支持、特殊源的处理有一些坑,反正我是试过几次后还是老老实实用方式一。
4.4 交叉编译工具链的落位技巧
RK3588的交叉编译工具链通常SDK里会预置,Linux SDK一般在prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/这类路径下。如果你是用git方式同步的SDK,工具链一般会被repo sync一并同步下来,不需要额外下载。
关键是要把工具链路径加入PATH:
export PATH=$SDK_DIR/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/:$PATH验证是否生效:
aarch64-none-linux-gnu-gcc --version如果没有工具链,且离线包中没有预编译工具链,就需要自己从ARM官网下载交叉编译器,但在SDK编译时会出现版本匹配问题——官方SDK的Makefile很挑工具链版本,不是随便一个aarch64-linux-gnu-gcc都能编出能跑的内核和u-boot。所以我还是推荐想方设法拿到SDK配套的预编译工具链,这是省事的不二法门。
5. 编译核心流程与参数选择
5.1 选择编译目标,别一上来就全量
RK3588 Linux SDK的编译目标大体分内核、u-boot、Buildroot根文件系统三块。刚开始调试我建议分步编译,别一上来全量。
先编译内核:
cd kernel make ARCH=arm64 rockchip_linux_defconfig make ARCH=arm64 rk3588-evb1-lp4-v10.img -j16- 如果没有指定输出文件,直接
make ARCH=arm64 -j16也可以,会生成Image和dtbs。 rk3588-evb1-lp4-v10.img对应官方EVB1参考板的设备树。如果你用的是第三方核心板,设备树名称要改成厂商提供的那份。
编译u-boot:
cd u-boot make rk3588_defconfig ./make.sh rk3588编译完会生成uboot.img、trust.img等镜像文件。
编译Buildroot:
cd buildroot make rockchip_rk3588_defconfig make -j16整个Buildroot首次编译特别耗时,因为要交叉编译大量应用组件,快的机器也得1~2小时,慢的可能要一晚上。建议首次编译时开着screen或tmux跑,防止SSH断线导致编译中断。
5.2 全量编译的命令套路
当你确认三个核心组件都能各自编译通过后,再回到SDK根目录执行全量编译:
./build.sh lunch # 选择编译配置 ./build.sh # 全量编译 ./build.sh updateimg./build.sh lunch会弹出一个菜单让选板型和系统配置,跟Android的lunch逻辑类似。全量编译完成后,输出镜像位于rockdev/目录下。
这个顺序是我踩了几次坑才总结出来的。直接全量编译的问题在于,一旦某个组件编译报错,日志刷过去很难快速定位,而且不同组件的依赖关系可能让你白编译半天。分步编译,每个环节的验证目标都明确。
5.3 内存与CPU资源的调度技巧
RK3588 SDK编译极度吃内存,尤其是Buildroot里的高并发编译任务。我习惯把-j参数设成物理核心数的一半再加一点,比如8核机器用-j6或-j8,但绝不盲目用-j32。之前在一台32核服务器上开-j32编译Buildroot,直接触发OOM,日志还很难定位到底卡在哪个包。
内存不够时,可靠方案是增加swap。我在编译RK3588之前把swap临时加到32GB:
sudo fallocate -l 32G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile编译完成后可以关掉swap释放磁盘空间:
sudo swapoff /swapfile sudo rm /swapfile5.4 首次编译的最短路径实战
第一次上手,我建议按下面的最短路径跑通一次,不求编译出完整固件,只求验证整个工具链没问题:
- 编译内核dts和Image,检查交叉工具链是否正常;
- 单独编译u-boot的
idbloader.img和u-boot.itb; - 烧录到板子,用串口看打印信息是否正常。
内核编译时可以用make -j$(nproc)自动获取CPU核心数,不过如果机器同时在跑其他任务,还是手动指定一个小点的数值更稳。
6. 常见问题与排查技巧实录
6.1 问题排查的基本思路
RK3588 SDK编译报错信息往往不是直接告诉你缺哪个包,而是在中间某个环节爆出一段编译器输出,需要你反推。我的排查顺序是:先看日志尾部30行,确认报错位置是编译、链接还是打包阶段;再往前翻50行,找第一个error:前缀的行;最后根据报错内容回查依赖。
build.sh的日志默认输出在终端,建议重定向到文件,方便回溯:
./build.sh 2>&1 | tee build.log6.2 高频问题速查表
我把实际工作中遇到的高频问题整理成了一张速查表,每个项都是真实踩过的坑:
| 问题表现 | 根本原因 | 解决方案 |
|---|---|---|
fatal error: libncurses.h: No such file or directory | Ubuntu 22.04默认源缺ncurses5开发包 | 手动下载20.04源里的libncurses5-dev |
/usr/bin/ld: cannot find -lz | 缺32位zlib库 | sudo apt install lib32z1-dev |
error: 'PATH_MAX' undeclared | 内核编译时标准头文件冲突 | 检查是否在非内核目录编译,或清理include/generated |
cc1: error: invalid option '--no-integrated-as' | 编译Android时用了系统GCC | 确认prebuilts里的工具链被正确加载,不要用系统默认gcc |
repo sync: error: RPC failed; curl 56 | 网络不稳定导致Git拉取失败 | 降低并发数、换成网盘离线包 |
No rule to make target 'modules_install' | 内核配置未包含模块安装目标 | make modules_install前先make modules |
Error: DT compatible match not found | 设备树名称跟内核里的config不匹配 | 检查arch/arm64/boot/dts/rockchip/Makefile确认设备树已编译 |
Failed to connect to lunch | 缺少Python2环境或JDK配置错误 | 重新source环境脚本,检查java -version |
mcopy: command not found | 缺mtools包 | sudo apt install mtools |
file not recognized: File format not recognized | 交叉编译链版本与源码不匹配 | 确认SDK配套的预编译工具链,不要自行替换新版本 |
Cannot find device for /dev/mmcblk0 | 打包脚本跟实际存储介质不匹配 | 检查打包配置文件里的StorageType参数 |
6.3 独家排查技巧:交叉工具链的“版本指纹”
怀疑工具链版本有问题时,最快的方式是直接看SDK里Makefile或scripts/目录里定义的版本期望值,然后跟当前实际版本比对:
aarch64-none-linux-gnu-gcc -dumpversion比如SDK期望GCC 10.3,你这里显示11.2,那大概率会踩各种莫名其妙的内核编译错误。遇到这种情况,别纠结着填坑,直接找对版本的工具链替换回来更高效。
6.4 编译时间太长挂掉的恢复方案
典型场景:Buildroot编译到70%,SSH断了或者电源不稳导致编译进程被杀。重启后能接着编吗?答案是大部分组件支持增量编译,但Pipeline类构建可能产生部分残留文件导致冲突。我的做法是:
cd buildroot make clean make -j8有些时候make clean会把整套配置也清掉,需要重新make rockchip_rk3588_defconfig。这里有个小技巧:编译前把.config文件备份一份,恢复时直接拷回来:
cp buildroot/.config ~/buildroot.config.bak # 下次恢复 cp ~/buildroot.config.bak buildroot/.config make olddefconfig make -j8这个操作能省掉重跑menuconfig的繁琐步骤。
7. 离线包制作与分享的进阶心得
7.1 SDK离线压缩的边界问题
制作RK3588 SDK离线包时,不是简单tar czf就完事。SDK内部有大量.git目录,直接打包会异常巨大,而且很多仓库里有历史对象文件,完全没必要带走。我的做法是先同步完所有仓库后,把.git目录清理或者仅保留当前分支:
find . -name ".git" -exec rm -rf {} \;这样打包后的体积能缩小30%到40%。但注意,清理.git后,后续想用repo sync更新代码就不行了,需要重新从源头拉取。所以离线包一般用于一次性交付,不适合长期迭代。
7.2 apt离线依赖包的生成实践
前面提到的apt离线包方案,在实际操作中有几个细节要补充。/var/cache/apt/archives目录默认只保留apt-get install下载的deb包,手动dpkg -i的包不会自动存入。如果想生成完整的离线仓库,建议在联网机器上用:
apt-get download $(apt-cache depends --recurse --no-recommends --no-suggests --no-conflicts [包名] | grep "^\w" | sort -u)批量下载依赖。但这种方式容易漏掉部分虚拟包或已经存在的包,实操下来,还是先安装、再把缓存目录打包来得可靠。
7.3 离线包验证清单
交付离线包前,我习惯做一套完整验证:
- 用干净的Ubuntu 22.04虚拟机测试离线安装,确认所有deb包能批量安装;
- 手动解压SDK离线包,确认
/kernel、/u-boot等关键路径可访问,符号链接未损坏; - 跑一次最小编译(只编内核Image),确认交叉工具链落位正确;
- 记录离线包MD5值,发给对方时同步提供,方便校验。
这套验证流程虽然繁琐,但能杜绝“对方拿到包后一套操作,发现签名不对、链接断裂、依赖缺失”的尴尬场面。
8. 写在最后的小技巧
真正的环境搭好之后,有几个容易忽略的小习惯强烈建议养成。第一,所有编译命令都丢到tmux里跑,SSH断开不中断任务;第二,在SDK根目录维护一份自己的env.sh,把所有环境变量、工具链路径固化进去,每次新终端source一下,避免反复配置;第三,定期清理rockdev/和中间文件,防止磁盘爆掉。
我自己会把编译产生的所有镜像统一归档到一个带时间戳的目录,方便回退。这个习惯在调试内核版本兼容性时帮了大忙。希望这篇经验对正在跟RK3588 SDK较劲的你有点帮助,少踩几个我踩过的坑。