news 2026/9/19 3:23:11

Qt 5.14.2在aarch64上的静态交叉编译完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Qt 5.14.2在aarch64上的静态交叉编译完整指南

早年间第一次在一台 arm64 开发板上部署 Qt 程序,我干过最蠢的一件事:把整棵/usr/lib/aarch64-linux-gnu/qt5目录从板子上另一台“同款”设备拷过去,然后对着“cannot find libQt5XcbQpa.so.5”折腾到半夜。后来换了思路,彻底改走静态交叉编译路线:在 x86 的编译机上用aarch64-linux-gnu-g++交叉工具链把 Qt 5.14.2 做成.a静态库,再链接出单个可执行文件,拷到板子上直接跑,之后再也没被 Qt 的动态库依赖折磨过。

这篇文章就是那套流程的完整复盘。核心是:Ubuntu 20.04 主机上交叉编译 Qt 5.14.2,目标平台 aarch64(即 ARM64),全静态链接。我不只给命令,还会把 configure 里每个参数为什么这么传、静态链接时插件为什么要手动导入、为什么最终二进制体积这么大、目标板 glibc 版本不匹配怎么排查,全部说清楚。适合刚接触交叉编译的读者,也适合被动态库版本地狱搞烦了、想换一种部署方式的嵌入式老人。

1. 为什么是 Qt 5.14.2、aarch64 和静态交叉编译

1.1 版本选择背后的考量

先解释选型。Qt 5.14.2 不是最新版,但做交叉编译,稳定压倒一切。5.14 这个分支的 configure 和 mkspec 对 aarch64 的支持已经完全成熟,网上能查到的踩坑记录也最多,真遇到问题,搜一搜基本都有答案。5.12 是更老的 LTS,也能用,但一些模块的 bug 修复和 aarch64 相关补丁不如 5.14 完整。5.15 后续补丁版本对开源用户来说拿不全,6.x 的构建系统变化又比较大,如果你不是非追新不可,选 5.14.2 是风险最低的方案。

另外一点是这个版本对静态构建特别友好。它的静态库构建路径经过了大量验证,第三方库(zlib、libpng、libjpeg、freetype、harfbuzz、pcre)都可以选择用 Qt 源码树内自带的版本,不需要在 sysroot 里逐个装 ARM64 的开发包,这能省掉一大半环境问题。对于“从零搭建”这件事来说,少一个外部依赖就少一分失败概率。

1.2 静态交叉编译到底解决什么问题

静态和动态的核心区别一句话就能讲明白:动态方案里,可执行文件只记下“我需要 libQt5Widgets.so.5”,运行时再去系统里找;静态方案里,Qt 库的代码在链接阶段直接焊进你的可执行文件,运行时不再找 Qt 的动态库。

在 aarch64 嵌入式场景下,动态方案的痛苦非常典型:

  • 板子存储小,但 Qt 动态库动不动几百 MB,加插件更多。
  • 每次换板子都要对 Qt 库版本和编译器版本,cannot find -lQt5XcbQpa.so.5这类报错能追到怀疑人生。
  • 动态插件机制在裁剪过的 rootfs 上经常失效,平台插件找不到,程序直接黑屏退出。
  • 生产板子往往没有网络,没法临时apt install补依赖。

静态方案把这些问题整个绕开:最终交付物就是单文件二进制,拷贝即运行。代价是体积大(一个 Qt Widgets 静态程序大概 15~30 MB,strip 之后会小一些)和编译时间长(全量编译一两个小时很正常)。对“部署简单、环境干净”有硬要求的项目,这笔交换是值的。

1.3 这套手册适合谁

严格来说,这套流程适合三类人:第一类,目标是 ARM64 Linux 板子,板子跑精简 rootfs,没有条件装 Qt 运行环境;第二类,程序功能相对固定,不需要在板子上频繁加载外部 Qt 插件,也不需要做动态更新的二次开发;第三类,做交付型项目,希望把“环境搭建”这个不可控因素从交付清单里划掉的人。

反过来,如果你需要在板子上长期做二次开发,每次改代码都重新全量编译一个几十 MB 的静态程序,或者你的程序要按设备动态加载第三方插件,那还是老老实实走动态方案。静态不是银弹,它是用编译期的复杂换运行期的简单。

2. 开始前的环境准备:主机、工具链与 sysroot

2.1 主机环境与基础软件

我这套流程在 Ubuntu 20.04 x86_64 上完整验证过,18.04 也可以,再老的版本建议先升级。主机先装基础工具:

sudo apt update sudo apt install -y build-essential perl wget git

build-essential提供宿主机的gccg++make,Qt 的 configure 脚本还要依赖perl,少一个都会在奇怪的地方报错。顺手把git装上,后面拉补丁或者做版本管理工作方便。

这里有个常见的坑:很多人以为交叉编译只需要交叉工具链,结果 configure 一开始就报“The specified compiler is not available”或者make找不到,其实是因为宿主编译环境都没装齐。Qt 构建过程中有一部分工具(moc、rcc、uic、qmake)必须在编译机上运行,它们是用宿主编译器先编译出来的,所以宿主机工具链同样必需。

2.2 安装 aarch64 交叉编译工具链

Ubuntu 软件源里现成的交叉工具链就很够用:

sudo apt install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu

安装完验证一下:

aarch64-linux-gnu-gcc --version # 通常在 9.3.0 或更新版本

这个工具链的名字要记清楚:以aarch64-linux-gnu-为前缀。对应 Qt mkspec 里默认的编译器名就是aarch64-linux-gnu-gccaarch64-linux-gnu-g++,所以用系统包不会出现“找不到编译器”的问题。这个包会连带安装 ARM64 的 libc、libstdc++、libatomic 等运行库,默认 sysroot 在/usr/aarch64-linux-gnu目录下,这点后面会用到。

如果你的板子处理器比较特殊,比如需要针对某些 ARM 特性做优化,可以用 Linaro 的工具链或者自己编的 GCC,但那属于进阶玩法,这次先不展开。

2.3 sysroot 的三种做法

sysroot 是交叉编译里最容易懵的概念。说白了,它就是“目标板根文件系统的裁剪版”,里面装着目标板上的头文件和库文件,交叉编译器编译时拿它当/usr/lib的根。有三种常见做法:

第一种,直接用工具链自带的默认 sysroot。Ubuntu 的gcc-aarch64-linux-gnu包在/usr/aarch64-linux-gnu下自带了一套 ARM64 的 libc/libstdc++ 头文件和库,大多数情况够用。本手册的配置里,我们刻意关掉了 xcb、OpenGL、DBus、ICU 这些依赖外部库的功能,所有图像、字体、压缩库都用 Qt 源码自带的,所以外部的 ARM64 依赖只剩 glibc 和 libstdc++,工具链自带的 sysroot 就足够了。

第二种,从目标板把真实运行环境 rsync 出来。当你的程序需要链接板子上特有的、工具链 sysroot 里没有的库时,就得用这个办法:

mkdir -p sysroot/lib sysroot/usr/lib sysroot/usr/include rsync -avz root@<board_ip>:/lib/ ./sysroot/lib/ rsync -avz root@<board_ip>:/usr/lib/ ./sysroot/usr/lib/ rsync -avz --safe-links root@<board_ip>:/usr/include/ ./sysroot/usr/include/

注意保持符号链接,rsync 不要加-L,否则一些相对路径的软链会被破坏。然后用--sysroot=/path/to/sysroot指定给编译器。这个方案的好处是和目标板完全一致,坏处是每次板子更新系统都要重新同步。

第三种,用 Buildroot 或 Yocto 生成的 SDK sysroot。项目本身用 Buildroot/Yocto 管理的,直接导出它们的 toolchain 即可,干净、可复现。本手册不依赖它,但如果你的生产构建体系已经在用,直接替换工具链部分就行。

3. 下载源码与 configure 参数决策

3.1 获取 Qt 5.14.2 源码

源码从 Qt 官方 archive 下载,文件名很关键,一定要是qt-everywhere-src而不是qt-everywhere-opensource-src(后者是老版本命名):

wget https://download.qt.io/archive/qt/5.14/5.14.2/qt-everywhere-src-5.14.2.tar.xz tar -xJf qt-everywhere-src-5.14.2.tar.xz cd qt-everywhere-src-5.14.2

解压完先别急着 configure,看一下目录里的qtbase/mkspecs/linux-aarch64-gnu-g++这个目录是否存在。Qt 对 aarch64 的支持在 mkspec 层面已经集成了,确认它在,后面用-xplatform linux-aarch64-gnu-g++就不会出“mkspec 不存在”的问题。

3.2 模块裁剪:先砍掉不必要的重量级模块

Qt 5.14.2 完整源码包包含几十个模块。交叉编译静态构建时,如果全部编译,一是耗时长,二是一堆模块根本用不上,三是一些模块在静态交叉场景下依赖特别多、特别容易失败。最典型的就是qtwebengine,它在 aarch64 静态构建下基本是噩梦,直接跳过。

我的建议是只保留核心模块。qtbase是核心,必须留;qtserialportqtsvgqtimageformats这类轻量的按需保留;qtwebengineqtwebviewqt3dqtchartsqtdatavis3dqtmultimediaqtscriptqtvirtualkeyboardqtwayland这套重模块,没有明确需求就直接-skip掉。

这里特别提醒一句:很多人配置时图省事,把所有模块都留着,结果编译到一半卡在某个模块的依赖上报错,回头再查 configure 日志,发现问题根本不在 Qt 本身,而是某个可选模块要的库没在 sysroot 里。裁剪模块不是为了省硬盘,是为了把构建成功的概率拉高。

3.3 逐个拆解 configure 关键参数

configure 是整个流程里信息量最大的一步。我把关键参数按组拆开解释,这样你后面按需调整时知道自己在动什么。

-platform linux-g++指定的是编译机上运行的工具链。-xplatform linux-aarch64-gnu-g++指定的是目标平台工具链。两者必须同时给对——-platform决定 qmake、moc、rcc、uic 这些构建期工具用什么编译器生成,-xplatform决定真正的 Qt 库和目标二进制用什么编译器。搞反或者漏掉一个,轻则工具无法在主机上运行,重则编出一堆 x86 的“伪交叉”产物。

-static让 Qt 库以.a静态库形式产出。这里有个容易误解的点:这个参数只决定 Qt 库本身的形态,并不强制最后链接出的应用程序一定是全静态。最终链接时,你还可以选择只静态 Qt 库而保留动态 glibc,这个策略差异我们放到第 5 节细讲。

-release -opensource -confirm-license是常规交代。-release去掉调试信息,体积和速度都更友好;-opensource -confirm-license接受开源协议,省得 configure 交互式问你。

第三方库相关的参数是本手册默认配置的核心:

-qt-zlib -qt-libpng -qt-libjpeg -qt-freetype -qt-harfbuzz -qt-pcre

这组参数的意思是“用 Qt 源码里自带的第三方库,不要到 sysroot 里找系统库”。交叉编译最怕的是每个依赖都要为 ARM64 单独编译一份,有了这组参数,zlib、libpng、libjpeg、freetype、harfbuzz、pcre 全部由 Qt 自己构建,sysroot 里缺什么都不影响,这是从零搭建能成功的关键。

功能裁剪参数是另一组:

-no-opengl -no-xcb -no-dbus -no-icu -no-glib -no-fontconfig

-no-opengl关闭 OpenGL/EGL,因为静态编译默认不需要 GPU 渲染的 framebuffer 应用用不到;-no-xcb关闭 X11 客户端支持;-no-dbus关闭 D-Bus,嵌入式 rootfs 十有八九没跑 D-Bus,不关的话 configure 会尝试找 dbus 头文件;-no-icu关闭 ICU 文本库,省掉一个大依赖;-no-glib避免和 glib 发生关系;-no-fontconfig关闭系统字体配置服务,字体问题我们在第 6 节单独解决。

这组参数换来的是“外部依赖只剩 glibc/libstdc++”的干净状态。如果你的板子确实需要 xcb 或 OpenGL,那 sysroot 要重新准备,不能照抄这组配置,这点后面常见问题里再展开。

4. 执行编译与安装

4.1 完整的 configure 命令

把前面的决策落到命令上,完整配置如下。先创建安装目录,再执行 configure:

sudo mkdir -p /opt/qt-aarch64 sudo chown -R $USER /opt/qt-aarch64 cd qt-everywhere-src-5.14.2 ./configure \ -platform linux-g++ \ -xplatform linux-aarch64-gnu-g++ \ -prefix /opt/qt-aarch64 \ -static \ -release \ -opensource \ -confirm-license \ -nomake examples \ -nomake tests \ -skip qtwebengine \ -skip qtwebview \ -skip qt3d \ -skip qtcharts \ -skip qtdatavis3d \ -skip qtlocation \ -skip qtmultimedia \ -skip qtpurchasing \ -skip qtscript \ -skip qtsensors \ -skip qtspeech \ -skip qttools \ -skip qtvirtualkeyboard \ -skip qtwayland \ -skip qtwebchannel \ -skip qtwebsockets \ -no-opengl \ -no-xcb \ -no-dbus \ -no-icu \ -no-glib \ -no-fontconfig \ -qt-zlib \ -qt-libpng \ -qt-libjpeg \ -qt-freetype \ -qt-harfbuzz \ -qt-pcre

configure 跑完会输出一大段检测结果。重点看这几个字段:FreeType: yes (bundled copy)FontConfig: noICU: noXcb: no。如果看到和预期不一致的项,先别急着 make,回头调整参数。configure 失败时,去config.log里搜error:,大部分原因一眼就能看出来。

4.2 并行编译与内存控制

configure 通过后开始编译:

make -j4

-j并发数不要盲目拉满。Qt 静态全量编译非常吃内存,8 GB 内存的机器用-j4比较稳,16 GB 可以试-j8。我见过有人用-j$(nproc)在 8 核心机器上编译,跑到一半进程被内核 OOM 杀掉,白白浪费一小时。用-j4慢是慢点,但能一次跑完。

编译中途如果make报错,修完问题后重新执行同样的make -j4即可,Qt 的构建系统支持断点续编,不需要重新 configure。

整体耗时和机器配置强相关。8 核心 16 GB 内存的机器,按上面的裁剪方案大概 40 到 60 分钟;4 核心老机器可能要两小时。建议编译期间不要跑大型 GUI 程序,免得把内存顶爆。

4.3 安装产物验证

编译完成后安装:

make install

装完做两个验证,确认交叉编译结果没搞反:

file /opt/qt-aarch64/bin/qmake # 输出: ELF 64-bit LSB executable, x86-64 # qmake 必须能在 x86 主机上运行 file /opt/qt-aarch64/lib/libQt5Widgets.a # 输出: ELF 64-bit LSB relocatable, ARM aarch64 # 静态库必须是指向 aarch64 的目标文件

这个对照很重要:bin/qmake是 x86-64,因为它要在编译机上执行,负责替目标程序生成 Makefile;而lib/下的.a库则是 aarch64 的目标文件,是给目标板用的。如果你看到libQt5Widgets.a显示 x86-64,说明-platform-xplatform传反了,马上回头重配,别继续往下走。

注意这里make install不需要INSTALL_ROOT,因为安装路径就是-prefix指定的/opt/qt-aarch64,直接装进宿主机目录。等目标板部署时,我们只拷贝最终的可执行文件,不拷贝整棵 Qt 树。

5. 交叉编译第一个静态 Qt 程序

5.1 示例工程与静态插件导入

Qt 库编成静态之后,有一个和动态方案截然不同的关键操作:手动导入插件。动态方案下,Qt 在运行时根据配置去插件目录找libqlinuxfb.so;静态方案下没有这个查找过程,所有插件代码必须在链接时进入可执行文件,这就要靠Q_IMPORT_PLUGIN宏。

建立一个示例工程目录:

mkdir -p ~/hello && cd ~/hello

hello.pro文件:

QT += core gui widgets CONFIG += static TARGET = hello TEMPLATE = app SOURCES += main.cpp QTPLUGIN += qlinuxfb qoffscreen qminimal

main.cpp文件:

#include <QApplication> #include <QLabel> #include <QtPlugin> Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin) Q_IMPORT_PLUGIN(QLinuxFbIntegrationPlugin) Q_IMPORT_PLUGIN(QOffscreenIntegrationPlugin) int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel label("Hello, aarch64 static Qt!"); label.resize(360, 120); label.show(); return app.exec(); }

.pro里的QTPLUGIN += qlinuxfb qoffscreen qminimal让 qmake 去链接这三个平台插件的静态库,Q_IMPORT_PLUGIN宏负责把插件的初始化代码拉进来。少了Q_IMPORT_PLUGIN,程序运行时会报“could not find the Qt platform plugin”,这是个非常典型的静态编译坑。

5.2 编译步骤与链接选项

用交叉环境下的 qmake 生成 Makefile,然后编译:

export PATH=/opt/qt-aarch64/bin:$PATH /opt/qt-aarch64/bin/qmake hello.pro make

如果链接阶段报cannot find -latomic,说明 aarch64 的 libatomic 静态库没装:

sudo apt install libatomic1-arm64-cross

或者在.pro里直接加一行:

QMAKE_LIBS += -latomic

libatomic是 aarch64 上比较常见的一个隐藏依赖,某些原子操作需要它,很多人第一次编完 Qt 却在链接 app 时翻车,基本都是这个原因。

关于最终链接方式,这里说清楚三种选择。第一种是“Qt 静态 + 系统库动态”,也就是默认行为:不额外加链接参数,Qt 的.a会进入二进制,而 libc、libstdc++ 保持动态链接。第二种是半静态,在.pro里加QMAKE_LFLAGS += -static-libgcc -static-libstdc++,把 C/C++ 运行库也打成静态,只剩 glibc 的动态部分。第三种是全静态,加QMAKE_LFLAGS += -static,glibc 也静态链入。

全静态看起来最美,但 glibc 静态链接有边界问题:getaddrinfo、NSS 这些需要运行时动态打开.so的能力在静态链接下会失效,程序跑起来会打印类似“Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries”的警告,涉及网络的程序可能直接解析不了域名。所以我个人最推荐第二种,Qt 静态、C/C++ 运行库静态,但保留 glibc 动态。目标板几乎都带 glibc,兼容性最好,部署只依赖 libc 一个动态库,风险极低。

5.3 用 file 和 readelf 验证静态属性

编译出的二进制在编译机上无法直接运行,但可以先验证结构。file告诉你架构,readelf告诉你动态依赖:

file hello # 输出: ELF 64-bit LSB executable, ARM aarch64 aarch64-linux-gnu-readelf -d hello | grep NEEDED # 默认方式下会看到: libstdc++.so.6, libgcc_s.so.1, libc.so.6, libm.so.6 # 如果加了 -static,这里应该一行 NEEDED 都没有

看到ARM aarch64字样,说明编译目标正确;看NEEDED列表,确认没有libQt5Widgets.so.5之类的 Qt 动态依赖,就说明 Qt 已经成功焊进二进制了。体积上,一个带 Widgets 的静态程序大概 15~30 MB,strip 之后能压到 8~15 MB:

aarch64-linux-gnu-strip hello ls -lh hello

这个体积在大容量 SD 卡或 eMMC 上完全不是问题。如果你后续要追求极致体积,可以再研究 UPX 压缩,但生产环境我并不推荐 UPX,它会拖慢程序启动,节省的那几 MB 不值得。

6. 部署到目标板:从拷贝到稳定运行

6.1 最简单的部署命令

部署其实就是传一个文件过去:

scp hello root@<board_ip>:/home/root/ ssh root@<board_ip> chmod +x /home/root/hello /home/root/hello -platform linuxfb

-platform linuxfb走 Linux framebuffer,直接操作/dev/fb0,不需要 X11、不需要 Wayland,这是精简嵌入式板子最常见的 GUI 运行方式。如果板子没有接显示器或者没有/dev/fb0,可以先用-platform offscreen验证程序能起来,它不依赖任何显示设备。

如果你的程序既有 GUI 又需要无人值守启动,可以在程序里硬编码平台插件,这样连-platform参数都不用带。办法是在 main 函数里调用qputenv("QT_QPA_PLATFORM", "linuxfb"),但注意必须在创建QApplication之前设置:

#include <QApplication> #include <QtPlugin> #include <QByteArray> Q_IMPORT_PLUGIN(QLinuxFbIntegrationPlugin) int main(int argc, char *argv[]) { qputenv("QT_QPA_PLATFORM", "linuxfb"); QApplication app(argc, argv); // ... }

6.2 字体等数据资源的处理

因为 configure 时带了-no-fontconfig,目标系统上的字体配置服务完全不参与,Qt 不会自动去/usr/share/fonts搜索字体。如果程序里显示中文或特殊字形,界面上很可能直接出现方块。

解决办法很简单,把需要的字体文件拷到板子上,然后在程序里用QFontDatabase::addApplicationFont加载:

#include <QFontDatabase> int main(int argc, char *argv[]) { qputenv("QT_QPA_PLATFORM", "linuxfb"); QApplication app(argc, argv); QFontDatabase::addApplicationFont("/usr/share/fonts/wqy/wqy-zenhei.ttc"); QFont font("WenQuanYi Zen Hei"); font.setPixelSize(28); app.setFont(font); // ... }

没有中文字体需求的话,复制一个DejaVuSans.ttf就够英文界面用了。这个细节在动态方案里基本不用操心,但在静态方案里它决定你看到的是正常文字还是满屏方块。

除了字体,还有两类资源容易漏。第一类是图片、样式表、QML 文件等数据文件,静态编译不会把这些文件嵌入二进制,除非你用了 Qt 资源系统.qrc;第二类是翻译文件.qm,同理。我的习惯是:所有静态二进制配套的数据资源,能塞进.qrc就塞进去,实在要塞外部文件的,在部署清单里单独列一行,防止交付时漏拷贝。

6.3 用 qemu 用户态在主机上先跑一遍

每次部署都往板子 scp 调试太慢了。一个高效的验证手段是用qemu-user在编译机上直接跑 ARM64 二进制:

sudo apt install -y qemu-user

然后指定目标 libc 的路径执行:

qemu-aarch64 -L /usr/aarch64-linux-gnu ./hello -platform offscreen

如果你的程序是全静态链接的,连-L都不用加:

qemu-aarch64 ./hello -platform offscreen

看到窗口内容打印出来或者程序正常退出,说明这个二进制在 ARM64 的 ABI 层面上是健康的。qemu 和真实板子毕竟有差异,最终还是要上板验证,但日常调试阶段用这招能省很多来回拷贝的时间。注意 GUI 程序要用-platform offscreen,linuxfb 在 qemu 下没有/dev/fb0可用。

7. 常见问题与排查技巧实录

7.1 高频错误速查表

这套流程跑了很多次,真正高频的报错就那几十个。整理成速查表,按出现频率排序:

报错信息原因处理办法
cannot find -latomiccannot find -lglib-2.0sysroot 缺少对应静态库安装跨平台库包,如libatomic1-arm64-cross;glib 系库若没必要就-no-glib关掉
unknown module(s) in Qt: serialportconfigure 时跳过了 qtserialport,或者使用的 Qt 构建里没有该模块不要-skip对应模块重新构建;qtserialport是库模块,静态链接后直接在.proQT += serialport即可
Could not find the Qt platform plugin "linuxfb"静态构建下平台插件未链入可执行文件在源码里Q_IMPORT_PLUGIN(QLinuxFbIntegrationPlugin),并在.pro里加QTPLUGIN += qlinuxfb
cannot find -lGLOpenGL 相关功能开启,但 sysroot 没有 libGL确认 configure 带-no-opengl;确有需要时给 sysroot 装 mesa aarch64 静态库
qmake: ELF 64-bit LSB executable, x86-64libQt5Core.a也是 x86-64-platform-xplatform传反-platform linux-g++ -xplatform linux-aarch64-gnu-g++重配
error: cannot run C++ compiler或 configure 中途退出缺少宿主机构建环境或交叉工具链未装安装build-essentialg++-aarch64-linux-gnu
make: g++: Command not found宿主 g++ 不存在sudo apt install build-essential
编译进程被Killed内存不足,OOM降低-j并发,建议先关浏览器再编译
运行时报Illegal instruction编译器默认指令集与板子 CPU 不匹配确认板子是否为 armv8-a,过老的板子考虑用老工具链或调整 mkspec 的 march 参数

7.2 运行时崩溃与插件相关排查

静态程序出现运行时崩溃,十有八九是插件导入不全,其次是系统资源路径不对。最典型的场景是:程序里只导入了qlinuxfb,却用-platform offscreen启动;或者反过来,界面程序依赖了QOffscreenIntegrationPlugin但忘了Q_IMPORT_PLUGIN,运行时报“No such plugin”。

遇到这类问题,先别急着怀疑 Qt 库本身,按这个顺序排查:

第一,确认启动参数。-platform后面跟的插件名必须在导入列表里。截图验证或者在 main 开头qputenv固定平台,这是最省事的做法。

第二,确认 sysroot 和链接参数。用readelf -d再看一遍NEEDED,如果出现libQt5Core.so.5这种 Qt 动态依赖,说明你链接的库不是我们刚编好的静态库,八成是系统里原来的 qmake 混进来了。务必用/opt/qt-aarch64/bin/qmake,别依赖环境变量里的旧版本。

第三,确认目标板 glibc 版本。用 qemu 用户态测过没问题的二进制,上板后如果报version GLIBC_2.32 not found,说明目标板 glibc 比工具链对应版本老。查内核和 glibc 版本用:

# 目标板上执行 ldd --version

如果板子比较老,需要换一个旧版本的交叉工具链重新编译,这是交叉编译里最无奈但也最需要意识到的一个约束:编译机的新工具链,产出的二进制默认要求目标板具备相近或更新的系统库。

7.3 静态方案最容易踩的三个坑

第一个坑是盲目追求全静态。QMAKE_LFLAGS += -static全静态链接后,glibc 的getaddrinfo会需要运行时加载 NSS 模块,静态程序里没有这些模块,DNS 解析就废了。程序里只要用到QNetworkAccessManager,我都不建议全静态,用-static-libgcc -static-libstdc++的半静态方案最合适。如果必须全静态,考虑用 musl 工具链替代 glibc,那是另一套体系,本手册不展开。

第二个坑是只拷二进制不拷数据。静态编译只解决了代码依赖,不解决数据依赖。字体、图片、QSS、QML、翻译文件、配置文件,统统不会自动进来。要么用.qrc资源系统,要么在部署清单里逐项核对。我在项目里吃过这个亏——程序在编译机 qemu 下跑得好好的,上板后界面空白,查了半天发现是字体文件没拷过去。

第三个坑是 configure 参数没有存档。交叉编译最怕的是过两个月要重编一次,却想不起来当时用了哪些参数。我的习惯是把完整 configure 命令写成一个build-qt-aarch64.sh脚本,放到 Qt 源码目录外面,随时可以重新执行。换 Qt 版本时,把脚本里的版本号改一下,拿 diff 做对比,比翻笔记靠谱得多。

最后再分享一个这些年养成的习惯:每次构建都是在同一个干净目录里进行,不依赖~/.bashrc里的环境变量。交叉编译本来变量就多,把编译环境固化在脚本里,才能保证换台电脑也能一键重建。这套 Qt 5.14.2 静态交叉编译的环境,我现在基本能做到从零到出可执行文件,全程不用手动干预。按这份手册走一遍,你也能把“部署 Qt 程序”这件事,从最头疼的环节变成最放心的环节。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 3:22:40

腾讯云AIGC短漫剧全链路方案:从剧本到成片的实战拆解

腾讯云的AIGC短漫剧方案最近在行业里讨论度很高&#xff0c;很多做短剧、漫剧、甚至动画番剧的团队都在关注。说实话&#xff0c;市面上讲AI视频生成、讲大模型应用的文章已经很多了&#xff0c;但真正把“从剧本到成片”的全链路打通、并且拿出真金白银的成本账来聊的&#xf…

作者头像 李华
网站建设 2026/9/19 3:20:59

AI驱动的游戏出海增长:从买量优化到专属语言引擎实践

过去几年&#xff0c;我踩过最深的坑&#xff0c;就是把“游戏出海”这四个字理解成“把游戏翻译成外语再买量”。直到项目数据连续三个月原地踏步&#xff0c;我才真正意识到&#xff0c;出海的瓶颈从来不是预算不够&#xff0c;而是买量的边际效率在肉眼可见地衰减&#xff0…

作者头像 李华
网站建设 2026/9/19 3:20:55

读书笔记App开发实战:Room表结构、防抖保存与FTS检索

简介&#xff1a;一份基于Android平台的读书笔记App毕业设计论文文档&#xff0c;面向高校计算机专业学生与Android开发初学者&#xff0c;采用Java语言开发设计&#xff0c;解决了传统Web应用只能在PC机上使用、无法随时随地阅读的问题。文档从选题背景、研究现状出发&#xf…

作者头像 李华
网站建设 2026/9/19 3:19:32

Gatsby 与内容分发网络(CDN):原理、收益与实战部署指南

Gatsby 与内容分发网络&#xff08;CDN&#xff09;&#xff1a;原理、收益与实战部署指南 【免费下载链接】gatsby React-based framework with performance, scalability, and security built in. 项目地址: https://gitcode.com/gh_mirrors/ga/gatsby 内容分发网络&a…

作者头像 李华