Buildroot中Qt5从5.10升级到5.12:包族改造、实操与排障

发布时间:2026/11/3 15:03:42
Buildroot中Qt5从5.10升级到5.12:包族改造、实操与排障 1. 摸清底细Buildroot 里的 Qt5 包族是怎么组织的Buildroot 把 Qt5 拆成了一堆独立的包package/qt5/目录下你能看到qt5base、qt5declarative、qt5quickcontrols2、qt5svg、qt5multimedia、qt5serialport、qt5webengine这一长串名字。它们全都不是各自维护版本号的真正决定版本的地方只有一处——package/qt5/qt5.mk开头那几行。我第一次接触这套结构时以为是每个子包单独管版本结果改了半天发现只要把qt5.mk里的QT5_VERSION一动所有子包都跟着变这个设计其实很聪明但也意味着你动手改的是整个家族而不是某一个模块。具体长这样不同 Buildroot 小版本行号会有出入内容基本一致QT5_VERSION_MAJOR 5.10 QT5_VERSION $(QT5_VERSION_MAJOR).1 QT5_SITE https://download.qt.io/official_releases/qt/$(QT5_VERSION_MAJOR)/$(QT5_VERSION)/submodules QT5_SOURCE_TARBALL_PREFIX qt子包们通过QT5BASE_VERSION $(QT5_VERSION)、QT5DECLARATIVE_VERSION $(QT5_VERSION)这种方式引用源码包名则统一走$(QT5_SOURCE_TARBALL_PREFIX)xxx-opensource-src-$(QT5_VERSION).tar.xz。看上去只要把5.10.1换成5.12.12就能收工但实际动手过的都知道真正的活儿全在后面哈希文件要换、老补丁要重做、部分包的依赖关系变了、个别模块在 5.12 里源码包结构也不一样了。1.1 版本号集中管理带来的连锁反应因为所有子包共用一个QT5_VERSION你没法做到“base 用 5.12、multimedia 留 5.10”这种混搭这在工程上其实是好事——Qt 各模块之间是强耦合的版本错位大概率会在链接期炸出一堆符号问题。但它也带来一个副作用当你只想升qtbase验证一下时所有已选中的 Qt 子包都会一起被拖着升编译时间和踩坑面一下子放大好几倍。我的建议是第一次升级时把make menuconfig里的 Qt 相关选项砍到最少只留qt5base加一个qt5declarative确认能编过、能上板起一个最小的 QML 窗口再逐个把业务需要的模块加回来。这样出问题时排查范围小也容易定位到底是哪一个模块在 5.12 上不兼容。这个思路跟做硬件调试先点亮电源再上负载是一个道理别一上来就全量编译那是给自己找麻烦。另外提醒一点Buildroot 在package/qt5/下每个子包目录里还有Config.in里面定义了BR2_PACKAGE_QT5BASE_EGLFS、BR2_PACKAGE_QT5BASE_LINUXFB、BR2_PACKAGE_QT5BASE_FONTCONFIG这类细粒度开关。这些开关在 5.12 里有增有减升级后第一件事是把Config.in通读一遍看看有没有你原来依赖的选项名字已经变了。我就遇到过一次某个选项在 5.12 里改了名defconfig里还写着老名字make时被静默忽略结果编译出来的库少了一大块功能查了大半天才发现是配置没生效。1.2 Qt 5.12 到底带来了什么值不值得折腾5.12 是 Qt 的一个长期支持版本官方承诺的支持周期明显长于普通版本社区里绝大多数基于 Qt 的嵌入式项目都把 5.12 当作事实上的稳定基线。相比 5.9、5.10 这类过渡版本5.12 在 QML 引擎性能、Qt Quick 的渲染管线、高 DPI 支持上都有实打实的改进WebEngine 部分也跟着上游做了比较大的版本跳跃。但升级不是没有代价的。5.12 对编译器的最低要求提高了C11 从“可选”变成“必须”如果你的工具链还是 gcc 4.9 那一代qtbase的 configure 阶段就会直接卡住。同时 5.12 在 EGL 和 OpenGL ES 的接口探测上比 5.10 严格得多以前“糊弄过去”的平台升级后会明确报找不到EGL/egl.h。我给一个粗判断如果现有版本跑得稳、没有新 API 需求、也没有 WebEngine 的安全更新压力那就不必动。反过来如果你遇到了 QML 列表滚动卡顿、想用 5.12 里新的QQuickWindow接口、或者上游某个第三方库明确要求 5.12 以上那这次升级就值得做。最怕的是“听说 5.12 更好就升”升完发现板子上的 GPU 驱动只支持到 GLES 2.0 的某个子集那才是真的进退两难。1.3 动手前先做一次基线备份这一步很多人跳过然后在一堆报错里迷失方向。升级前务必把当前的编译产物完整跑一遍把output/images/下的镜像留一份把defconfig存一份最好再记录一下当前qtbase的实际版本号和安装到staging里的库文件清单。一旦升级失败回不去这些记录就是你重新校准的锚点。我一般的做法是git tag baseline-before-qt512然后把整个output/target/usr/lib和output/target/usr/lib/qt打个 tar 包放到别处。这样即使后面把package/qt5改得面目全非git checkout一下就能回到原点不至于从零开始。git tag baseline-before-qt512 tar -czf /tmp/qt5-baseline.tar.gz output/target/usr/lib output/target/usr/lib/qt2. 三条改造路径的取舍别一上来就闷头改想给 Buildroot 换 Qt 版本本质上是有几种做法的选哪条取决于你这个工程是要“临时验证一下”还是“长期维护三五年”。我在不同项目里三种都走过代价差别挺大这里把账算清楚。2.1 直接改 package 目录十分钟见效但别进生产最直接的办法就是打开package/qt5/qt5.mk改两行然后make qt5base-dirclean make。这条路适合快速验证“5.12 在我的板子上到底能不能跑起来”改完编译一次成了就成了不成就回滚成本极低。问题在于它不可维护。你改了package/qt5/下的文件等于在 Buildroot 的源码树里留了一堆本地修改。下次想从上游拉个补丁、升个 Buildroot 小版本git pull就会撞车更麻烦的是团队里别人拿到你的代码不知道你改过哪些地方。我见过有项目把这种改动直接提交到内部仓库的主干两年后没人说得清为什么qt5.mk里有个版本号和 hash 对不上最后整棵源码树都不敢动。所以这条路我只用在两类场景一是新平台预研评估 Qt 5.12 能不能跑通二是线上版本紧急修一个 Qt 的 bug需要在最短时间内出一个验证镜像。验证完就把改动整理成正式的补丁或者并入分支绝不留在工作区里过夜。2.2 用 git 分支承载改动长期维护的正解真正上线的东西我建议的做法是在 Buildroot 源码的 git 仓库里开一个自己的分支把 Qt 升级做成一次或者几次干净的提交。这样改动有记录、有注释、能回溯上游 Buildroot 发新版时你git rebase一下冲突点一目了然。具体操作是先在package/qt5/上把版本号、哈希、补丁全部改好编译验证通过之后把这些改动拆成几块提交一块是qt5.mk的版本变更一块是各子包 hash 文件的更新一块是老补丁的删除与新补丁的添加最后一块是defconfig里相关选项的调整。拆开提交的好处是将来排查问题时可以单独回退某一部分比如发现是某个补丁导致的编译失败直接 revert 那一个提交就行不用整个回滚。有一点需要说明Buildroot 的 external tree 机制主要用来新增包和配置不能用来覆盖内置包的同名定义。你在 external 里再写一个qt5base.mkBuildroot 会在解析阶段报包名重复然后退出。所以想让外挂目录去改内置包的版本这条路走不通老老实实用 git 分支管改动更靠谱。external 目录该用来放什么放你自己的 Qt 应用包、放板级配置、放自定义的 rootfs overlay这些才是它的正确用法。2.3 工具链与 host 依赖的底线检查不管走哪条路5.12 对工具链是有硬门槛的提前查清楚能省掉后面一大堆莫名其妙的报错。最低要求是 gcc 4.8 以上并且开启 C11但实践中我建议至少 gcc 5.4gcc 7 以上更稳。Buildroot 里通过BR2_TOOLCHAIN_EXTERNAL或者内置的BR2_TOOLCHAIN_BUILDROOT_*配置进去之后看一眼实际选中的 gcc 版本。host 侧还需要确认几个东西perlqtbase的 configure 脚本和部分生成脚本要用、pythonqt5declarative和一些构建脚本需要5.12 时代默认还是 python2、flex/bison部分模块的解析器生成、pkg-config。Buildroot 一般会自动把这些 host 依赖拉起来但如果你用的是外部的预编译工具链staging里的.pc文件可能不全configure 阶段就会找不到依赖。# 看工具链版本 output/host/bin/arm-linux-gnueabihf-gcc --version # 看 staging 里有没有 EGL/GLES 的 pkg-config 描述 ls output/staging/usr/lib/pkgconfig/ | grep -E egl|glesv2最后一条命令的输出很关键如果这里空空如也那qtbase的-opengl es2基本没戏你要么先把 GPU 的 GLES 库和头文件正确安装到 staging要么改用-no-opengl配合 Qt Quick 的软件渲染后端。3. 完整实操把 Qt 从 5.10 换到 5.12下面这段是按我实际做过的一个工程整理的输入是 Buildroot 2018.02 系列的源码树内置 Qt 5.10.1目标平台是一块 ARM Cortex-A7 的开发板只有 framebuffer 没有 X11。你要根据自己的情况调整但步骤顺序基本通用。3.1 改版本号、源码站点与包名前缀先开分支然后只看这三行git checkout -b qt5-5.12 sed -n 1,10p package/qt5/qt5.mk把QT5_VERSION_MAJOR改成5.12QT5_VERSION改成5.12.12。注意QT5_VERSION_MAJOR是两位的5.12不是5.12.12因为下载路径是按5.12/5.12.12/submodules/这个层级组织的写错这一行后面的 URL 就全错。QT5_VERSION_MAJOR 5.12 QT5_VERSION $(QT5_VERSION_MAJOR).12 QT5_SITE https://download.qt.io/official_releases/qt/$(QT5_VERSION_MAJOR)/$(QT5_VERSION)/submodules QT5_SOURCE_TARBALL_PREFIX qtQT5_SOURCE_TARBALL_PREFIX一般不用动它决定了源码包名前缀是qtbase-opensource-src-...还是别的形式。5.12 和 5.10 在这一块是一致的保持原样即可。如果你用的 Buildroot 版本里这个变量叫别的名字以本地文件为准别硬套。改完之后先别急着编去dl/目录下确认源码包能下下来。运行make qt5base-source让它只做下载和解压这一步能提前暴露 URL 错误。3.2 哈希与补丁目录的清理这里最容易翻车Buildroot 对每个源码包都做 sha256 校验.hash文件里写着文件名和对应的哈希值。版本一变文件名变了哈希自然也变了不更新的话下载阶段就会报wrong sha256 hash。好消息是这个报错信息里会同时给出“期望值”和“实际值”你直接把实际值抄进.hash文件就行连手动算都省了。第一次跑make qt5base-source失败时仔细看输出大概是这个形式ERROR: qtbase-opensource-src-5.12.12.tar.xz has wrong sha256 hash: ERROR: expected: xxxxxxxx... ERROR: got : yyyyyyyy...把got后面那串填到package/qt5/qt5base/qt5base.hash里注意还要把文件名那一行也改成新版本号。每个你启用的子包都要走一遍这个流程qt5declarative、qt5svg、qt5multimedia、qt5serialport一个都不能漏。漏一个的表现是编译到一半突然报 hash 错前面的编译时间全白费。补丁是另一个大坑。package/qt5/qt5base/目录下往往躺着若干0001-xxx.patch这些补丁是针对老版本源码打的升到 5.12 之后大概率对不上上下文。我的做法是先把它们全部改名成.patch.disabled后缀让 Buildroot 跳过应用cd package/qt5/qt5base for f in *.patch; do mv $f $f.disabled; done然后编译如果顺利通过说明这些补丁在 5.12 上已经不需要了很多补丁本来就是修上游后来已经修复的问题。如果编译失败再根据报错把相关的补丁改回来手动适配一下上下文行号通常就是那几行偏移的变化改改就能用。3.3 qtbase 的 configure 参数逐项过一遍Buildroot 里qt5base的配置主要落在QT5BASE_CONFIGURE_OPTS这个变量上5.12 相比 5.10 在参数语义上有些微妙变化值得逐项确认。第一组是路径相关的-sysroot $(STAGING_DIR)让 Qt 去 staging 里找依赖的头文件和库-no-gcc-sysroot告诉它别让 gcc 再套一层 sysroot这两个必须配对出现。忘了-no-gcc-sysroot的典型症状是 configure 阶段报“找不到标准库头文件”明明工具链是好的。-hostprefix和-hostbindir决定 qmake、moc、rcc 装到哪个 host 目录这个必须指向$(HOST_DIR)否则后续依赖 Qt 的包找不到qmake。第二组是图形后端。-opengl es2要求 staging 里有EGL/egl.h、GLES2/gl2.h以及对应的.pc文件如果板子只有 framebuffer就写-no-opengl。这里有个 5.12 才比较好用的选项Qt Quick 支持软件渲染后端运行时设置QT_QUICK_BACKENDsoftware即使编译时用了-no-openglQML 界面照样能跑只是动画会掉帧。对于没有 GPU 的低端平台这几乎是唯一可行的方案5.10 时代要么硬上 GLES 要么放弃 QML。第三组是平台插件。-eglfs编译 EGL 全屏后端-linuxfb编译 framebuffer 后端两个可以同时编运行时用QT_QPA_PLATFORM切。-no-xcb一定要加除非你的系统真跑 X11不然会白白引入一堆 X 相关依赖。-no-cups、-no-ico这类“关掉不用的东西”的参数能加就加对编译时间和最终体积都有好处。第四组是编译优化。-no-pch在 Buildroot 里通常是默认加的因为预编译头在并行编译时非常吃内存一个 8 核机器编qtbase能吃掉十几个 G。如果你的机器内存充足32G 以上可以试着去掉它编译速度能快一截。-reduce-relocations要求目标代码用-fPIC编译在静态链接场景下容易出问题不确定就先别加。还有一个经常被忽略的点qmake 的mkspec。Buildroot 通过环境变量和 configure 参数组合出交叉编译的 mkspec如果你的工具链前缀比较特殊比如自定义的arm-custom-linux-gnueabi-一定要确认output/host/bin下有对应名字的 qmake 配置生成否则后面qmake生成的 Makefile 会调用宿主机的 gcc。3.4 子模块按需同步别一股脑全开qtbase编过之后再逐个把业务需要的模块加回来。我按常见程度排个序你对照自己的界面代码挑。qt5declarative是 QtQuick 和 QML 引擎的本体只要界面是 QML 写的就必须有。qt5quickcontrols2提供 Controls 2 那套现代控件qt5graphicaleffects提供阴影、模糊这类视觉效果Material 风格的界面经常会用到。qt5svg在图标是 svg 格式时必须有否则图标全变成空白。qt5multimedia涉及音视频它底下会拉 gstreamer 或者 ffmpeg依赖链比较长能用轻量方案替代就别上。qt5serialport在工控类项目里几乎是标配编起来很快。qt5webengine我要单独说一句这玩意儿编译起来是灾难级别的源码包几百兆编译过程要跑一堆 host 工具生成中间代码8G 内存的机器很容易被 OOM killer 干掉整个编译过程可能持续几个小时。更麻烦的是 5.12 时代的 WebEngine 还需要 host 上的 python2而很多新发行版默认只有 python3你得额外把BR2_PACKAGE_HOST_PYTHON拉起来。除非业务明确要求内置浏览器否则我不建议在嵌入式板子上开这个模块。3.5 编译、烧写、上板验证的标准流程改完版本号之后最容易犯的错误是直接make。因为output/build/下还留着qt5base-5.10.1那个目录Buildroot 不会自动清理你make一下看着有输出其实用的还是老源码。正确做法是先 dircleanmake qt5base-dirclean make qt5basedirclean会删掉整个 build 目录和 stamp 文件保证从源码重新解压编译。这一步看着简单但我见过太多人在这里浪费时间明明改了版本号编出来的库strings一看还是 5.10 的。编译时间上有个心理准备4 核机器上qtbase大概要 40 到 90 分钟取决于你开了多少特性。开了qt5declarative和qt5quickcontrols2再加 20 分钟左右。所以第一次编译建议挂个make -j4 qt5base 21 | tee build.log日志留着后面查错用。编完之后检查产物ls output/target/usr/lib/libQt5Core.so* ls output/target/usr/lib/qt/plugins/platforms/ strings output/target/usr/lib/libQt5Core.so.5 | grep -m1 Qt 5\.第二条命令应该能看到libqeglfs.so、libqlinuxfb.so这类平台插件第三条能看到实际的 Qt 版本字符串。三个都对上了才算真正升级成功。上板验证时把平台插件和调试信息都打开export QT_QPA_PLATFORMlinuxfb:fb/dev/fb0 export QT_LOGGING_RULESqt.qpa.*true ./your-appQT_LOGGING_RULES这行能让 Qt 把平台初始化的每一步都打出来黑屏的时候全靠它定位问题。如果 framebuffer 能用但 eglfs 不行那就先跑 linuxfb 把业务逻辑验证通再回头折腾 GPU 那条路。4. 编译期和运行期的问题排查实录升级过程中踩的坑我整理了一份速查表基本上覆盖了八成的报错场景。表格里的“原因”一栏是我根据实际现象反推的如果你的情况对不上还是要看完整日志。4.1 编译报错速查表报错现象常见原因处理方式Cannot find EGL/egl.hstaging 里没有 GPU 的 EGL 头文件确认 GPU 库已正确安装到 staging或临时改-no-openglUnknown module(s) in QT: quick没启用qt5declarative在 menuconfig 里打开对应选项nullptr was not declared in this scope工具链 gcc 版本过低换 gcc 5.4 以上的工具链patch does not apply老补丁与新源码不匹配把补丁临时禁用按需重做undefined reference to __atomic_*缺少 libatomic链接时加-latomic或换工具链Project ERROR: Unknown module(s) in QT: qmlqt5declarative的 qml 模块没编进去检查qt5declarative的 Config.in 依赖fatal error: features.h: No such filesysroot 配置错误检查-sysroot与-no-gcc-sysroot是否配对host 侧qmake: Permission deniedhost 目录权限异常检查output/host/bin权限和挂载选项这几条里我印象最深的是__atomic_*那个。当初排查了半天以为是 Qt 的问题后来用nm一查发现是某个依赖库用了旧的原子操作接口而这个平台的 gcc 默认没链接 libatomic。解决方式很土就在那个包的.mk里加FOO_CONF_ENV LIBS-latomic编过就完事了。还有一个隐蔽的坑qt5base编译到一半报“找不到qhelpgenerator”或者类似的 host 工具缺失。这通常是因为上一次编译中途被打断host 工具没装完整。解决办法是make qt5base-dirclean之后再编一次别试图手工补文件很容易留下状态不一致的烂摊子。4.2 上板后黑屏、字体乱码、QML 加载失败黑屏是最高频的问题排查顺序建议是先看平台插件有没有加载再看 EGL 集成对不对最后看权限。QT_DEBUG_PLUGINS1这个环境变量会把插件加载的全过程打出来包括它尝试了哪些路径、为什么拒绝某个插件。十有八九你会看到它在/usr/lib/qt/plugins/platforms/里找不到匹配的QT_QPA_PLATFORM值或者找到了但依赖的libEGL.so版本对不上。如果是 eglfs 加载了但屏幕一直黑大概率是 EGL 集成选错了。5.12 里 eglfs 下面有好几种集成方式用QT_QPA_EGLFS_INTEGRATION显式指定export QT_QPA_EGLFS_INTEGRATIONeglfs_kms # 走 DRM/KMS export QT_QPA_EGLFS_INTEGRATIONeglfs_fb # 走 framebuffer有的平台厂商会提供自己的 eglfs 集成插件名字通常是eglfs_xxx具体叫什么得翻厂商给的文档或者ls一下插件目录。字体乱码在中文界面上几乎必然遇到。Qt 5.12 默认只带一小撮西文字体中文全靠系统字体。解决方式是把一个中文字体文件放到目标板的/usr/share/fonts/下或者在代码里QFontDatabase::addApplicationFont()加载打包进资源的字体。后者的好处是不依赖系统路径坏处是字体会让二进制体积增加几兆。QML 加载失败的报错通常很直白module QtQuick.Controls is not installed这种就是模块没编进去或者插件路径不对。检查output/target/usr/lib/qt/qml/下有没有对应的目录如果有目录但运行时还是找不到那就设置QML2_IMPORT_PATH指过去。另外 5.12 引入了 QML 缓存机制编译期生成的.qmlc文件如果和源码不同步运行时会报“no cached version available”之类的警告遇到这种情况把 build 目录清掉重编一般就好。4.3 体积与启动时间的优化空间升级到 5.12 之后体积涨个两三兆是正常的但如果不做处理可能涨得更多。qtbase的库加上插件、QML 模块一个完整的 GUI 环境轻松超过 25MB。对于 flash 只有 128MB 的板子这个数字得盯着点。第一刀砍在插件目录。/usr/lib/qt/plugins/下面有imageformats、sqldrivers、bearer、iconengines一堆子目录把业务用不到的整个删掉比如不做图片处理就把imageformats里除 png/jpeg 之外的都去掉。第二刀砍在 QML 模块/usr/lib/qt/qml/下用不到的模块目录直接删注意删之前确认业务代码没 import。第三刀是编译选项-optimize-size让编译器偏向体积而不是速度配合BR2_STRIP_stripy效果明显。如果对启动时间敏感可以反过来用-optimize-speed但体积会涨。启动时间方面QML 应用的冷启动主要耗时在 QML 文件解析和插件加载上。5.12 的 QML 缓存机制能显著改善这一点前提是你的 QML 文件是打进 qrc 资源的编译期会生成对应的缓存。如果 QML 是放在文件系统上动态加载的缓存机制就用不上启动会慢不少。5. 长期维护怎么让下次升级不再这么痛5.1 把改动固化成可复现的提交前面说过用 git 分支管改动这里补充几个实操细节。提交信息里一定要写清楚“为什么升”、“从哪个版本升到哪个版本”、“哪些补丁被移除以及原因”。我当时那条提交信息写了快两百字半年后回头看省了不知道多少事。defconfig也要跟着提交。很多人只提交package/qt5/的改动忘了defconfig里可能有关联的选项变化。比如 5.12 里某个 Kconfig 选项改名了老defconfig里那一行会被静默忽略编译出来的功能少了但没人发现。所以升级完成后务必make savedefconfig重新生成一份对比一下差异。5.2 版本锁、补丁管理和持续集成qt5.mk里的QT5_VERSION一旦定下来就别轻易动尤其是产品已经出货之后。5.12 系列本身有小版本迭代5.12.1 到 5.12.12每个小版本都会有 bug 修复和安全补丁但对嵌入式项目来说每次升级都要重新验证一遍成本不低。我的做法是锁定一个经过充分验证的小版本只在出现严重安全问题时才

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询