这篇文章记录这段过程里最重要的几个问题:开发环境怎么分工,Qt 工具和交叉编译器怎么配合,怎样确认生成的是 ARM 程序,以及界面启动后为什么还可能收不到数据。
本文使用的板卡终端标识为 RK3588-Tronlong,因此按创龙 RK3588 记录。具体板卡型号、系统镜像和 SDK 版本仍需以自己的设备资料为准。
本文是项目实践整理,不是适用于所有 RK3588 镜像的一键安装教程。环境版本和运行日志来自实际记录;下面重新整理的构建命令是操作模板,并非完整恢复的历史命令,也未在本文编写环境重新执行板端测试。路径、网口及 SDK 初始化方式需要按实际环境核对。
环境部署
本项目采用 Windows VS Code 远程连接 Ubuntu 虚拟机开发,Ubuntu 中使用 RK3588 LinuxSDK 提供的 Qt 交叉编译环境,通过 qmake 和 make 编译生成 ARM64 可执行程序,再通过 scp 上传到 RK3588 开发板,最后在 HDMI 显示器上使用 eglfs 平台运行 Qt 界面程序。
一、整体开发链路
1 | Windows 本机 |
Windows 负责编码,Ubuntu 虚拟机负责编译,RK3588 负责运行
二、开发环境分工
| 项目 | 配置 |
|---|---|
| Qt | 5.15.8,Qt Widgets |
| 构建工具 | qmake + make |
| 当前项目语言基线 | C++14,以当前 .pro 为准 |
| 编译器 | Linaro GCC 10.2.1,aarch64-linux-gnu |
| SDK | rk3588_linux_release_v1.2.1 |
| qmake mkspec | linux-aarch64-gnu-g++ |
| 目标程序 | tankae-host-aebss |
| 构建目录 | build-rk3588 |
为什么需要交叉编译
普通桌面编译器生成的 x86_64 Linux 程序,不能直接作为 ARM64 程序运行在 RK3588 上。Windows 的 .exe 也不是复制过去就能运行。
这里的交叉编译,就是在 x86_64 Ubuntu 上运行编译工具,生成 ARM64 Linux 可执行文件。
三、准备条件
1. Windows 本机
安装:
1 | VS Code |
2. Ubuntu 虚拟机
需要有:
1 | RK3588 LinuxSDK |
核心 SDK 目录示例:
1 | /home/lxt/RK3588/rk3588_linux_release_v1.2.1 |
3. RK3588 开发板
需要确认:
1 | cat /etc/os-release |
应为 Debian 系统。
确认 HDMI:
1 | cat /sys/class/drm/card0-HDMI-A-1/status |
正常应为:
1 | connected |
四、配置 Ubuntu 虚拟机环境
进入 SDK 目录:
1 | cd ~/RK3588/rk3588_linux_release_v1.2.1 |
如果还没有 Qt 交叉环境,执行:
1 | ./build.sh debian |
如何配QT的交叉环境
这一块是重点和难点
1. 安装 LinuxSDK
1 | Host# sudo apt-get install -y git ssh make gcc libssl-dev \ liblz4-tool expect expect-dev g++ patchelf chrpath gawk texinfo chrpath \ diffstat binfmt-support qemu-user-static live-build bison flex fakeroot \ cmake gcc-multilib g++-multilib unzip device-tree-compiler ncurses-dev \ libgucharmap-2-90-dev bzip2 expat gpgv2 cpp-aarch64-linux-gnu libgmp-dev \ libmpc-dev libmpfr-dev |
具体内容参考自带的说明书在这里不做过多追述。
2. 确认 SDK 路径与工具链
1 | /home/user/RK3588/rk3588_linux_release_v1.2.1 |
重点核对以下位置:
| SDK 内相对路径 | 作用 |
|---|---|
| extra-tools/gcc-linaro-10.2.1-2021.01-x86_64_aarch64-linux-gnu/bin | 交叉编译器 |
| debian/sysroots/x86_64-linux/bin | 在 Ubuntu 上运行的 qmake、moc、uic、rcc |
| debian/sysroots/armv8a-linux | 目标系统的 sysroot |
sysroot 可以理解成编译时使用的一份目标系统开发文件集合,包含目标平台的头文件、库和链接所需文件。它不是任意 Linux 根目录,都能拿来替换。
最容易混淆的一点是:qmake、moc 等工具运行在电脑上,所以它们是主机程序;最终链接的 Qt 库和生成的业务程序才需要是 ARM64。
不要看到工具目录中有 x86_64 就认定拿错了,也不要把板端的 ARM64 moc 拿到 Ubuntu x86_64 上执行。
五、检查环境并生成 Makefile
如果厂商 SDK 提供环境初始化脚本,优先按对应版本文档加载。下面的变量只是便于定位和检查,不等价于所有厂商的完整初始化脚本。
在 Ubuntu 终端执行:
1 | export RK_SDK=/home/lxt/RK3588/rk3588_linux_release_v1.2.1 |
检查目标架构是否是 aarch64-linux-gnu,Qt 版本是否符合项目要求,以及 qmake 查询中的 sysroot、头文件和库路径是否对应这套 SDK。
不要只看 qmake -v 显示了 5.15.8 就认为配置正确:同一个版本也可能有桌面 Qt 和交叉 Qt 两套安装。
如果 SDK 被移动到新目录后仍引用旧路径,应检查厂商的 SDK 重定位方法及 qmake 配置,不要在每个源码文件里硬编码路径补漏洞。
检查工程文件
本项目沿用 Qt Widgets 和 .pro 工程。示意配置如下,不要直接覆盖已有文件:
1 | QT += core gui widgets printsupport opengl svg |
使用 Linux/POSIX socket 的工程,并不一定需要 Qt Network 模块。模块清单要按真实代码决定。
六、使用独立目录交叉编译
先进入包含 project.pro 的工程根目录。确认 SDK 的 qmake 已配置好目标 sysroot 和库路径后,再执行下面的构建模板:
1 | mkdir -p build-rk3588 |
这个命令明确了工具选择,但仅仅指定 -spec 或编译器,并不能把一套桌面 Qt 变成可用的交叉 Qt。sysroot 和 ARM64 Qt 库仍必须正确配置。
先检查生成结果:
1 | rg -n '^(CC|CXX|LINK|AR|MOC|UIC|RCC|CFLAGS|CXXFLAGS|INCPATH|LFLAGS|LIBS)[[:space:]]*=' Makefile |
重点看 C/C++ 编译器和链接器是否属于 aarch64 工具链,Qt 头文件和库是否指向目标 SDK,以及编译、链接是否有效使用了目标 sysroot。某些配置通过编译器默认项传递 sysroot,不一定每一行都显式出现 --sysroot,必要时结合编译器查询和实际命令检查。
确认后构建:
1 | make -j"$(nproc)" |
虚拟机内存较少时可以改为 make -j2。并行任务越多,不一定越快。
为什么不继续手写 Makefile
早期尝试出现过:
1 | No rule to make target 'moc_mainwindow.o' |
Qt 中带有 Q_OBJECT 的类需要 moc 生成相应代码。手写构建规则容易遗漏依赖,而 qmake 可以根据工程配置生成相关规则。遇到这类问题,应该检查类头文件是否被工程正确管理,并重新生成构建文件,而不是删除 Q_OBJECT 来绕过错误。
如果换了工具链或 Qt 版本,使用一个新的构建目录验证,避免混入上一次留下的目标文件。
七、确认产物架构并上传开发板
在 Ubuntu 的构建目录中检查:
1 | file ./tankae-host-aebss |
项目已有产物记录显示为 ARM aarch64 ELF,动态加载器为 /lib/ld-linux-aarch64.so.1。检查到 x86-64 则说明仍然用了错误的构建配置。
“编译完成”只说明产物生成了,动态依赖和图形环境仍需在板端检查。
在上传之前确认目标目录存在,并先备份板上已有程序。下面是路径模板,替换账号、IP 和目录后使用:
1 | scp ./tankae-host-aebss <板端账号>@<RK3588管理IP>:<部署目录>/ |
尖括号表示占位符,不能原样复制执行。SSH 管理 IP 也不一定等于连接 FPGA 的那个网口 IP。
板端运行记录中的目录是 /home/Tronlong/QT1:
1 | cd /home/Tronlong/QT1 |
ldd 在目标板上检查自己的可信程序,留意 not found。缺少库时,使用匹配板端系统的 ARM64 库,不要复制 Ubuntu x86_64 的库,也不要随意替换板端系统库。
八、排查窗口无法打开的问题
| 现象 | 优先检查 |
|---|---|
| Exec format error | 可执行文件架构是否正确 |
| 文件存在却提示 No such file or directory | ELF 动态加载器是否存在;若为脚本则检查解释器 |
| error while loading shared libraries | 动态库是否缺失或搜索路径错误 |
| Could not load the Qt platform plugin | 平台插件、依赖库和图形会话 |
| 界面能打开,但没有波形 | 通信、采集状态及数据解析 |
平台插件排查时可在板端执行:
1 | QT_DEBUG_PLUGINS=1 ./tankae-host-aebss |
有桌面的镜像可能使用 X11 或 Wayland;无桌面的嵌入式配置可能使用 EGLFS 等方式。选择取决于当前镜像和 Qt 构建,不能把设置 QT_QPA_PLATFORM=eglfs 当成所有板子的通用修复。
尤其是通过 SSH 启动时,还涉及图形会话的访问权限。先在板端已有桌面终端运行通常更容易区分问题,不要用关闭显示访问控制的方式绕过权限。
九、参考资料与适用范围
本文的设备环境、路径和错误日志来自本项目开发记录;Qt 通用机制可结合以下官方资料理解:
- Configuring qmake:qmake 配置与 mkspec 概念。
- Using the Meta-Object Compiler:moc 的作用与构建集成。
- Configure an Embedded Linux Device:主机工具、目标系统和交叉构建概念。
以上在线链接为 Qt 6 文档,仅用于通用概念参考;本项目使用 Qt 5.15.8,不能将 Qt 6 的配置或 CMake 命令直接替换进本项目。实际操作仍以对应版本的厂商 SDK 文档为准。