ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ARM架构UOS上从源码编译Qt 5.15.2与定制Qt Creator全攻略

ARM架构UOS上从源码编译Qt 5.15.2与定制Qt Creator全攻略 在飞腾FT-2000/4或者鲲鹏920这类ARM架构处理器上跑统信UOS日常办公倒还好一旦涉及Qt开发麻烦就来了。系统源里的Qt版本偏老不说很多模块拆得七零八落想直接用网上现成的预编译包到了ARM这里基本全部失效即使费劲装上一套能跑的Qt环境Qt Creator还会因为同时存在不同版本的库而时不时给你一个“cannot mix incompatible qt library (5.15.3) with this library (5.15.2)”的下马威。我前前后后折腾了几天从源码编译Qt 5.15.2到定制一套匹配的Qt Creator总算把问题彻底解决。这篇文章就是完整流程的记录适合需要在ARM架构UOS上做Qt开发的团队和个人参考也欢迎已经踩过坑的朋友对照验证。1. 为什么非得从源码编译UOS自带Qt的版本之痛与ARM适配现实1.1 系统自带的Qt版本到底差在哪统信UOS的软件源里其实有Qt相关的包qtbase5-dev、libqt5gui5这些装一下好像就能用但实际开发时会发现不太对劲。UOS桌面环境大量组件是基于Qt写的系统会锁定一套Qt版本以保持稳定比如某些版本UOS默认带的是Qt 5.11或者5.14而不是我们想要的5.15系列。很多第三方库、控件库早就切到了Qt 5.15的接口用系统自带的Qt编译经常报一堆“未定义的引用”或者“member access into incomplete type”之类的错误。更麻烦的是模块不完整。UOS源里虽然提供了核心的widgets、gui、network等模块但QML相关模块经常缺胳膊少腿。Qt5QmlModels、Qt5QuickControls2、Qt5Qml这些包要么版本对不上要么干脆没有。热词里有一条“uos找不到qt5qmlmodels”说的就是这种情况。系统仓库的包为了满足桌面整机依赖会把一些模块拆散开发时你需要的某个模块可能根本不在仓库里就算用apt search搜到了版本也未必是5.15.x。此外还有一个隐性风险系统升级。UOS的软件更新会不定期把Qt补丁版本往上抬比如把libqt5core5a升级到5.15.3。这时候你项目里的二进制可能还是链接5.15.2的运行就蹦出那个经典的库版本冲突提示。自己从源码编译一套带固定前缀的Qt至少能把这层不确定性解除。1.2 ARM架构额外增加的门槛在x86_64平台上实在不想编译还可以去找现成的Qt离线包或者用aqtinstall拉取预编译二进制。但到了ARM架构上这条路基本堵死。Qt官方预编译的Linux桌面版只提供x86_64ARM Linux的预编译包主要面向嵌入式设备和UOS这种桌面环境的glibc版本、图形栈对不上。也就是说想在飞腾、鲲鹏、麒麟990或者Apple Silicon虚拟机上做UOS Qt开发源码编译几乎是唯一现实的选择。交叉编译也是个选项但要准备sysroot、交叉工具链、目标机的依赖库还容易遇到编译出来的程序在目标机上缺libstdc版本的问题。我的建议是除非你有一批完全相同的设备需要批量编译否则直接在目标机上编译更省心。ARM设备编译大型项目确实比x86慢但在飞腾四核平台上Qt 5.15.2全量编下来两小时左右是可以接受的时间成本。你省下来的是交叉编译环境反复排错的痛苦。1.3 源码编译换来的是可控性自己编译的收益不只是版本正确更重要的是可控。你可以通过-prefix指定安装目录为/opt/Qt5.15.2和系统Qt完全隔离互不干扰可以通过-skip裁掉用不到的模块比如WebEngine这种在ARM上编译成本极高的模块还可以按需单独补编某些子模块比如MySQL驱动、QML库。这套玩法一旦跑通后续做版本升级、模块增删、跨机器分发都非常方便。代价是第一次编译前需要把依赖环境准备干净configure参数也要选对。下面这部分就是我反复试错之后沉淀下来的“地基工程”。2. 编译前的地基依赖安装、configure选参、磁盘与内存规划2.1 先把依赖装全否则configure会卡在莫名其妙的地方UOS基于Debian体系安装依赖用apt就行。我的建议是先执行一次sudo apt update然后安装下面这组包sudo apt install -y build-essential gcc g make perl python3 \ libgl1-mesa-dev libegl1-mesa-dev \ libx11-dev libx11-xcb-dev libxcb1-dev libxcb-util-dev \ libxcb-xinerama0-dev libxcb-xkb-dev libxcb-icccm4-dev \ libxcb-image0-dev libxcb-keysyms1-dev libxcb-render-util0-dev \ libxcb-shape0-dev libxcb-xfixes0-dev libxcb-randr0-dev \ libxcb-glx0-dev libxkbcommon-dev libxkbcommon-x11-dev \ libfontconfig1-dev libfreetype6-dev \ libsqlite3-dev libmysqlclient-dev libglib2.0-dev不同版本UOS的包名可能有一点点差异如果某个包找不到用apt search libxcb搜一下再调整。这里面xcb系列是重中之重。Qt 5在Linux桌面上默认的窗-口系统插件就是xcb编译时会检测libxcb的各个开发包是否齐全缺了任何一个configure阶段就会报“Feature xcb was enabled, but the pre-condition failed”之类的错误或者编译出来运行时报”could not load the Qt platform plugin xcb”。网上很多ARM UOS编译Qt的求助帖最后问题都出在这一堆xcb依赖没装干净。另外如果你的设备有独立GPU或者Mesa软件渲染libgl1-mesa-dev就够用如果还需要EGL相关功能再加libegl1-mesa-dev。ARM设备上的GPU驱动往往不太完善很多飞腾机器就是靠Mesa的llvmpipe做软件渲染所以OpenGL的头文件一定得备齐。2.2 configure参数少即是多别全书库很多人第一次编译Qt习惯全默认结果编译时间翻倍还编译出一堆用不上的模块。我在ARM UOS上用的configure命令是这样的mkdir /opt/source cd /opt/source tar xf qt-everywhere-opensource-src-5.15.2.tar.xz mkdir qt-build cd qt-build ../qt-everywhere-opensource-src-5.15.2/configure \ -prefix /opt/Qt5.15.2 \ -opensource \ -confirm-license \ -release \ -xcb \ -qt-libpng -qt-libjpeg -qt-zlib \ -skip qtwebengine \ -skip qtwebview \ -skip qtcharts \ -skip qtdatavis3d \ -nomake examples \ -nomake tests \ -sql-mysql \ -opengl desktop这里我解释几个关键取舍-prefix /opt/Qt5.15.2指定安装位置后面所有环境变量、快捷方式都以这个路径为锚点。-release只编发布版不编debug库。ARM上编译慢能省一半时间。-xcb明确启用xcb平台插件。-qt-libpng -qt-libjpeg -qt-zlib用Qt自带的图片和压缩库源码避免和系统版本冲突。-skip qtwebengineWebEngine在ARM上是出了名的难编依赖大量Chromium组件不是做浏览器内核项目的话不要碰。-nomake examples -nomake tests不编译示例和测试省时间也省空间。-sql-mysql顺手把MySQL驱动编译开关打开后面链接MySQL数据库会用到。-opengl desktop使用桌面OpenGL即使没有独显Mesa也能用软件方式提供OpenGL支持Qt Quick面板也能跑起来。如果你只是做纯Widgets项目连QML都不需要可以再补一个-skip qtdeclarative但我建议保留因为很多项目哪怕主界面用Widgets也难免会嵌入一些QML页面。qtdeclarative是QML的核心模块保留它后续会少很多麻烦。2.3 磁盘、内存和编译策略编译Qt是个吃资源的过程。/opt分区建议预留25GB到30GB的可用空间其中build目录占大部分安装目录大概5GB左右。内存8GB以上比较舒服编译时可以并行make -j4如果内存小于4GB老老实实用make -j2否则编译中期的C链接阶段很容易触发OOM被系统杀掉前功尽弃。ARM板子普遍散热一般长时间满载编译芯片温度会拉高所以编译期间建议把设备放在通风好的地方有条件可以垫个散热底座。3. 三大核心命令跑通编译configure、make、make install的执行细节3.1 下载源码包和解压Qt 5.15.2的源码包可以在Qt官方归档地址获取文件名是qt-everywhere-opensource-src-5.15.2.tar.xz。下载后校验一下SHA256再解压防止下载损坏导致后面编译出莫名奇妙的错误。cd /opt/source wget https://download.qt.io/official_releases/qt/5.15/5.15.2/single/qt-everywhere-opensource-src-5.15.2.tar.xz sha256sum qt-everywhere-opensource-src-5.15.2.tar.xz tar xf qt-everywhere-opensource-src-5.15.2.tar.xz一定要在源码目录外面单独创建build目录不要直接在解压出来的源码目录里configure。原因是Qt的构建系统支持out-of-source编译在独立目录里build将来想重新配置或者单独补编某个子模块原来的源码目录还是干净的如果混在源码目录里build哪天想换个prefix或者增减模块清理起来非常痛苦。3.2 configure通过的标准Qt is now configured for building在build目录里执行configure命令后屏幕会滚动大量检查信息。中途如果缺少依赖会直接出现ERROR: Feature xxx was enabled, but the pre-condition ... failed这类提示然后停止。正常走到最后输出会有类似下面这段Qt is now configured for building Super module may require additional make steps看到这行基本说明核心检查通过。这时候不要急着make先看一眼生成的config.summary确认Xcb、OpenGL、SQL这些特性是否都是yes。如果某项是no回到第2节补依赖后重新执行configure。3.3 make和make install接下来就是等待时间。make -j4首次编译过程中会有大量warning比如“deprecated declaration”“unused parameter”这些都是正常现象不用管。如果中途因为断电、OOM之类中断了重新执行make -j4构建系统会从断点继续不会从头开始。这点比很多人的预期要友好。make结束之后执行sudo make install安装完成后检查/opt/Qt5.15.2/bin/qmake -v如果输出QMake version 3.1 ... Using Qt version 5.15.2 in /opt/Qt5.15.2/lib说明核心Qt已经装好了。3.4 环境变量不是导个PATH就完事很多资料只让你export PATH/opt/Qt5.15.2/bin:$PATH这在命令行里敲qmake确实能找到但运行编译出来的程序时动态库搜索路径不对还是会跑到系统Qt那边去。我建议把下面这段写到一个脚本文件里比如~/qt5152.envexport QTDIR/opt/Qt5.15.2 export PATH$QTDIR/bin:$PATH export LD_LIBRARY_PATH$QTDIR/lib:$LD_LIBRARY_PATH export QT_PLUGIN_PATH$QTDIR/plugins export PKG_CONFIG_PATH$QTDIR/lib/pkgconfig:$PKG_CONFIG_PATH用的时候source ~/qt5152.env即可。注意LD_LIBRARY_PATH里面千万别再放其他任何Qt版本的路径这是后面“库版本冲突”问题的最主要来源。4. 定制Qt Creator让IDE与自编译Qt正确对接的关键步骤4.1 为什么IDE也要自己编译一把这是个容易忽略的坑。UOS自带的Qt Creator通常是系统软件包它本身链接的是系统Qt库。即使你在IDE里添加了/opt/Qt5.15.2/bin/qmake作为新的Qt VersionIDE自身的进程加载的仍然是系统库。当项目在Qt Creator里构建、调试时IDE进程和项目进程的Qt库版本不一致轻则调试器断点错位重则弹那个让人抓狂的cannot mix incompatible qt library错误。既然我们已经源码编译了Qt 5.15.2不如把配套的Qt Creator也一起编译了。Qt官方在5.15时代对应的Qt Creator版本是4.15.x系列4.15.2和Qt 5.15.2基本同期发布兼容性最好。4.2 下载Qt Creator源码并准备编译Qt Creator源码下载地址在Qt官方归档目录下文件名为qt-creator-opensource-src-4.15.2.tar.xz。解压后需要确认两个工具cmake的版本要在3.16以上否则Qt Creator 4.15的CMakeLists无法解析。UOS自带的cmake大概率是3.13甚至更低需要先升级。如果你的系统cmake版本不够可以从cmake官网下载源码编译或者用pip install cmake装一个。在ARM UOS上pip install cmake有时没有对应架构的wheel会直接尝试从源码构建cmake耗时也不短。我这边是直接用UOS的官方Python pip装成功的具体看你的源。总之先跑一下cmake --version不满足就处理这一步做在前面别等到编译Qt Creator到一半才发现。依赖方面Qt Creator还需要libclang做代码模型。这个依赖可选如果你不需要C/C的智能补全、代码高亮分析可以在CMake配置时关掉把-DCMAKE_DISABLE_FIND_PACKAGE_ClangON传进去。我建议ARM设备上先关掉因为libclang的版本匹配问题也是一堆坑先把IDE跑起来最重要。4.3 编译Qt Creator的完整命令cd /opt/source tar xf qt-creator-opensource-src-4.15.2.tar.xz mkdir qt-creator-build cd qt-creator-build cmake ../qt-creator-opensource-src-4.15.2 \ -DCMAKE_PREFIX_PATH/opt/Qt5.15.2 \ -DCMAKE_BUILD_TYPERelease \ -DCMAKE_DISABLE_FIND_PACKAGE_ClangON make -j4这里CMAKE_PREFIX_PATH必须指向我们刚才编译安装的Qt 5.15.2cmake才能找到对应的Qt5库。编译完成后./bin/qtcreator就能启动。建议直接make install装到/opt/QtCreator-4.15.2方便后续在桌面环境添加快捷方式sudo make install4.4 在Qt Creator里配置Kit别用默认值启动Qt Creator后依次进入Tools - Options - Kits在Qt Versions页面点击Add选择/opt/Qt5.15.2/bin/qmakeQt Creator会自动识别出Qt 5.15.2。在Compilers页面确保gcc/g都能被识别。UOS上一般是gcc和g架构为aarch64。在Kits页面新增一个Kit把Qt Version选成刚添加的Qt 5.15.2编译器选gcc/g给Kit起个名字比如UOS-ARM-Qt5.15.2。新建项目时在Kit选择页一定要选这个新Kit不要选系统默认的“Desktop”Kit。很多人在这一步偷懒结果项目构建时用的还是系统Qt又回到老问题上。4.5 桌面快捷方式与启动脚本编译安装好的Qt Creator在/opt/QtCreator-4.15.2/bin/qtcreator。直接双击这个路径它启动时不会自动加载环境变量可能找不到Qt库。我习惯写一个启动脚本~/qtcreator-5152.sh#!/bin/bash source ~/qt5152.env exec /opt/QtCreator-4.15.2/bin/qtcreator $赋予执行权限后桌面创建一个.desktop文件指向这个脚本即可。注意不要顺手把系统原有的Qt Creator快捷方式覆盖掉保留一份原版万一后面做对比测试还用得上。5. 高频坑位逐一排查库版本冲突、QmlModels缺失和MySQL驱动5.1 cannot mix incompatible qt library版本冲突的排查链路这个报错信息几乎每个从源码编译Qt的人都见过。完整提示是cannot mix incompatible qt library (5.15.3) with this library (5.15.2)意思是当前进程加载了两个不同大版本的Qt库而Qt库内部用了一个全局标识来防止混用一旦发现版本不一致直接abort。这个问题的出现场景大致有两类。第一类是系统环境变量导致。比如你之前为了方便在/etc/profile或~/.bashrc里全局导出了LD_LIBRARY_PATH/opt/Qt5.15.2/lib:$LD_LIBRARY_PATH那么所有图形程序启动时都会优先加载Qt 5.15.2的库。但UOS桌面本身的一些组件是链接系统Qt 5.15.3的强制加载5.15.2之后就会出现版本冲突。解决方式就是我前面说的不要全局导出只在终端或者特定启动脚本里source。第二类是程序构建时用的qmake路径不对。比如你编译项目时用的是/usr/bin/qmake但运行环境里LD_LIBRARY_PATH又指向/opt/Qt5.15.2/lib导致运行时的库来自5.15.2编译时链接的却是系统Qt。排查链路是这样的# 1. 看程序实际链接了哪个QtCore ldd /path/to/your/binary | grep QtCore # 2. 看当前环境变量里有多少Qt路径 echo $LD_LIBRARY_PATH # 3. 看qmake到底指向谁 which qmake正确做法是确保编译项目前先source ~/qt5152.env让qmake、pkg-config都指向自编译Qt运行时环境变量保持一致。如果项目已经在Qt Creator里要检查Kit里的Qt Version是否选对并保存后重新构建。5.2 找不到Qt5QmlModels单独补编qtdeclarative模块热词里那条“uos找不到qt5qmlmodels”在实际开发中也特别常见。现象包括编译项目时报错找不到Qt5QmlModels头文件或者运行QML程序时提示无法加载QtQml.Models模块。原因是首次configure时即使保留了qtdeclarative模块也可能因为某些子项依赖缺失构建过程把它跳过了。还有情况是构建系统版本和编译器对不上导致libQt5QmlModels.so没有生成。排查方式find /opt/Qt5.15.2/lib -name *Qml*正常能看到libQt5Qml.so.5、libQt5QmlModels.so.5这些文件如果只有libQt5Qml.so没有libQt5QmlModels.so需要补编qtdeclarative模块。补编不需要重新跑整个Qt构建。进入源码目录里的qtdeclarative子模块单独构建cd /opt/source/qt-everywhere-opensource-src-5.15.2/qtdeclarative mkdir build cd build /opt/Qt5.15.2/bin/qmake .. make -j4 sudo make install整个过程比全量编译快很多十几分钟就能完成。重新检查/opt/Qt5.15.2/lib确认QmlModels的so文件存在后重启Qt Creator或者重新source环境变量即可。5.3 顺手把MySQL驱动补上如果你开发的项目需要直连MySQL数据库Qt的MySQL驱动是必须的。在configure阶段加了-sql-mysql且安装了libmysqlclient-dev的前提下驱动应该在编译时就已经生成了。验证方式ls /opt/Qt5.15.2/plugins/sqldrivers/如果没看到libqsqlmysql.so大概率是configure时libmysqlclient-dev还没装导致MySQL开关实际是关闭状态。这时候需要进入qtbase的sqldrivers目录单独补编cd /opt/source/qt-everywhere-opensource-src-5.15.2/qtbase/src/plugins/sqldrivers mkdir build cd build /opt/Qt5.15.2/bin/qmake .. make sub-mysql sudo make install编完之后再次检查plugins/sqldrivers目录。测试连接可以用一条最简单的命令或者在代码里用QSqlDatabase::isDriverAvailable(QMYSQL)确认驱动是否加载成功。这个驱动在ARM UOS上还有一个常见问题是动态库路径运行程序前确保LD_LIBRARY_PATH包含/opt/Qt5.15.2/plugins/sqldrivers或者把驱动复制到可执行文件的插件目录下。6. 几个维护心得模块裁剪、备份和升级避雷6.1 用-skip裁剪模块但别把qtdeclarative裁掉我在第一次编译时图省事直接去掉了qtdeclarative模块觉得项目里暂时用不到QML。结果后面同事交付的资源文件里有几个.qml界面要嵌入我只能在已经装好的Qt 5.15.2上补编模块虽然最终成功了但来回折腾了半个下午。建议是除非你非常确定整个生命周期都不会用QML否则保留qtdeclarative。真正应该skip的是webengine、webview、charts这些重量级或低频模块它们对ARM平台的编译时间影响极大。6.2 源码包和build目录不要急着删有人编译完安装成功就顺手把/opt/source下的源码包和build目录删了。后面一旦需要补编MySQL驱动、QML模块或者调整configure参数增加某个feature没有源码就得重新下载build目录没了还得重新configure。我自己的做法是把/opt/source整个目录保留源码包、源码解压目录、每个子模块的build目录都放在里面反正ARM设备的存储一般都有几百GB多占十几GB不是问题。6.3 apt upgrade之后留意系统库变化UOS的更新机制会把系统自带的Qt库版本往上抬比如从5.15.2升到5.15.3。这对自编译Qt本身没有影响因为二者安装在不同目录互不干扰。但如果你在系统全局环境里设置了LD_LIBRARY_PATH指向自编译Qt就会造成前面说的版本冲突。所以再次强调环境变量脚本只在你自己的终端会话和Qt Creator启动脚本里source不要写入/etc/profile这类全局配置。这样即使系统把Qt升到5.15.3你自编译的程序和IDE仍然稳稳地跑在5.15.2上。6.4 同架构设备之间分发时的注意事项如果你的团队有多台同架构的UOS设备编译好的一套/opt/Qt5.15.2和/opt/QtCreator-4.15.2是可以打包复制过去直接用的省去每台设备重复编译的时间。打包之前确认目标机器的glibc版本不低于编译机的版本Mesa或GPU驱动相关的系统库也保持一致。我用tar打包整个目录分发到另一台鲲鹏机器上解压后source环境变量就直接能编译运行没有遇到额外问题。需要注意的是如果分发后机器上还设置了系统全局Qt路径要检查一下环境变量优先级避免两个版本的Qt库混着加载。这套流程走下来从源码编译Qt 5.15.2到定制一套匹配的Qt CreatorARM架构UOS上的Qt开发环境就算彻底立住了。整个过程里最关键的其实不是那些命令本身而是理解每条命令、每个参数背后的取舍尤其是环境变量的隔离思路和模块裁剪的粒度。把这些想清楚了以后不管是升级Qt版本还是增加功能模块都不会再一头雾水。
返回列表