尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

RK3568 Qt交叉编译环境搭建与远程调试实战指南

RK3568 Qt交叉编译环境搭建与远程调试实战指南 如果你手上正好有一块RK3568开发板想在Ubuntu下用Qt开发界面那这篇文章就是给你写的。RK3568是ARM64架构的处理器而我们常用的Ubuntu开发机是x86_64两边指令集完全不一样所以必须用交叉编译在Ubuntu上生成ARM64可执行文件再部署到板子上跑。搭配Qt Creator做可视化管理、配合gdbserver做远程断点调试这套流程是嵌入式Linux开发中非常经典的组合。文章以Ubuntu 20.04 Qt 5.12.10 RK3568为例把环境搭建的每一个环节都拆开讲清楚交叉编译工具链怎么装、Qt源码怎么针对ARM架构编译、Qt Creator里怎么配置套件和远程设备、以及最后怎么实现断点调试。无论你是刚从桌面Qt转过来还是第一次接触RK3568都可以按着步骤操作把坑提前避开。1. 动手前先理清整体设计为什么这套环境这么搭1.1 交叉编译到底是什么为什么绕不开先明确一个概念普通开发中你在Ubuntu上写的程序编译出来是x86_64格式直接在本机运行。但目标板是ARM64的RK3568CPU是四核Cortex-A55它没法直接执行x86_64的二进制。你要么在板子上装一套完整的gcc编译器去本机编译要么就在开发机上用支持ARM64的工具链编译出ARM64格式的程序再拷贝到板子上运行。第二种方式就叫交叉编译。嵌入式开发几乎都走这条路原因也很现实RK3568核心板的内存、存储和CPU算力虽然够用但比起动辄16核32G内存的开发机还是差了不少尤其是编译大型C工程、Qt库这种量级的代码板载编译一次可能要几个小时而交叉编译十几分钟就搞定。而且大规模的Linux SDK比如buildroot、yocto本身就默认用交叉编译方式构建整个根文件系统你个人写应用最好也保持同样的工具链避免最后动态库ABI不一致。打个简单的比方交叉编译就像你在中国下单让工厂按日本插座的规格生产电器再出口到日本用。你不需要人肉飞到日本去改生产线只需要用对应的模具——也就是aarch64交叉编译工具链。1.2 选型细节Qt版本、工具链和显示后端如何取舍RK3568相关的开发板很多正点原子、飞凌、瑞芯微官方EVB等都在用它们的SDK版本和板级配置会有些差异但应用程序层面的开发方式是一致的。Qt版本目前RK3568项目里用得最多的还是Qt 5.12.x和5.15.x尤其是5.12.10它是嵌入式圈子里口碑很稳的LTS版本很多板卡厂商的BSP默认就带它。Qt 6虽然新但嵌入式设备上的平台插件、GPU适配、qml模块的支持并不如5.x成熟所以我建议新项目优先选5.12.10稳妥第一。工具链Ubuntu 20.04可以直接通过apt安装gcc-aarch64-linux-gnu这个简单省事。但要注意有些老SDK自带的是Linaro的gcc 7.5工具链如果你的SDK是用老工具链编的那应用最好也用它编。后面我会讲怎么确认版本一致性。显示后端Qt在嵌入式Linux下跑界面通常有三个平台插件可选linuxfb、eglfs、wayland。区别可以用一个表格说清楚平台插件依赖GPU适用场景特点linuxfb不需要简单UI、无GPU环境直接把窗口绘制到/dev/fb0实现简单性能一般eglfs需要Mali等GPU全屏应用、车载/HMI用EGL直接渲染到屏幕流畅度高wayland需要wayland compositor多窗口、多进程UI灵活但环境搭建复杂不适合入门RK3568带Mali G52 GPU理论上跑eglfs效果最好但前提是你正确移植了Mali用户态驱动。很多新手上来就卡在eglfs的显卡库上半天黑屏。我自己的建议是第一轮先用-no-opengl加linuxfb把整个链路跑通程序能出画面、能触摸然后再去深入研究eglfs的GPU加速。先把基础盘活再去吃大餐。2. 基础环境与交叉编译工具链准备2.1 Ubuntu开发机需要安装的依赖清单开发机建议直接用Ubuntu 20.04或18.0422.04也能用但要注意系统自带的gcc 11对老SDK可能会有兼容性隐患这个我在后面的坑位部分单独说。你需要先安装以下基础工具sudo apt update sudo apt install -y build-essential git wget cmake ssh net-tools sudo apt install -y gcc-aarch64-linux-gnu g-aarch64-linux-gnu sudo apt install -y gdb-multiarchgdb-multiarch是为了后面远程调试用它支持多种目标架构可以连ARM64板子上的gdbserver。另外编译Qt源码还需要额外的系统库不然configure阶段会报一堆错sudo apt install -y libgl1-mesa-dev libfontconfig1-dev libfreetype6-dev sudo apt install -y libts-dev libssl-dev libxcb1-dev libxcb-glx0-dev libx11-dev这里多装几个X11相关的库主要是为了保险虽然我们编译嵌入式Qt时会禁用xcb但configure阶段有些检测仍然需要头文件存在。安装完之后验证工具链aarch64-linux-gnu-gcc -v正常会显示类似gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)的信息。然后写一个最简单的C程序测试#include iostream int main() { std::cout hello rk3568 std::endl; return 0; }交叉编译并检查文件格式aarch64-linux-gnu-g hello.cpp -o hello file hello如果输出是ELF 64-bit LSB executable, ARM aarch64说明工具链工作正常。这一步虽然简单但能帮你确认整个工具链没有装错。2.2 工具链版本一致性最容易踩的暗坑很多RK3568的SDK里会自带一个类似gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu的工具链根文件系统里的libstdc、libc等库都是用它编译的。如果你用Ubuntu apt的gcc 9交叉编译自己的程序理论上多数情况没问题但一旦SDK里的第三方库比如opencv、jsoncpp是用旧工具链编的而你的应用用的是新工具链就可能出现GLIBCXX版本不匹配板子上一跑就报./app: /usr/lib/aarch64-linux-gnu/libstdc.so.6: version GLIBCXX_3.4.29 not found排查方法是到板子上执行strings /usr/lib/aarch64-linux-gnu/libstdc.so.6 | grep GLIBCXX看看最高支持到哪个版本再对你编译出的程序执行readelf -V myapp | grep GLIBCXX两边一对齐就知道能不能跑。这个坑我见过太多人踩所以提醒一句工具链的选择标准不是越新越好而是要和目标板根文件系统匹配一致。3. 编译嵌入式Qt库这一步是整个环境的全局核心3.1 下载Qt源码认识qtbase、qtdeclarative、qtsvg等模块Qt嵌入式环境的本质就是把Qt库源码用aarch64工具链重新编译一遍安装到一个指定目录然后让你的应用链接这个目录下的库。去Qt官网下载qt-everywhere-opensource-src-5.12.10.tar.xz解压后会看到很多qt目录qtbase最核心的库包含QtCore、QtGui、QtWidgets以及最重要的qmake工具。这是必须编译的。qtdeclarativeQML引擎和Qt Quick模块。如果你的界面用QML必须有它。qtsvgSVG图标渲染很多项目会用到。qtcharts、qtdatavis3d图表类模块按需编译。qtwebengine浏览器内核体积巨大嵌入式设备基本用不上最好跳过。建议在configure时通过-skip qtwebengine这样的参数把不需要的大模块排除掉能省去大量编译时间。我一般习惯这样配置./configure \ -prefix /opt/rk3568/qt5.12.10 \ -opensource -confirm-license \ -release \ -xplatform linux-aarch64-gnu-g \ -no-opengl \ -no-xcb \ -no-gtk \ -tslib \ -I /usr/local/tslib/include \ -L /usr/local/tslib/lib \ -nomake tests -nomake examples \ -skip qtwebengine \ -skip qtwayland \ -skip qtscript -skip qtpurchasing这里我暂时没有开启eglfs先保证纯CPU的linuxfb模式能跑起来。等后面要把界面跑得更流畅再回头研究Mali GPU的eglfs适配。3.2 configure参数逐项拆解以及为什么这样设置-prefix /opt/rk3568/qt5.12.10指定Qt库编译后的安装路径。后面应用、qmake、Qt Creator都会到这个目录找库。-xplatform linux-aarch64-gnu-g告诉Qt源码我们是交叉编译目标平台是Linux AArch64。这个参数直接对应qtbase/mkspecs/linux-aarch64-gnu-g这个配置目录。-no-opengl关闭OpenGL模块。因为Mali GPU的EGL/GLES头文件没有准备好之前强行开OpenGL只会让configure检测失败。后面如果做eglfs可以去掉这个参数再重新编译一个版本。-no-xcb明确不编译X11下的xcb插件。嵌入式板子一般不跑X server开着只会引入一堆X11依赖。-tslib编译触摸屏支持。RK3568开发板大多用电阻或电容触摸屏通过tslib来做触点校准。-nomake examples -nomake tests不编译官方示例和测试节省时间。-skip qtwebengine跳过浏览器内核模块。configure成功后的输出结尾会有Qt is now configured for building之类的提示。如果中途报错最常见的是缺少某个系统依赖根据提示用apt补装再重新configure即可不用重复解压。接下来就是真正编译安装建议用多线程make -j$(nproc) sudo make install我实测在8核的Ubuntu虚拟机上只编译qtbase加qtdeclarative大约需要40分钟左右。如果机器配置低耐心等一下。编译完成后查看安装目录/opt/rk3568/qt5.12.10/bin/qmake -v能看到类似QMake version 3.1, Using Qt version 5.12.10就说明Qt库编译成功了。3.3 顺手编译tslib把触摸屏一次搞定如果你的板子没有触摸屏这一步可以跳过。但大多数RK3568评估板都带屏幕和触摸所以我还是建议提前处理好。从GitHub下载tslib源码交叉编译./autogen.sh ./configure --hostaarch64-linux-gnu --prefix/usr/local/tslib make -j$(nproc) sudo make install安装完成后把/usr/local/tslib目录完整拷贝到板子上比如放到板子的/usr/local/tslib。在板子上跑Qt程序前导出触摸屏环境变量export TSLIB_ROOT/usr/local/tslib export TSLIB_TSDEVICE/dev/input/event0 export TSLIB_CONSOLEDEVICEnone export TSLIB_FBDEVICE/dev/fb0 export TSLIB_PLUGINDIR/usr/local/tslib/lib/tsTSLIB_TSDEVICE具体是哪个event设备要看你的触摸屏驱动绑定情况可以用cat /proc/bus/input/devices查看。4. Qt Creator配置把RK3568变成你的远程Qt目标4.1 安装Qt Creator但别用它的桌面版Qt库Qt Creator是一个独立的IDE可以直接通过Ubuntu软件源安装sudo apt install -y qtcreator这里有个经验要强调你不需要在开发机上额外安装桌面版Qt库因为我们已经从源码编译出了ARM版的Qt库。如果图省事在Ubuntu上装了官网的桌面版Qt在配置Kit时一定要小心别选错了qmake路径否则你会惊讶地发现明明选的ARM套件编译出来的却是x86_64的可执行文件。打开Qt Creator后进入Tools - Options按顺序配置编译器Compilers点击Add选择GCCC编译器路径填/usr/bin/aarch64-linux-gnu-gC编译器路径填/usr/bin/aarch64-linux-gnu-gcc名字可以取成“AArch64 GCC”。调试器Debuggers添加/usr/bin/gdb-multiarch名字叫“AArch64 GDB”。这是远程调试的关键。Qt版本Qt Versions点击Add选择/opt/rk3568/qt5.12.10/bin/qmakeQt Creator会自动识别版本号。设备Devices点击Add选择Generic Linux Device填上板子的IP地址、SSH端口默认22、用户名和密码。这里推荐让板子和开发机连同一个路由器IP固定下来不要用自动获取的DHCP地址不然每次调试都要改配置。套件Kits点击Add把编译器选为上面添加的AArch64 GCCQt Version选为编译好的5.12.10Debugger选为gdb-multiarchDevice选为刚才添加的板子。配好之后新建一个Qt Widgets Application项目在构建套件选择界面勾选这个新Kit然后编译。编译完成后在构建目录下找到可执行文件用file看格式如果显示ARM aarch64就说明整套链路已经打通了。4.2 一键部署到板子上的三种方式程序编译出来只是第一步关键是把它跑起来。我常用的部署方式有三种方式一手动SCP上传scp build-myapp/myapp root192.168.1.100:/root/ ssh root192.168.1.100 export LD_LIBRARY_PATH/opt/rk3568/qt5.12.10/lib:$LD_LIBRARY_PATH export QT_QPA_PLATFORMlinuxfb ./myapp这种方式适合排查问题因为你可以在板子上手动控制每一步。方式二Qt Creator自动部署在Qt Creator的项目页面选择Projects - Build - Build Steps添加一个部署步骤用Upload File via SFTP把本地编译出的可执行文件传到板子的指定目录比如/root/myapp。然后设置运行配置在Run页面里可以配置命令行参数和环境变量。这样点一下绿色运行按钮Qt Creator会自动上传并启动程序。方式三NFS挂载如果你的板卡根文件系统支持NFS可以把编译产物目录挂载到板子上。优点是改完代码直接编板子上立即看到新程序缺点是需要额外配置NFS服务端且网络断开会造成程序崩溃。我一般在项目开发期用NFS产品成型后再换成内置存储。4.3 首次运行必看的三大环境问题程序拷到板子上一跑新手最容易遇到下面这几种错误。先说最常见的一个could not find or load the Qt platform plugin linuxfb这个错误意思是Qt没有在预期的目录里找到平台插件。你必须把Qt库的plugins目录也部署到板子上并设置export QT_QPA_PLATFORM_PLUGIN_PATH/opt/rk3568/qt5.12.10/plugins如果你把整个/opt/rk3568/qt5.12.10目录都scp到板子上了那就不会再报这个错。第二个是需要检查动态库能否找到。在板子上执行ldd myapp如果找不到某个libQt5Core.so说明LD_LIBRARY_PATH没有设置对。还有一个隐蔽问题是程序依赖的Qt库没有对应上架构可能你把开发机上x86_64的Qt库拷过去了这种情况程序一启动就会Segment fault。第三是触摸屏问题。如果发现触摸没反应那大概率是tslib环境变量里的TSLIB_TSDEVICE写错了设备节点。可以先通过hexdump /dev/input/event0看触摸时有没有数据输出再回过来核对。5. 远程调试用gdbserver和Qt Creator打断点5.1 板端gdbserver与开发端gdb的配合程序跑起来只是最简单的一环。真到了复杂业务逻辑比如HMI界面通讯协议解析、摄像头采集线程崩溃你不可能靠printf一条条去猜。这时候就必须上远程调试。先在板子上准备gdbserver。如果你的板卡根文件系统是buildroot或yocto构建的一般会在/usr/bin/gdbserver中自带没有的话用板卡自己的包管理器装一个。在板子上启动程序调试模式gdbserver :2345 /root/myapp其中2345是调试端口可以随便选只要不冲突。启动后板子会等待开发机连接。然后在开发机上用命令行gdb连过去测试gdb-multiarch /path/to/myapp (gdb) set sysroot / (gdb) target remote 192.168.1.100:2345 (gdb) continue这里推荐用gdb-multiarch而不是aarch64-linux-gnu-gdb因为Ubuntu源里通常没有预编译好的aarch64专用gdb而multiarch版本通吃。连接成功后你就拥有了完整的断点、单步、查看变量、backtrace能力。注意如果程序已经启动并且执行到了main函数你通过break main后需要输入continue才能真正停在入口。5.2 Qt Creator里的远程调试操作指南在Qt Creator里做远程调试很直观但配置细节不少。首先在Tools - Options - Kits里确保套件的Debugger是之前添加的gdb-multiarchDevice是RK3568板子。然后从菜单栏选择Debug - Start Debugging - Start and Debug Remote Executable会弹出一个对话框Local executable选择开发机上编译出的可执行文件路径。Remote executable板子上的实际运行路径比如/root/myapp。gdbserver port填2345。Working directory如果程序需要读取当前目录下的资源文件这里要填对应的远端工作目录。点击OK后Qt Creator会自动通过SSH把程序上传到板子、启动gdbserver并连接。之后就可以像调试本地程序一样在Qt Creator里打上断点查看调用栈和变量值。这里有个很关键的细节编译时必须带调试信息。Qt Creator默认的Release构建是不带-g的断点会根本不能命中。在.pro文件里加上CONFIG debug QMAKE_CXXFLAGS -g或者在套件的构建配置里选择Debug版本。如果调试时提示源码找不到多半是因为编译机和板子上的源码绝对路径不一致。可以在项目运行配置里的Breakpoints标签下配置路径映射也可以通过把源码放到板端相同路径来解决。5.3 QML页面调试的坑如果你用QML写界面远程调试会比纯C麻烦一点。Qt Creator的QML调试器默认依赖qmlscene或者开启qmljsdebugger参数。交叉编译时qmlscene位于/opt/rk3568/qt5.12.10/bin/qmlscene你同样需要把它拷贝到板子上。在板子上运行时给程序增加参数./myapp -qmljsdebuggerport:3768,block然后在Qt Creator里Debug菜单选择Debug QML Engine填上板子的IP和3768端口。注意QML调试时最好把C调试和QML调试分开进行混在一起容易卡死这是我调了好几个晚上踩出来的经验。5.4 远程调试问题排错速查表下面是我在实际项目里遇到过的问题汇总现象可能原因解决办法Qt Creator连接不上设备SSH服务未启动、网络不通板子执行systemctl start sshd开发机ping板子IPgdbserver启动后连上立刻断开gdb与gdbserver版本不兼容尽量用大版本一致的组合gdb-multiarch对gdbserver 8/9/10均可报Remote g packet reply is too longgdb版本过新和gdbserver过老不匹配使用板卡同年代的gdb或升级gdbserver断点无法命中编译用了Release模式、没有-g改用Debug构建重新编译部署调试时变量值看着不对劲优化导致的乱序用-O0或-Og重新编译程序启动即Segmentation fault缺少动态库或Qt平台插件检查ldd和QT_QPA_PLATFORM_PLUGIN_PATH找不到源码文件源码路径不一致在Qt Creator设置源路径映射这里我特别想提醒一点远程调试前一定要先在板子上直接运行一次程序确认基础环境是好的。很多人一上来直接点调试结果板子上连程序都启动不了你根本分不清是调试配置的问题还是运行环境的问题。先让它裸跑通再挂调试器这个顺序能帮你省掉80%的排查时间。6. 项目里经常还会遇到的三个扩展需求6.1 给Qt Network加上OpenSSL支持如果你的项目要访问HTTPS接口或者用WebSocket那Qt的network模块必须带上SSL支持。交叉编译OpenSSL的步骤是wget https://www.openssl.org/source/openssl-1.1.1g.tar.gz tar xzf openssl-1.1.1g.tar.gz cd openssl-1.1.1g ./Configure linux-aarch64 no-asm --prefix/opt/openssl-aarch64 make -j$(nproc) sudo make install然后在Qt configure时追加参数-openssl-linked \ -I /opt/openssl-aarch64/include \ -L /opt/openssl-aarch64/lib特别注意linux-aarch64这个配置目标不是openssl默认的你需要确认你的openssl版本支持。而且不要用no-asm以外的乱开优化之前我在树莓派交叉编译时就遇到过因为汇编指令集不匹配导致运行崩溃的诡异问题老老实实no-asm最安全。编译好后把/opt/openssl-aarch64/lib下的.so库拷贝到板子上用ldd检查应用是否找得到。这个需求在现在的物联网HMI项目里越来越常见很多设备数据要上报到云端平台没有SSL连不上HTTPS。6.2 中文字体和Qt国际化的处理很多RK3568项目的界面都是中文。你交叉编译时如果发现板子上界面显示中文全是方块那就是缺少中文字体文件。解救方法是找一个开源中文字体比如思源黑体、文泉驿微米黑。把.ttf或.ttc文件拷贝到板子比如放到/opt/fonts。运行程序前设置export QT_QPA_FONTDIR/opt/fonts如果项目要做多语言Qt的国际化流程是源码里用tr()包字符串开发机上运行lupdate生成.ts翻译文件翻译完成后运行lrelease生成.qm文件最后在程序里用QTranslator加载。这个流程在交叉编译环境里和桌面Qt完全一致唯一要注意的是.qm文件别漏部署到板子否则界面上一句英文都不会翻译。6.3 摄像头采集和显示输出的配合RK3568常被用在带摄像头、带屏幕的AIoT设备上比如有人会调试OV5695摄像头sensor也有人纠结BT1120输出。这类项目的通用分工是摄像头采集走V4L2驱动在Qt应用里开一个独立线程读帧转成QImage再通过QWidget或QML显示BT1120这类输出的信号通常是接到显示芯片或采集芯片不属于Qt直接管的范畴Qt只管最终的人机界面。这里想强调的教训是把摄像头采集、编解码这些耗时操作放到GUI线程会卡界面成幻灯片这是新手最容易犯的错。建议用std::thread或QThread做采集通过signal/slot把新帧传给主线程刷新显示并且控制刷新频率不要每秒推送所有帧给UI留条活路。7. 几条让我少走弯路的实际操作习惯最后分享几个我踩过无数坑之后沉淀下来的操作习惯不一定写在某个文档里但对项目推进速度影响很大。第一把所有工具链和库的路径统一放到一个环境脚本里。比如创建一个setenv.shexport RK_TOOLCHAIN/usr/bin/aarch64-linux-gnu- export QT_INSTALL_DIR/opt/rk3568/qt5.12.10 export OPENSSL_INSTALL_DIR/opt/openssl-aarch64 export PATH$QT_INSTALL_DIR/bin:$PATH以后每次打开终端先source一下避免每次敲一长串命令。第二先跑通最简单的Qt程序再上大项目。很多人一上来就把公司那套一堆模块的大工程塞进交叉编译环境结果编译报错几十个不知道是工具链问题还是模块依赖问题。我建议新建一个空窗口的main.cpp先确认linuxfb能出画面Qt Creator的Kit流程是通的然后逐步往工程里加模块。这个过程虽然慢一点但每一步都稳。第三保存好每一次.configure命令。Qt的configure参数非常多你可能会在不开GPU和开GPU、加openssl和不加openssl之间反复横跳。强烈建议把不同配置写成shell脚本统一命名比如build-qt-linuxfb.sh、build-qt-eglfs-openssl.sh哪天想换方案直接执行脚本就行不用凭记忆重新拼命令。第四重要的一点也是最容易被项目工期挤压的一点环境搭建好后立刻做一次全套验证把编译、部署、断点调试整个流程跑通再Commit一个README记录步骤。不然半年后你或者同事重新搭环境又要从头填坑。我在实际调试中还有一个习惯每次新板子到手先在命令行手动完成一遍下载、部署、运行、调试的流程确认整条链路都是通的再接入Qt Creator的可视化操作。否则你根本搞不清楚到底是Qt Creator设置问题还是板子网络问题抑或是权限问题。等命令行流程完全跑通Qt Creator的图形化配置只需要照着填一遍就好基本一次成功。这篇文章写的这套环境我自己在多个不同品牌的RK3568板子上都搭过路径和参数细节大同小异核心思路完全一致。希望它能帮你在调试路上少走几段弯路把更多时间留给真正的业务逻辑开发。
返回列表