说实话,拿到RK3568开发板之后,真正让人头疼的往往不是硬件本身,而是软件环境。特别是你想在板子上跑Qt界面程序时,第一步就卡在一个问题上:怎么在Ubuntu上把Qt交叉编译环境搭起来,还要能在Qt Creator里一键编译、一键部署、一键调试。这活儿我折腾过好几回,踩过不少坑,今天把整个流程整理成一篇能直接照着抄的文章,从交叉编译原理、工具链选择、Qt源码编译,到Qt Creator配置和远程调试,一次说清楚。
这个流程适合的目标读者很明确:手上有RK3568开发板,打算用Qt做嵌入式GUI,宿主机是Ubuntu的开发者。不管你是刚接触嵌入式Linux的小白,还是从单片机转过来的老手,这篇文章都尽量讲得细致一些,至少让你少走我当年走的弯路。
1. 为什么要在Ubuntu上搭这套环境:先搞清楚交叉编译的原理
1.1 从x86到ARM:交叉编译到底解决什么问题
RK3568是瑞芯微旗下的一颗ARM64架构处理器,核心是四核Cortex-A55。我们日常开发用的PC,绝大多数是x86_64架构。x86和ARM是两套完全不同的指令集,这就像一个是简体中文、一个是繁体中文,虽然都认识,但直接混着用是不行的。
问题就来了:在板子上直接编译Qt工程不现实。RK3568虽然能跑Linux,但算力有限,编译一两千个源文件的Qt库可能得等半天甚至更久,而且板子上的存储一般也不宽裕。所以常规做法是在性能强劲的PC上,用一套能生成ARM指令集程序的编译器来编译代码,再把编译好的二进制拷到板子上运行。这个“在A架构上编译B架构程序”的过程,就叫交叉编译。
这里面有个关键概念需要先理解透彻:交叉编译器不止是一个gcc/g++那么简单。它背后是一整套工具链,包括汇编器、链接器、C标准库头文件、glibc运行库等等,它们共同决定了你能编出什么样的程序,以及这个程序将来能在什么环境里跑。很多时候大家把交叉编译叫“工具链”,原因就在这里。
1.2 RK3568平台的特殊性:工具链版本不是随便选的
RK3568是ARMv8-A架构,对应的是aarch64也就是64位ARM指令集。如果你拿一套32位的arm-linux-gnueabihf工具链去编译,虽然也能编出ARM程序,但不是针对RK3568优化的,而且很多依赖库的系统路径、库文件都不对,跑起来各种报错。所以第一步就要选对:aarch64-linux-gnu这套64位工具链。
工具链版本这事儿我多说一句。别不听劝就上最新的gcc 13、gcc 14,我实测下来,RK3568这类板子配套的官方SDK里通常自带工具链,版本稳定在gcc 9.3到10.3之间。这个版本范围内的工具链,和板子自带的glibc版本是能匹配的,编译出来的程序放上去直接就能跑。如果你用太新的工具链,很有可能编出来的程序在板子上报“version `GLIBC_X.XX' not found”,然后你就要去折腾板子的rootfs降级,那是真的痛。
1.3 环境搭建的两条路线:SDK工具链和独立工具链怎么选
搭建交叉编译环境有两条路线,我先说清楚,你自己权衡。
第一条路线是用厂商SDK自带的工具链。RK3568的开发板不少,正点原子、迅为、飞凌这些都有配套SDK,解压之后在prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-x86_64-aarch64-none-linux-gnu/bin/路径下就能找到现成工具链。这种方式的好处是和板子的内核版本、库版本高度匹配,基本不会出现跑不起来的问题,缺点是路径藏得比较深,环境变量得自己配。
第二条路线是用ARM官方发布的工具链,或者Linaro工具链,自己去gcc.arm.com下载解压。这种路线的好处是版本选择灵活,坏处是你要多花精力去匹配板子rootfs里的glibc版本。我个人的建议是:如果你手头有厂商SDK,优先用SDK里的;项目一旦稳定下来,版本就不要改了,换来换去早晚出事。
2. 基础环境准备:Ubuntu、工具链与验证小实验
2.1 宿主机需要装什么
我默认你已经装好了Ubuntu系统。版本上,20.04和22.04我都跑过,都行。如果你用的是虚拟机,建议给虚拟机分配至少4核CPU和8GB内存,否则后面编译Qt源码,在看片转圈的时候真的会怀疑人生。
首先把基础工具装齐,打开终端执行:
sudo apt update sudo apt install -y build-essential gdb-multiarch rsync ssh vim这四条命令分别做了什么事,我说明一下:
- build-essential:包含编译必需的make、gcc、g++等,宿主机本地的编译环境得先立起来。
- gdb-multiarch:一个跨架构的gdb调试器,x86上调试ARM程序就靠它。很多教程会让你装aarch64-linux-gnu-gdb,如果工具链包里没有,用gdb-multiarch一样能干这活儿,Qt Creator也能识别。
- rsync:后面把板子的系统目录同步到宿主机,以及文件部署,都离不开它。
- ssh:远程连接板子、执行命令上传文件的基础,不装什么都干不了。
额外提醒一个容易忽略的包:libxkbcommon-dev。后面你编译Qt源码时如果开了xcb相关模块,很容易因为缺少这个依赖直接报错。既然要搭环境就一步到位装好吧:
sudo apt install -y libxkbcommon-dev2.2 下载并配置ARM64交叉编译工具链
不管你用哪条路线拿到工具链,本质上都是一堆解压即用的文件。以SDK内举例,假设工具链目录位于~/rk3568_sdk/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-x86_64-aarch64-none-linux-gnu,我需要把它加进PATH里。
我习惯在~/.bashrc末尾追加一段环境变量配置:
export RK_TOOLCHAIN=~/rk3568_sdk/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-x86_64-aarch64-none-linux-gnu export PATH=$RK_TOOLCHAIN/bin:$PATH然后执行:
source ~/.bashrc这里有个细节值得注意:环境变量最好写在最后面,不要覆盖系统原有的PATH。很多代码编译工具依赖宿主机的python、perl等解释器,如果你把PATH里宿主机命令的优先级挤掉,后面编译Qt源码时会冒出一堆莫名其妙的问题。
2.3 用一个小程序验证工具链是否可用
工具链配好只是第一步,真金白银要经过火炼。写一个最简单的Hello World验证一下:
mkdir -p ~/rktest && cd ~/rktest cat > hello.c << 'EOF' #include <stdio.h> int main() { printf("Hello RK3568!\n"); return 0; } EOF然后交叉编译:
aarch64-linux-gnu-gcc hello.c -o hello_arm file hello_arm如果输出中包含ELF 64-bit LSB executable, ARM aarch64这样的字样,恭喜,工具链基本没问题了。我习惯再用readelf -l hello_arm | grep interp看一眼程序依赖的动态链接器路径,正常情况下应该是/lib/ld-linux-aarch64.so.1,这能提前预判glibc兼容性问题。
这个验证程序到后面还会用到,先别删。
3. Qt源码交叉编译:整个过程最核心也是最磨人的一步
3.1 为什么不能用apt直接装的Qt来交叉编译
我知道很多新手习惯在Ubuntu上sudo apt install qt5-default,这没问题,但在交叉编译这个场景里完全行不通。用apt装的是面向x86宿主机编译好的二进制包,它调用的qmake、Qt库都是x86指令集。你拿着这个qmake去编译ARM程序?它会很认真地告诉你:我只会编x86。
所以交叉编译Qt,必须走这条老路:下载Qt官方源代码包,用交叉工具链在x86机器上编译出一套ARM架构的Qt库,这套库加上配套的qmake,才是有资格参与RK3568交叉编译的完整工具链。
这一步是整个搭建过程中最容易让人崩溃的环节,因为Qt源码体量大、依赖面广,你configure时候漏掉一个选项,编译到一半才报错,返工成本极高。我下面把每一步的关键参数和背后的原因都拆开讲。
Qt的源码包,我建议选qt-everywhere-src-5.15.2.tar.xz。5.15是LTS长期支持版本,RK3568的嵌入式GUI场景下稳定性有保障。Qt6系列的configure参数变化较大,不是不能用,但网上参考案例少,踩坑了你连个问的地方都不好找,先把5.15跑通再说。
解压源码:
mkdir -p ~/rk3568/qt && cd ~/rk3568/qt tar xf qt-everywhere-src-5.15.2.tar.xz3.2 准备sysroot:把板子的库同步到宿主机
这是很多教程会一笔带过、但实际特别关键的一步。Qt交叉编译时,编译器需要找到目标平台的头文件和库文件,比如c标准库、tslib触摸库、各种Linux系统库。这些文件从哪里来?答案是直接从开发板的rootfs里同步过来,那套文件集合就叫sysroot。
先在你的PC上建目录:
mkdir -p ~/rk3568/sysroot cd ~/rk3568/sysroot然后用rsync连接你的板子同步目录。我假设板子的IP是192.168.1.100,用户名root:
rsync -av root@192.168.1.100:/lib . rsync -av root@192.168.1.100:/usr/lib sysroot/usr/注意我这里是同步到sysroot/usr/子目录里,因为工具链默认会去sysroot/usr/lib寻找库文件。操作完成后,务必确认目录结构像这样:
~/rk3568/sysroot/ ├── lib └── usr └── lib有一个细节必须特别注意:rsync同步的时候会保留符号链接,这本身是好事,但很多板子上的符号链接是指向绝对路径的,比如/lib/aarch64-linux-gnu/libm.so.6 -> /lib/aarch64-linux-gnu/libm-2.28.so,到了宿主机上依然指向绝对路径,结果就是工具链找不到文件。遇到这种情况,我建议你在sysroot里手动创建一个从sysroot根目录到实际库目录的软链接,或者干脆重新调整库文件目录,把板子的/usr/lib/aarch64-linux-gnu整个同步进来。稳妥做法是:
rsync -av root@192.168.1.100:/usr/lib/aarch64-linux-gnu sysroot/usr/lib/具体路径以你板子的实际目录为准,先ssh到板子上用ls确认,别想当然。
如果你的应用还要用tslib触摸库,检查一下板子上有没有/usr/include/tslib.h,没有就得先把tslib编译安装到板子上,再从板子同步。这属于前置依赖,漏了后面Qt configure必然过不去。
3.3 configure参数详解:哪些项必须开、哪些项必须关
进入Qt源码目录,创建一个build目录独立编译,这是我一直坚持的好习惯,编译产物和源码分开,以后清理非常方便:
cd ~/rk3568/qt/qt-everywhere-src-5.15.2 mkdir build && cd build然后执行configure。下面这份配置是我在RK3568上经过多轮验证的,可以直接拿来用:
../configure -prefix /opt/qt5.15.2-aarch64 \ -opensource -confirm-license \ -release \ -xplatform linux-aarch64-gnu-g++ \ -sysroot $HOME/rk3568/sysroot \ -linuxfb \ -eglfs \ -opengl es2 \ -tslib \ -no-xcb \ -no-openssl \ -skip qtwebengine \ -skip qtmultimedia \ -nomake examples -nomake tests每个关键项我都解释一下,因为光会抄参数不行,你得知道动了什么:
- -prefix /opt/qt5.15.2-aarch64:最终编译好的Qt库安装路径。这个路径是你宿主机的路径,不是板子的。
- -xplatform linux-aarch64-gnu-g++:告诉Qt源码用哪个平台定义文件来编译。在源码的qtbase/mkspecs/目录下你会看到linux-aarch64-gnu-g++这个文件夹,里面是qmake.conf和qplatformdefs.h,专门针对aarch64交叉编译写的。如果你的工具链前缀不是aarch64-linux-gnu,这个mkspec可能也要微调,但大多数情况直接用就行。
- -sysroot:指向刚才同步的sysroot目录,这是Qt交叉编译和宿主机编译最大的区别之一。有了它,编译器才知道去哪里找头文件和库。
- -linuxfb -eglfs -opengl es2:这三个是嵌入式Qt最常用的平台插件。RK3568有GPU,支持Mali GPU的OpenGL ES 2.0,编译进去之后,程序就能用eglfs模式跑硬件加速,也可退回到linuxfb纯软件渲染。两个都编进去,运行时候用命令行切换,灵活很多。
- -tslib:如果你的板子用了电阻式触摸屏,多数情况会外接tslib库,这里打开选项,Qt的linuxfb平台就能读取触摸事件。如果板子用的是电容触摸屏,走的是evdev协议,其实开不开tslib影响不大,但我个人建议开到,防止以后换屏麻烦。
- -no-xcb:RK3568上跑Qt GUI,主流是不跑桌面环境,直接用framebuffer或EGLFS,不需要X11,更不需要xcb插件。关掉xcb能省一长串依赖,省去很多不必要的烦恼。
- -no-openssl:如果你的程序将来要跟HTTPS服务器交互,这个选项要慎重关掉。但交叉编译OpenSSL本身是个独立工程,且会把configure复杂度拉高一个数量级,我建议第一版先关掉保平安,后面有需求再单独编。
- -skip:跳过一些在嵌入式场景下用不到的重量级模块,qtwebengine编译起来能让你等到怀疑人生,skip掉能大幅节省编译时间。
configure执行完之后,终端会显示一大堆配置总结。我每次都会在输出里找三个关键词:linuxfb yes、eglfs yes、tslib yes。只要这三个都是yes,后面编译基本就稳了。
3.4 编译、安装和一次常被忽略的验证
configure通过后,真正的考验开始了。执行编译:
make -j$(nproc)这里的-j$(nproc)会自动把并发线程数设成CPU核心数。如果是在虚拟机上,建议相对保守一点,比如-j4,否则内存不够的话编译到一半直接OOM被杀死,前面的等待全部白费。
编译完成后安装到指定prefix目录:
sudo make install为什么需要sudo?因为/opt目录默认root权限,而prefix指向那里。如果你不想用sudo,也可以把prefix改成$HOME/qt5.15.2-aarch64,这一层次可以自己定。
装完后,到/opt/qt5.15.2-aarch64/bin/目录下看一眼,确认qmake文件存在。然后做一个最关键的验证,执行:
/opt/qt5.15.2-aarch64/bin/qmake -query输出的QT_INSTALL_PREFIX应该指向 /opt/qt5.15.2-aarch64,QMAKE_SPEC应该是linux-aarch64-gnu-g++。如果这两个值不对,后面Qt Creator里所有的自动查找都会乱套。
我还习惯用这个qmake来编译一个最小Qt程序测试,避免Qt库编完了但没法用的尴尬:
cd ~/rktest cat > qt_test.cpp << 'EOF' #include <QApplication> #include <QLabel> int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel label("Qt on RK3568 OK!"); label.show(); return app.exec(); } EOF用交叉qmake编译:
/opt/qt5.15.2-aarch64/bin/qmake -project /opt/qt5.15.2-aarch64/bin/qmake make如果这一步能顺利生成可执行文件,且file qt_test显示aarch64,说明Qt交叉编译环境核心链路已经打通了。
4. Qt Creator配置:把交叉编译环境“带劲”起来
Qt库编好了,但日常开发总不能命令行敲全套make吧?接下来把这一切配置进Qt Creator,让IDE自动完成编译、部署、调试,这才能谈开发效率。
4.1 配置交叉编译器与调试器
打开Qt Creator,进入Tools -> Options -> Kits。左侧选Compilers,点击Add -> GCC -> C,在Compiler path里选择工具链bin目录下的aarch64-linux-gnu-gcc。按同样操作添加C++编译器,选择aarch64-linux-gnu-g++。
这里我要重点提醒一个界面细节:Qt Creator的编译器配置页里有个ABI下拉框,很多时候自动识别成Generic,会导致后面的Kit识别不了。你应该手动把ABI设置成arm-linux-generic-elf-64bit,不行的话就选aarch64-linux-generic-elf-64bit。这一步是很多新手第一次配Kit失败的直接原因。
接着切到Debuggers标签页,点Add -> GDB:
- 如果工具链bin下有aarch64-linux-gnu-gdb,直接选它。
- 如果用的是缩水版工具链没有,就用系统装好的/usr/bin/gdb-multiarch。
两个都能跑,但注意gdb-multiarch需要你在启动调试前手动指定目标架构,Qt Creator 新版本一般会自动带上,老版本偶尔会忘,到时我下面调试环节再讲怎么处理。
4.2 添加Qt版本与qmake路径
在同一个Kits窗口中,切到Qt Versions,点击Add,选择/opt/qt5.15.2-aarch64/bin/qmake。确认后在下方显示“Qt 5.15.2 (qt5.15.2-aarch64)”就说明识别成功了。
这里有第二个坑:Qt Creator 会尝试运行qmake -query来获取Qt的信息,如果你的PATH环境变量在GUI启动时没加载qmake相关路径,可能显示“Error”。解决办法不是去改环境变量(因为GUI环境不一定读取.bashrc),而是直接用按钮切换到/opt/qt5.15.2-aarch64/bin/qmake这个绝对路径,通常情况下它会重新运行查询并恢复。
4.3 配置远程设备与Kit:把三者串起来
还是在这个窗口,切到Devices标签页,点击Add,选择Generic Linux Device。填写:
- Name:RK3568 Board
- Host name:192.168.1.100
- Username:root
- Password:你板子的root密码(默认一般是rockchip)
配置完成后,Qt Creator会尝试通过ssh连接板子并在启动时做连通性测试。这一步如果失败,优先检查板子的SSH服务是否开启,命令是:
sudo systemctl status sshd如果没有,就在板子上安装或自启动:
sudo systemctl enable ssh最后回到Kits标签页,点击Add,新建一个Kit,取名叫RK3568 Qt 5.15.2,然后在各个下拉框里选:
- Compiler:C和C++都选刚才添加的RK3568 GCC/G++
- Debugger:选刚加的gdb
- Qt version:选5.15.2-aarch64
- Device type:Generic Linux Device
- Device:RK3568 Board
- Sysroot:填~/rk3568/sysroot
注意,Sysroot这项必须填,否则你将来在Qt Creator里打开Qt的头文件、查看Qt库源码时会定位到宿主机的Qt头文件,最后看到的源码根本对不上,调试信息也会乱一截。
4.4 新建一个测试工程验证整套链路
在Qt Creator里新建一个Qt Widgets Application,把构建套件选成刚配好的RK3568 Qt 5.15.2。写一个简单界面,然后直接点左下角的“构建”按钮。
如果构建顺利,会生成一个aarch64架构的二进制。部署到板子上有两种方式:
一种是直接用Qt Creator的部署功能,在Projects -> Run页面里配置部署步骤,勾选“Upload files via SFTP”之类的选项。这个方式适合文件量少的场景。
另一种是我个人偏爱的:命令行手动scp。原因很简单,部署到嵌入式板子时,你还需要把整个Qt运行库上传过去,那是一个大目录,IDE的部署功能处理起来既慢又容易遗漏。
scp ./qt_test root@192.168.1.100:/root/ scp -r /opt/qt5.15.2-aarch64/lib root@192.168.1.100:/opt/qt5.15.2-aarch64/上传完库文件后,在板子上设置环境变量:
export LD_LIBRARY_PATH=/opt/qt5.15.2-aarch64/lib:$LD_LIBRARY_PATH export QT_QPA_PLATFORM=linuxfb然后运行:
./qt_test看到板子屏幕上出现“Qt on RK3568 OK!”的窗口,这一步通关。
5. 远程部署与调试实操
在板子上能看到界面是一回事,能用Qt Creator断点调试代码又是另一回事。嵌入式开发最痛苦的时刻就是程序崩了,却只知道printf一行行加。远程调试能很大程度缓解这个问题。
5.1 部署机制:rsync同步、权限与依赖处理
上面提到了用scp上传文件,但实际项目越做越大,文件越改越频繁,scp就变得不高效了。我给一个更省心的方案:用rsync做增量同步。
在宿主机上写一个简单的部署脚本deploy.sh:
#!/bin/bash rsync -avz --progress \ --exclude='*.o' --exclude='*.user' \ ./build/rk3568/your_app root@192.168.1.100:/root/app/每次编译完后执行一下脚本,只有变更的文件会被传上去,带宽和时间节省非常明显。同时记得脚本里加上--exclude,把不需要的对象文件排除掉。
还有个必须养成习惯的点:板子上的库依赖。如果Qt程序依赖/opt/qt5.15.2-aarch64/lib下的动态库,你在板子上运行前必须确认环境变量:
export LD_LIBRARY_PATH=/opt/qt5.15.2-aarch64/lib:$LD_LIBRARY_PATH每次ssh登进去都要重设,很烦。推荐直接把这一行写进板子的/etc/profile里,一劳永逸。
5.2 在开发板上准备gdbserver
远程调试的架构是:板子上跑一个轻量gdbserver程序,负责接收调试指令并控制目标进程;宿主机上由gdb(Qt Creator 内置)通过网络发送调试指令。两边可以不同架构,gdbserver是ARM版,gdb是x86版,但它们之间通过调试协议通信,架构无关。
Ubuntu的apt源里不一定有aarch64版的gdbserver,所以推荐在板子上直接安装:
apt update && apt install gdbserver安装完成后验证一下:
gdbserver --version如果板子的rootfs里面没有apt源,或者装不上,还有一个办法:直接从宿主机工具链SDK里拷贝。很多工具链自带一个aarch64-linux-gnu-gdbserver,路径在bin目录下,把它scp到板子上用就行。
5.3 Qt Creator远程调试设置细节:路径映射与运行环境变量
回到Qt Creator,先配置Run选项。在Projects -> Run页面里,把Run locally取消掉,勾选Run on device,设备选RK3568 Board。这样Qt Creator会通过SSH在板子上启动程序,并且能够自动接入调试器。
这里有一个特别常见的问题:Qt Creator通过device启动程序时,运行环境变量跟板子上手动设置的不一样。你必须在Run页面下方的Run Environment里手动添加:
| 键 | 值 |
|---|---|
| LD_LIBRARY_PATH | /opt/qt5.15.2-aarch64/lib:$LD_LIBRARY_PATH |
| QT_QPA_PLATFORM | linuxfb |
不配好这两项,你在Qt Creator里一点调试按钮,程序在板子上可能还没跑到main()就崩了,报错信息还特别隐晦,说的是“加载共享库失败”之类的,让人一头雾水。
接着配置路径映射。调试的本质是拿板子上的符号信息跟宿主机上的源码做匹配。你在宿主机用/home/oem/RK3568_Qt/hello/main.cpp这个路径打开源码,但板子上gcc编译出来的调试符号里记录的是板子上的编译路径,两者对不上,断点就打不上。解决方法是:
Tools -> Options -> Debugger -> General -> Source Paths Mapping里添加一条映射,比如:
/opt/qt5.15.2-aarch64 -> /home/oem/RK3568_Qt/hello如果你整个工程都放在固定路径下,也可以在项目设置 -> Debugger Settings -> Debugger里单独配置,作用域更精确。
配置完成后,整体流程就是:写好代码,点编译,Qt Creator自动上传到板子,调用gdbserver启动进程,宿主机连接上去,然后就可以像调试本地程序一样加断点、看变量、看调用栈。
有一点要提醒:嵌入式远程调试比本地调试多了一个网络延迟,单步执行会有肉眼可见的卡顿,这是正常的,不是你的电脑坏了。我在实际开发中一般用远程调试来定位崩溃和逻辑bug,性能调优则靠打印日志辅助,两者结合效率最高。
6. 踩坑实录:高频问题与排查思路速查
环境搭建类的话题,光讲流程不讲坑等于白讲。这节我把这些年遇到过的典型问题整理成一个速查表,按阶段分类,方便你到时候直接翻。
6.1 编译阶段的常见报错
| 报错信息 | 原因分析 | 解决思路 |
|---|---|---|
| cannot find -lts | sysroot里没有tslib库文件 | 在板子上安装libts-dev,重新同步sysroot |
| GL/gl.h: No such file or directory | 缺少OpenGL相关头文件 | 检查sysroot的usr/include里有没有mesa、GLES头文件,必要时同步板子的/usr/include |
| qatomic.h: No such file | sysroot不完整,Qt版本和头文件mismatch | 重做sysroot同步,确保目录结构完整 |
| error: unknown type name ‘bool’ | 编译器参数或C语言标准问题 | 检查是否在纯C文件中混编了C++代码,用g++编译 |
libQt5Core.so: undefined reference todlopen@GLIBC_2.x | 板子的glibc版本太老,工具链太新 | 换用更低版本工具链,或升级板子rootfs |
编译阶段还有一个很典型的坑:make -j6 时编译到一半突然报internal compiler error: Killed (program cc1plus),这是内存不足把编译器杀了。解决办法是减少并行线程数,或者给虚拟机多分配内存,没有别的捷径。
6.2 运行阶段的高频问题
程序编译出来了,拷到板子上跑,报错也是五花八门。我把最常见的几种列出来:
| 报错信息 | 原因分析 | 解决思路 |
|---|---|---|
| application could not be executed | 二进制格式不对 | 用file检查文件头,确认是ELF 64-bit ARM aarch64 |
| error while loading shared libraries: libstdc++.so.6 | 缺少C++运行库 | 把/opt/qt5.15.2-aarch64/lib和板子上的/usr/lib相应对齐,确认工具链的库都部署了 |
| The wayland display couldn't be opened | 默认走了wayland平台插件 | 显式设置QT_QPA_PLATFORM=linuxfb或eglfs |
| could not find or load the Qt platform plugin "xcb" | 之前configure开了xcb选项,但相关依赖缺失 | 运行时设置QT_QPA_PLATFORM=linuxfb,或者重新编译时加-no-xcb |
这里我要重点说下QT_QPA_PLATFORM这个东西。Qt从5.0开始抽象出一层QPA(Qt Platform Abstraction),它在运行时决定Qt怎么跟底层显示系统交互。在开发板上,最保险的启动方式就是先设成linuxfb,它走Linux framebuffer,不依赖任何显示服务,兼容性最强。如果你在板子上装了完整的桌面环境,想跑在X11下面,才需要设置成xcb。而在RK3568上,如果想调用GPU硬件加速,设成eglfs会是最佳选择,但前提是Mali驱动已经正确加载,且你的Qt编译时带了-eglfs选项。
6.3 远程调试阶段的常见坑
| 现象 | 原因分析 | 解决思路 |
|---|---|---|
| 点击调试后,Qt Creator卡在“Connecting to server” | 板子上gdbserver没启动,或端口被防火墙挡了 | 先手动在板子上启动gdbserver :2345,确认能连 |
| 断点显示灰色,提示“not valid at this line” | 源码路径映射没配好,或有优化release编译导致行号错位 | 检查Debugger的Source Paths Mapping,改成release为debug |
| 断点命中后看不到变量值 | 编译时没加调试符号 | 确保编译时是debug模式,qmake工程中CONFIG += debug |
| 调试器报“Remote connection closed” | gdbserver崩溃或板子掉线 | 查看板子端gdbserver的日志,确认程序没有在启动阶段直接segfault |
| 单步调试卡死 | 网络延迟或同步点卡住 | 减少单步频率,多在不常变化的行打断点跳着走 |
远程调试还有一个特殊情况:如果你的程序在main()之前就崩了,比如动态链接库加载失败,Qt Creator的调试器是不好抓到的。这时候我会在板子上手动执行:
gdbserver :2345 ./your_app然后在宿主机用gdb attach上去,用info sharedlibrary查看哪些库没加载,往往能飞快定位到缺失依赖。
整个环境搭好之后,日常开发就进入一个相对舒服的节奏:宿主机写代码、编译、一键部署、远程调试,板子上的逻辑用断点和日志并行定位。这套流程我现在用得很顺手,但前期的坑也算踩了个遍。说实话,如果让我重来一次,我会在下载Qt源码之前,先把板子上的glibc版本、tslib依赖、工具链版本这三角关系理清楚,能省下非常多返工时间。希望这篇文章能帮你把这段路走得顺一点。