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

资讯详情

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

麒麟v10 ARM64交叉编译Qt 5.12.10实战(联想定制版)

麒麟v10 ARM64交叉编译Qt 5.12.10实战(联想定制版) 简介面向麒麟桌面系统 V10ARM64 架构及联想昭阳 N4720Z 设备这份由作者编译完成的 Qt 5.12.10 开发包为需要在麒麟 Linux ARM64 环境中搭建原生 Qt 开发环境的开发者提供了可直接集成的解决方案。整个压缩包包含两千个头文件覆盖区域、OpenGL 扩展、URL 解析等常用 Qt 模块体积约八十五兆字节以点 h 头文件为主目录结构清晰便于统一放置到根目录下的 opt 文件夹中使用免去自行交叉编译和源码构建的耗时流程。与 Qt Creator 构建套件无缝衔接可快速配置并识别 Qt 5.12.10 版本适合进行麒麟系统相关的 Qt 应用开发、跨平台适配与功能验证尤其适合需要快速搭建开发环境的团队或个人。发布者已在所标注型号上亲测可用其他硬件设备可参考此包自行验证。截至目前已有一千零六十五人学习或下载足见其在 ARM64 Linux 平台 Qt 环境搭建方面具有较好的参考与实践价值。1. 为什么要在麒麟v10 ARM64上自己编译QT先说痛点先说说我为什么折腾这件事。拿到一台预装Kylin-Desktop-V10-GFB-Release-020-ARM64的联想设备时系统自带的应用商店里能装到的Qt版本往往偏旧或者压根没有合适的ARM64版本。而CTK、医学影像、工控上位机这类项目一旦依赖了某些较新模块或者需要固定QT版本保证二进制兼容直接用系统仓库的包很不现实。最典型的例子就是很多医院PACS项目用的是QT 5.12.x配合特定补丁你换一个5.15或者6.x接口变了整个工程就得动刀。另外一个很现实的问题是联想定制这个后缀。品牌机在主板、显卡、电源管理上往往有自家驱动和固件系统镜像里也会预装一些定制库。如果你只是照着官方Generic版本交叉编译在联想实体机上可能会出现显示异常、OpenGL渲染花屏、快捷键失效这类奇怪现象。这就是为什么标题里专门写了Lenovo版本——不是噱头是为了和机型的固件特性对齐。这里要提前说清楚文章里所有步骤都基于一个假设你的机器已经是Kylin-Desktop-V10-GFB-Release-020-ARM64的成品系统内核和固件正常能够跑GPU加速。如果你拿到的是一台纯开发板或者没有显示器的最小系统那还多一步显示服务的部署不在本文范围内。2. 编译前的准备工具链、sysroot与目标平台确认2.1 主机与目标机的角色划分这里用的是标准的交叉编译模式一台x86_64的Ubuntu或者Kylin桌面作为编译主机目标机是ARM64架构的麒麟系统。跨架构编译的原因很简单目标机的CPU算力有限编译QT这种体量的工程动辄两三小时甚至更久而x86主机通常二十分钟到一个小时就能完成。而且如果你手头有多台ARM64设备编译一次分发多台效率也高。编译主机我建议至少16GB内存、4核以上磁盘剩余空间不低于20GB。QT源码解压后大概1.5GB编译中间产物会有10GB以上。别用机械硬盘编译否则光是IO等待就能让人崩溃。2.2 交叉编译工具链的安装在编译主机上先装好ARM64交叉工具链。以Ubuntu/Kylin这类Debian系系统为例sudo apt update sudo apt install gcc-aarch64-linux-gnu g-aarch64-linux-gnu有些场景还需要ARM64版本的libc开发包通常是libc6-dev-arm64-cross这个包通常随gcc-aarch64一起装好。验证一下工具链是否正常aarch64-linux-gnu-gcc --version如果能看到版本号工具链就算就绪了。另一个必须的工具是pkg-config并且要让它的交叉编译模式生效后续配置QT的模块依赖时会用到。建议安装pkg-config-aarch64-linux-gnu没有这个包的话需要手动设置PKG_CONFIG_PATH指到sysroot的usr/lib/aarch64-linux-gnu/pkgconfig目录。2.3 sysroot准备这一步决定能不能跑起来交叉编译需要目标机的根文件系统作为依赖参考也就是sysroot。两种方式第一种直接把目标机的根目录打成包拷贝过来。比如在目标机上执行sudo rsync -avx / /home/user/sysroot/然后在编译主机上把sysroot路径设好同时用qemu-aarch64-static配合chroot测试。这种方式缓存最准确但sysroot里会夹杂大量运行时文件体积大而且处理不当容易带回来一些运行时状态导致编译混乱。第二种方式用debootstrap拉取ARM64仓库生成干净的根文件系统sudo debootstrap --archarm64 buster /opt/sysroot-arm64 http://mirrors.ustc.edu.cn/debian/这种方式得到的sysroot干净但需要注意版本镜像里包的版本跟目标系统的libc版本如果差得太大编译出来的QT拷贝到目标机后可能因为GLIBC版本不兼容直接报错。我个人的经验是如果你是给固定一批同型号设备做适配直接用第一种方式从一台已经装好的同款联想机器上打包sysroot。这样目标机的环境和你编译环境完全对齐编译产物拷过去直接能跑少很多我明明编译成功了为什么跑不起来的幺蛾子。2.4 确认目标平台的依赖库在开始configure之前先站在目标机的角度想清楚QT 5.12.10需要哪些依赖libxcb系列xcb-util、xcb-image、xcb-keysyms、xcb-render-util、xcb-shm、xcb-xinerama、xcb-xkb等OpenGL开发库libgl1-mesa-dev、libegl1-mesa-dev等字体和渲染库fontconfig、freetype、harfbuzzDBus、icu等基础库你可以在目标机上用apt search确认这些库是否已经安装。如果缺用apt install装上对应的-dev包。交叉编译时对应的dev包要在sysroot里也存在。这里有一个比较容易忽略的点libxkbcommon-dev和libxcb-xkb-dev这两个包经常漏装漏了之后QT的xcb插件编不完整最后表现出来就是程序能编译但一运行就报could not load platform plugin xcb。3. configure配置阶段几个关键参数的取舍逻辑3.1 源码获取与解压QT源码我习惯从官方仓库或者清华、中科大镜像下载。版本必须是5.12.10不要用5.12.10之上打其他补丁的版本除非你有把握。因为QT每个补丁版之间平台集成的代码有变动小版本升级可能导致其他模块ABI不匹配。wget https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/5.12/5.12.10/single/qt-everywhere-src-5.12.10.tar.xz tar xf qt-everywhere-src-5.12.10.tar.xz cd qt-everywhere-src-5.12.103.2 configure命令的实践写法这是整个流程里最核心的地方。我直接给出一个经过大量验证、适用于Kylin V10 ARM64和联想平台的配置./configure \ -prefix /opt/Qt5.12.10-arm64 \ -xplatform linux-aarch64-gnu-g \ -opensource -confirm-license \ -release \ -shared \ -nomake examples -nomake tests \ -no-compile-examples \ -qt-libpng -qt-libjpeg \ -fontconfig \ -system-freetype \ -dbus-linked \ -no-opengl \ -skip qtwebengine -skip qtwebview \ -no-feature-vulkan \ -no-use-gold-linker \ -reduce-relocations有几个参数需要单独解释一下因为选错的代价很大。先看-no-opengl。很多人不理解麒麟系统上明明有Mesa的OpenGL库为什么关掉我实测下来在联想部分ARM64机型上QT自带的OpenGL检测会在运行时和设备的Mali GPU驱动产生冲突尤其在混合架构的桌面环境下经常出现渲染线程崩溃。如果你的应用不强依赖QOpenGLWidget关掉反而更稳。如果你坚决要OpenGL那建议单独做一个带OpenGL的构建版本不要和通用版本混在一起分发。再看-qt-libpng -qt-libjpeg。QT自己的png和jpeg在交叉编译时稳定性更高因为系统的libpng版本如果跟sysroot不一致会导致图像插件加载失败。用自带的这两个库可以少排查很多问题。然后是-reduce-relocations。这个参数在ARM架构上特别有好处能减少运行时符号重定位的开销对加载速度有一定提升。但是这个参数跟-no-pch有兼容问题如果后续开启Precompiled Header反而会让构建变慢我这里特意没有加-no-pch也没加-pch保持默认。3.3 关于-qmake参数的补充如果你需要把qmake导出来单独使用比如后续用qmake构建其他工程可以在configure之后再执行make -C qmake sudo make -C qmake install某些自动化脚本会直接用qtbase/bin/qmake所以确认qmake在最终安装目录里存在并且是链接到正确arm64版本别被同名的x86 qmake干扰。3.4 为什么要去掉qtwebengine先说结论建议去掉。QT WebEngine在ARM64上编译不仅耗时极长而且依赖Ninja和大量GN构建脚本。更关键的是麒麟v10的系统仓库里一些库的版本和QT WebEngine要求的版本不一致编译到一半极容易因为libnss3-dev版本太老而失败。如果你的业务确实需要网页渲染建议直接用系统自带的浏览器内核或者简单接CEF不建议在QT 5.12.10里面强行集成WebEngine性价比太低。4. 实际构建过程从make到make install的实施细节4.1 多线程编译与资源限制configure通过后执行编译make -j$(nproc)如果你的编译主机是8核16线程-j8是个合理值。有人图快直接-j16结果内存暴涨编译中途OOM把整个环境搞死。编译过程中你会看到大量颜色输出和进度滚动这部分没有什么太多要点。但我建议每隔一段时间留意一下是否有error:字样因为有些错误不是立刻终止的尤其是和头文件缺失相关的错误会以警告形式刷过去最终链接的时候才暴露。如果某一个模块编译失败不要急着把整个构建清理掉重来Qt的构建系统对已完成的模块是有缓存的。找到失败模块的目录单独进入该模块重新makecd qtbase make clean make然后再回到根目录继续make这样可以节省大量时间。4.2 安装与目录结构确认编译完成后安装sudo make install默认prefix是/opt/Qt5.12.10-arm64。安装完成后检查几个关键路径ls /opt/Qt5.12.10-arm64/bin/qmake /opt/Qt5.12.10-arm64/bin/qmake -v此时看到Using Qt version 5.12.10就说明基本成功了。另外检查/opt/Qt5.12.10-arm64/plugins/platforms/目录下是否有libqxcb.so这个文件是xcb插件能否加载的关键。如果编译过程中xcb相关的依赖库配置有问题这个库可能根本不会生成。4.3 编译出一个最小验证程序在目标机上新建一个测试工程mkdir ~/qttest cd ~/qttest cat main.cpp EOF #include QApplication #include QMessageBox int main(int argc, char *argv[]) { QApplication app(argc, argv); QMessageBox::information(nullptr, Test, Qt 5.12.10 works on Kylin ARM64); return app.exec(); } EOF /opt/Qt5.12.10-arm64/bin/qmake -project /opt/Qt5.12.10-arm64/bin/qmake make ./qttest如果弹窗正常显示说明xcb插件、字体库、窗口系统和平台集成已经正常。如果弹窗没弹出来最可能是xcb插件加载失败。5. 联想定制模块的集成思路5.1 机上固件和驱动的特殊处理联想的部分ARM64机型比如基于飞腾或者麒麟芯片的台式机在固件里有特殊的显示输出机制比如某些机型通过LSPCON芯片做HDMI转换或者有双显卡切换逻辑。QT本身不直接和这些硬件打交道但它在启动时要通过xcb连接X Server而X Server的显示驱动是由系统侧决定的。如果你在实体机上运行QT程序一切正常但在联想某些型号上出现窗口模糊、分辨率不对或者无法全屏那大概率是显示服务器的分数缩放配置问题。此时可以在系统设置中把显示缩放调整为100%再测试或者设置环境变量export QT_AUTO_SCREEN_SCALE_FACTOR0 export QT_SCALE_FACTOR1这会强制QT不自动缩放使用原始像素尺寸很多兼容性问题会迎刃而解。5.2 键盘布局和特殊功能键联想机型的键盘上通常有Fn锁定、一键恢复、计算器快捷键等功能键。QT程序如果处理特殊按键需要确认系统的XKB配置是否正常。在QT应用里可以通过重写keyPressEvent获取键值。如果你发现某些F功能键没有反应先检查X服务器层面用xev工具看按键事件是否到达应用层。通常这是XKB映射问题和QT本身无关。5.3 针对联想的低功耗模式优化如果你开发的是仪表盘、工控屏这类需要长期待机的程序建议在QT中主动适配系统的电源管理DBus接口。麒麟v10基于较新的Linux内核联想的BIOS和固件会暴露一定的电源状态。QT应用可以通过DBus调用系统接口在系统进入省电模式时暂停定时器或者降低刷新率。这一部分和QT编译关系不大但在Lenovo版本这个命名里我觉得有义务提醒真正做到模板化还需要跑通系统的org.freedesktop.UPower或者org.kde.Solid.PowerManagement接口确认AC/Battery切换时应用不会崩。6. 常见问题与排查经验6.1 could not load platform plugin xcb一类错误这个错误在ARM64交叉编译里太常见了。排查顺序确认libqxcb.so存在于安装目录的plugins/platforms/下确认sysroot里的xcb相关库版本和编译时的头文件版本一致在目标机上用ldd查看QT库依赖是否满足ldd /opt/Qt5.12.10-arm64/plugins/platforms/libqxcb.so如果有依赖库显示not found说明目标系统缺少对应的运行时库直接apt install缺失的库即可。6.2 configure时对libGL的检测卡住如果你决定打开OpenGLconfigure过程中可能会检测libGL.so在交叉编译时检测脚本偶尔会误判。此时需要在configure之前设置export PKG_CONFIG_PATH/opt/sysroot-arm64/usr/lib/aarch64-linux-gnu/pkgconfig/ export PKG_CONFIG_SYSROOT_DIR/opt/sysroot-arm64确保pkg-config能找到正确的arm64库而不是编译主机x86的库。6.3 中文显示乱码与FontConfig问题在麒麟桌面上QT程序中文显示异常多数是因为系统没有安装中文字体。Kylin V10默认带了中文字体但你的sysroot里如果不包含字体文件编译出的QT就不知道系统有哪些可用字体。解决方法是拷贝中文字体到目标机的/usr/share/fonts/目录并执行fc-cache -f刷新字体缓存不需要重新编译QT。6.4 交叉编译中遇到的CMake工程问题如果你后面用CMake来构建QT工程请记住QT 5.12.10的CMake支持并不完美。建议使用CMake 3.5到3.14之间的版本太新的CMake反而会产生一些兼容警告。用CMake时指定交叉toolchain文件的写法很多时候不是CMake本身的问题而是依赖库路径不对。最好先在qmake里验证成功后再转CMake。6.5 make install后无法启动due to架构错误如果你尝试在x86主机上运行编译出来的arm64 qmake一定会提示Exec format error或cannot execute binary file。这不是编译问题是你在x86侧执行了ARM64的二进制。要么把安装目录拷贝到ARM64目标机上要么使用qemu-aarch64来模拟运行。很多时候这个低级错误会让人误以为编译失败白白浪费调试时间。7. 后续还能怎么扩展编译好QT 5.12.10的Lenovo版本之后推荐再补做几件事把这次编译的成果固化下来。第一是做一个安装脚本内容就是解压安装目录、配置环境变量QTDIR、PATH、LD_LIBRARY_PATH并创建QtCreator的Kit配置。这样以后任何一台同型号的新机器一条命令就能部署。第二是编写一套简单的自检测试程序集覆盖基础控件、网络请求、数据库连接、多线程这些常用场景部署后跑一遍确保目标机的运行环境和编译环境没有隐性差异。第三是打一个干净的系统镜像备份把QT安装好之后的系统状态存成镜像。以后不管是批量部署还是故障恢复直接用镜像烧录即可省去每台机器重新配置的麻烦。我在实际项目里一般还会做一个对应x86_64版本的QT编译产物保持两个平台的接口和版本完全一致这样开发调试都在x86上位机进行最后统一发布ARM64的产物。这个习惯能省掉很多为什么x86没问题ARM就有问题的排查时间。几个版本适配下来我最大的体会是交叉编译本身不可怕真正耗时的是编译完之后的集成调试尤其是平台插件的加载和依赖库的版本对齐。只要这一步做好了QT在麒麟ARM64上完全可以跑得非常稳定。本文还有配套的精品资源点击获取
返回列表