
1. 为什么非得自己搭 Qt 5.14.2 aarch64 静态交叉编译环境——多数人踩坑的起点你手头有一块基于 aarch64 架构的嵌入式板子比如 RK3399、Hi3559A 或者飞腾 D2000 的国产化平台客户明确要求软件必须“扔过去就能跑”不依赖目标机上任何 Qt 动态库连 libc 都得尽量静态链接。这时候你点开 Qt 官网下载页发现官方只提供 x86_64 Linux/macOS/Windows 的预编译安装包aarch64没有。再搜“Qt aarch64 交叉编译”满屏是“Ubuntu 20.04 安装 qt 交叉编译环境”这类标题党教程点进去一看全是拿现成的qt5-default或qtbase5-dev包糊弄根本不是交叉编译更别提静态链接了。我去年在给某电力终端做 HMI 升级时就卡在这一步——客户现场不允许联网也不允许拷贝几十 MB 的.so文件到板载 Flash所有依赖必须打进一个二进制里。当时试了三种方案第一种用 Linaro 提供的 aarch64-linux-gnu-gcc 工具链直接./configure报错说找不到qmake第二种照着 Qt 官方文档跑./configure -xplatform linux-aarch64-gnu-g结果卡在libxcb依赖上提示xcb_xkb找不到头文件第三种干脆放弃静态用linuxdeployqt打包动态库结果目标机上glibc版本比编译机低半级一运行就symbol lookup error。这三轮折腾下来我意识到问题根本不在于“会不会编译”而在于整个构建链条里有至少五个关键环节被绝大多数教程刻意绕开了工具链 ABI 兼容性、XCB 插件的静态构建路径、Qt 模块依赖图的显式裁剪、-static-libgcc/-static-libstdc与-static的协同关系、以及最关键的——qmake本身必须由交叉编译环境生成而不是宿主机上的那个。这不是一个“改几行命令就能过”的问题而是一整套需要从底层重连的信任链。你看到的“Qt 5.14.2 aarch64 静态交叉编译”这个标题背后其实是对嵌入式交付底线的一次硬性确认二进制零依赖、启动无报错、闪存占用可控。它解决的不是“能不能编译出来”而是“能不能在客户现场第一台设备上不改一行代码、不换一个库就稳定运行三年”。2. 工具链选型为什么必须用 crosstool-ng 自建而不是直接用 Linaro 或 ARM 官方包很多人一上来就去下载gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz这类现成包觉得“大厂出品应该稳”。实测下来这是整个流程里第一个也是最隐蔽的雷区。Linaro 提供的工具链默认启用--enable-default-pie位置无关可执行文件而 Qt 5.14.2 的 configure 脚本在检测g时会尝试编译一个 PIE 测试程序如果失败就直接退出错误信息却是模糊的C compiler cannot create executables。你翻遍日志也找不到pie这个词最后只能靠strace抓系统调用才定位到execve(/path/to/aarch64-linux-gnu-g, [aarch64-linux-gnu-g, -pie, ...])返回ENOENT—— 因为你的目标机内核不支持CONFIG_ARM64_UAO压根不认 PIE 指令。这个问题在 Qt 5.15 里被修复了但 5.14.2 就是死结。另一个更致命的问题是 C 库选择。Linaro 包默认用glibc而很多工业级 aarch64 板子比如 NXP i.MX8 系列出厂固件用的是musl libc或精简版glibc两者 ABI 不兼容。你用 Linaro 工具链编译出的二进制哪怕静态链接了 Qt只要调用了getaddrinfo()这类网络函数运行时就会因为glibc的 NSSName Service Switch模块缺失而卡死。我见过最离谱的案例是同一个二进制在开发板上./app正常启动但一插上网线就Segmentation fault调试发现是glibc尝试加载/usr/lib/libnss_files.so.2失败后触发了野指针。所以我坚持用crosstool-ng从源码构建工具链核心就为控制三个参数C 库类型强制指定CT_LIBC_musly这样生成的工具链天然适配大多数嵌入式场景且musl的静态链接行为比glibc更干净PIE 支持关闭CT_ENABLE_PIE确保所有输出都是传统 ELF 格式浮点 ABI根据你的 CPU 明确设为CT_ARCH_FLOAT_ABI_HARDVFP/NEON或CT_ARCH_FLOAT_ABI_SOFTFP软浮点避免__aeabi_dadd符号未定义。具体操作分四步走# 第一步安装 crosstool-ngUbuntu 20.04 sudo apt install -y gawk bison flex gperf texinfo help2man \ python3 python3-dev libncurses5-dev libexpat-dev wget https://crosstool-ng.github.io/download/crosstool-ng/crosstool-ng-1.25.0.tar.bz2 tar -xjf crosstool-ng-1.25.0.tar.bz2 cd crosstool-ng-1.25.0 ./configure --prefix/opt/ct-ng make sudo make install # 第二步初始化配置以 aarch64-musl 为例 /opt/ct-ng aarch64-unknown-linux-musl cp /opt/ct-ng/share/doc/crosstool-ng/samples/aarch64-unknown-linux-musl/crosstool.config .config # 第三步关键参数修改用 sed 批量处理避免手动编辑出错 sed -i s/CT_ENABLE_PIEy/CT_ENABLE_PIEn/ .config sed -i s/CT_ARCH_FLOAT_ABIsoft/CT_ARCH_FLOAT_ABIhard/ .config sed -i s/CT_GLIBC_VERSION2.33/CT_MUSL_VERSION1.2.3/ .config # 第四步构建耗时约 40 分钟CPU 占满 ct-ng build构建完成后工具链路径是/opt/x-tools/aarch64-unknown-linux-musl里面bin/目录下有aarch64-unknown-linux-musl-gcc等全套工具。注意这个路径必须加入PATH且后续所有 Qt 编译步骤都必须在这个 shell 环境中执行否则qmake会偷偷调用宿主机的gcc。我建议写一个env-aarch64.sh脚本#!/bin/bash export PATH/opt/x-tools/aarch64-unknown-linux-musl/bin:$PATH export CCaarch64-unknown-linux-musl-gcc export CXXaarch64-unknown-linux-musl-g export ARaarch64-unknown-linux-musl-ar export RANLIBaarch64-unknown-linux-musl-ranlib export STRIPaarch64-unknown-linux-musl-strip export PKG_CONFIG_PATH/opt/x-tools/aarch64-unknown-linux-musl/lib/pkgconfig export PKG_CONFIG_SYSROOT_DIR/opt/x-tools/aarch64-unknown-linux-musl每次开始工作前source env-aarch64.sh。这个脚本不是可选项是保命符——我曾因忘记source让configure误用宿主机pkg-config找到了 x86_64 的libxcb结果编译出来的qmake在 aarch64 上直接Illegal instruction。提示不要试图用--sysroot参数替代PKG_CONFIG_SYSROOT_DIR。pkg-config在交叉编译时会自动拼接--sysroot路径但 Qt 的configure脚本内部调用pkg-config时并不传这个参数导致它永远在宿主机路径里找库。只有设置PKG_CONFIG_SYSROOT_DIR才能真正隔离。3. XCB 插件的静态化Qt GUI 程序能跑起来的唯一钥匙如果你跳过这一步直接./configure -static最终生成的qmake会告诉你“No QPA platform plugin enabled”然后你的程序启动就是黑屏或直接退出。原因很简单Qt 5.14.2 默认 GUI 后端是xcb而xcb不是 Qt 自带的它是一个独立的第三方库必须由你手动编译并链接进去。网上所有“一键编译 Qt 静态库”的教程90% 都在这里栽跟头——它们要么完全忽略 XCB要么只编译了libxcb.so动态库结果静态链接时ld报undefined reference to xcb_connect。XCB 的静态化不是简单make install就完事它有三层依赖必须全部静态化依赖层级库名静态化关键点常见错误第一层libxcb必须禁用--enable-xinput输入设备扩展否则依赖libXi而libXi在 aarch64 下几乎无静态包configure通过但make时找不到Xi.h第二层libxcb-xkb必须显式启用--enable-xkb且xkbcommon必须先静态编译qmake检测到xcb但找不到xcb_xkbGUI 无法处理键盘事件第三层libxkbcommon必须用--without-wayland编译否则引入wayland-client依赖而 Wayland 在嵌入式板子上基本不用链接时出现undefined reference to wl_display_connect实操步骤如下全部在env-aarch64.sh激活的环境下执行# 1. 编译 xkbcommon基础依赖 wget https://xkbcommon.org/download/libxkbcommon-1.4.1.tar.xz tar -xf libxkbcommon-1.4.1.tar.xz cd libxkbcommon-1.4.1 ./configure --hostaarch64-unknown-linux-musl \ --prefix/opt/x-tools/aarch64-unknown-linux-musl \ --without-wayland \ --disable-wayland \ --disable-docs \ --enable-static \ --disable-shared make -j$(nproc) sudo make install cd .. # 2. 编译 xcb核心库 wget https://xcb.freedesktop.org/dist/libxcb-1.15.tar.xz tar -xf libxcb-1.15.tar.xz cd libxcb-1.15 # 关键禁用所有扩展只留最简 core ./configure --hostaarch64-unknown-linux-musl \ --prefix/opt/x-tools/aarch64-unknown-linux-musl \ --disable-dependency-tracking \ --disable-silent-rules \ --enable-xkb \ --disable-xinput \ --disable-xprint \ --disable-xinerama \ --disable-xfixes \ --disable-xrandr \ --disable-xrender \ --disable-xtest \ --disable-xv \ --disable-xvmc \ --enable-static \ --disable-shared make -j$(nproc) sudo make install cd .. # 3. 编译 xcb-xkb键盘支持 wget https://xcb.freedesktop.org/dist/xcb-proto-1.15.2.tar.xz tar -xf xcb-proto-1.15.2.tar.xz cd xcb-proto-1.15.2 ./configure --prefix/opt/x-tools/aarch64-unknown-linux-musl make sudo make install cd .. # 4. 最后编译 xcb-util可选但推荐修复部分字体渲染问题 wget https://xcb.freedesktop.org/dist/xcb-util-0.4.0.tar.gz tar -xf xcb-util-0.4.0.tar.gz cd xcb-util-0.4.0 ./configure --hostaarch64-unknown-linux-musl \ --prefix/opt/x-tools/aarch64-unknown-linux-musl \ --enable-static \ --disable-shared make sudo make install完成之后验证 XCB 是否真正可用# 检查 pkg-config 是否能返回静态库路径 aarch64-unknown-linux-musl-pkg-config --static --libs xcb xcb-xkb xkbcommon # 正常输出应类似 # -L/opt/x-tools/aarch64-unknown-linux-musl/lib -lxcb -lxcb-xkb -lxkbcommon -lXau -lXdmcp # 检查头文件是否就位 ls /opt/x-tools/aarch64-unknown-linux-musl/include/xcb/ # 必须有 xcb.h, xcb_xkb.h, xkbcommon.h 等注意xcb-util的--enable-static参数必须显式加上否则make install只会安装头文件不会生成libxcb-util.a。我曾因此浪费两天——qmake检测通过但链接时ld找不到xcb_change_property符号因为xcb-util的静态库根本没生成。4. Qt 5.14.2 源码的精准裁剪与 configure 参数详解Qt 官网下载的qt-everywhere-src-5.14.2.tar.xz有 1.2GB解压后 4.3GB里面包含 WebEngine、Quick3D、WebChannel 等 37 个模块。如果你不做任何裁剪就./configure -static编译时间超过 12 小时最终生成的libQt5Core.a会达到 80MB而你的目标板子 Flash 可能只有 256MB。更糟的是很多模块如qtwebengine根本无法在 aarch64 交叉编译环境下构建会卡在 Chromium 的 GN 构建系统里。所以裁剪不是可选项是交付前提。我的裁剪原则是“三不原则”不编译、不链接、不部署。具体到模块层面绝对禁用qtwebengine,qtwebchannel,qtwebsockets,qt3d,qtquick3d,qtspeech,qtlocation,qtmultimedia—— 这些模块要么依赖 OpenGL ES 3.0老板子只支持 2.0要么需要 Python 3.7交叉编译环境里 Python 是 3.6要么引入libffmpeg这种巨无霸依赖。有条件启用qtserialport串口通信、qtcharts数据图表、qtsvg矢量图—— 这些模块体积小、依赖少但必须显式添加-I和-L参数指向你已编译的静态库。必须保留qtbase,qtdeclarativeQML 支持,qttoolsqmake和moc工具,qtxmlpatternsXML 解析—— 这是 GUI 程序的骨架。configure命令不是一行能写完的我把它拆成三段环境变量 一行主命令确保每个参数都有据可依# 环境变量段必须在 configure 前设置 export QT_QMAKE_TARGET_MKSPEClinux-aarch64-gnu-g export QT_HOST_PATH/opt/qt-host # 宿主机 Qt 路径用于 moc/uic 工具 export PKG_CONFIG_PATH/opt/x-tools/aarch64-unknown-linux-musl/lib/pkgconfig # 主 configure 命令关键参数逐条解释 ./configure \ -static \ # 核心生成静态库 -release \ # 关闭调试符号减小体积 -no-exceptions \ # 嵌入式环境禁用异常处理省 3% 体积 -no-rpath \ # 静态链接不需要 rpath -no-openssl \ # 若无需 HTTPS彻底禁用 OpenSSL否则需额外编译 -no-dbus \ # 无 D-Bus 总线禁用除非你真要用 -no-opengl \ # 禁用 OpenGL用 raster 渲染器兼容性最好 -opengl es2 \ # 如果板子支持 OpenGL ES 2.0用这个代替上一行 -platform linux-aarch64-gnu-g \ # 指定交叉编译平台 -xplatform linux-aarch64-gnu-g \ # 同上双保险 -device-option CROSS_COMPILEaarch64-unknown-linux-musl- \ # 工具链前缀 -prefix /opt/qt-aarch64-static \ # 安装路径 -extprefix /opt/qt-aarch64-static \ # 导出路径 -hostprefix /opt/qt-host \ # 宿主机工具路径 -no-feature-style-windows \ # 禁用 Windows 风格减小 Core 库 -no-feature-style-fusion \ # 禁用 Fusion 风格 -no-feature-textmarkdownreader \ # 禁用 Markdown 解析 -skip qtwebengine \ # 跳过 WebEngine -skip qtwebchannel \ # 跳过 WebChannel -skip qtwebsockets \ # 跳过 WebSockets -skip qt3d \ # 跳过 3D -skip qtspeech \ # 跳过语音 -nomake examples \ # 不编译示例 -nomake tests \ # 不编译测试 -no-sql-db2 -no-sql-ibase -no-sql-oci -no-sql-tds -no-sql-db2 \ # 只留 sqlite -sql-sqlite \ # 启用 SQLite -I /opt/x-tools/aarch64-unknown-linux-musl/include \ # XCB 头文件路径 -L /opt/x-tools/aarch64-unknown-linux-musl/lib \ # XCB 库路径 -l xcb -l xcb-xkb -lxkbcommon -lXau -lXdmcp \ # 显式链接 XCB 静态库 -fontconfig \ # 启用字体配置重要否则中文乱码 -system-freetype \ # 用系统 freetype已静态编译 -system-harfbuzz \ # 用系统 harfbuzz已静态编译 -no-feature-cups \ # 禁用打印 -no-feature-alsa \ # 禁用音频 -no-feature-glib \ # 禁用 GLib避免引入 glib 依赖 -no-feature-gstreamer \ # 禁用 GStreamer -no-feature-libproxy \ # 禁用代理 -no-feature-icu \ # 禁用 ICU用 Qt 自带 Unicode -no-feature-evdev \ # 禁用 evdev触摸屏用 tslib -no-feature-tslib \ # 如果不用 tslib禁用 -no-feature-libudev \ # 禁用 udev -no-feature-libinput \ # 禁用 libinput -no-feature-libjpeg \ # 用系统 libjpeg-turbo已静态编译 -no-feature-libpng \ # 用系统 libpng已静态编译 -no-feature-libtiff \ # 禁用 TIFF -no-feature-libwebp \ # 禁用 WebP -no-feature-gif \ # 禁用 GIF -no-feature-svg \ # 禁用 SVG除非你启用了 qtsvg -no-feature-openssl \ # 再次强调禁用 OpenSSL -no-feature-bearssl \ # 禁用 BearSSL -no-feature-mbedtls \ # 禁用 mbedTLS -no-feature-warnings-are-errors \ # 编译警告不中断 -v \ # 显示详细日志排错必备 -confirm-license \ # 自动确认许可证 -opensource这个命令里最易被忽视的是-fontconfig和-system-freetype。很多教程说“禁用 fontconfig”结果编译出来的程序在板子上显示中文全是方块。fontconfig是字体发现和匹配的核心它告诉 Qt “这个中文字体文件在哪里、支持哪些字符集”。而-system-freetype则确保 Qt 使用你静态编译的freetype库来解析字体文件而不是依赖目标机上的动态库。我测试过去掉-fontconfigQFontDatabase::families()返回空列表加上它再配合-system-freetype中文、日文、韩文都能正常渲染。注意-opengl es2和-no-opengl不能同时存在。如果你的板子 GPU 支持 OpenGL ES 2.0比如 Mali-T860用-opengl es2能获得 3 倍以上的绘图性能如果不支持比如纯 CPU 渲染的 Cortex-A53必须用-no-opengl并确保-qpa eglfs或-qpa linuxfb可用。Qt 5.14.2 的eglfs后端需要libEGL和libGLESv2这两个库必须由你的 SoC 厂商提供不能自己编译。5. 静态链接的终极验证从qmake到最终二进制的全链路检查make make install成功后你以为就结束了不这才是真正考验的开始。很多开发者在此刻松一口气把生成的libQt5Core.a拷到项目里qmake一下就提交结果客户现场一运行./myapp: error while loading shared libraries: libQt5Core.so.5: cannot open shared object file—— 明明是静态编译怎么还找动态库答案是你的qmake本身是动态链接的或者你的项目pro文件里写了QT widgets却没指定CONFIG static。验证必须分三层进行5.1 第一层检查qmake本身的静态性进入/opt/qt-aarch64-static/bin目录运行file qmake # 正常输出qmake: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), statically linked, BuildID[sha1]..., for GNU/Linux 3.7.0, stripped readelf -d qmake | grep NEEDED # 正常输出空没有任何 NEEDED 动态库如果file qmake显示dynamically linked说明qmake编译时没用上你自建的工具链或者configure时漏了-static。此时必须回到 Qt 源码目录make clean重新configure。5.2 第二层检查 Qt 静态库的符号完整性Qt 的静态库不是简单打包它按模块分割libQt5Core.a里只放 Core 模块的符号libQt5Widgets.a放 Widgets 的但 Widgets 依赖 Core所以链接时必须按顺序libQt5Widgets.a libQt5Core.a。用nm检查关键符号是否存在# 检查 Core 库是否包含 QObject 构造函数 aarch64-unknown-linux-musl-nm -C libQt5Core.a | grep QObject::QObject # 正常输出0000000000000000 T QObject::QObject(QObject*) # 检查 Widgets 库是否包含 QWidget 构造函数 aarch64-unknown-linux-musl-nm -C libQt5Widgets.a | grep QWidget::QWidget # 正常输出0000000000000000 T QWidget::QWidget(QWidget*, QFlagsQt::WindowType)如果grep无输出说明该模块没被正确编译进静态库或者configure时-skip了不该跳过的模块。5.3 第三层检查最终应用二进制的零依赖性这才是交付前的最后一道闸门。假设你的项目叫hmi-apppro文件里必须有CONFIG static QT core widgets gui network serialport # 注意这里不能写 QT webengine否则链接器会去找 libQt5WebEngineCore.so编译后用file和ldd检查# 编译 /opt/qt-aarch64-static/bin/qmake hmi-app.pro make # 检查二进制属性 file hmi-app # 必须显示ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), statically linked # 检查动态依赖对静态二进制ldd 应该报错 ldd hmi-app # 正常输出not a dynamic executable # 检查实际链接的库确认 Qt 符号存在 aarch64-unknown-linux-musl-readelf -d hmi-app | grep NEEDED # 正常输出空没有任何 NEEDED但光这些还不够。我遇到过最诡异的案例是file和ldd都显示静态但一运行就Segmentation fault。用gdb调试发现崩溃点在QApplication构造函数里调用xcb_connect而xcb_connect的符号在libQt5Gui.a里但libQt5Gui.a依赖libxcb.a而libxcb.a里又依赖libXau.a和libXdmcp.a—— 这两个库你可能忘了静态编译所以最终检查必须用readelf -d查看所有依赖库# 查看 hmi-app 实际链接了哪些静态库 aarch64-unknown-linux-musl-readelf -S hmi-app | grep \.a # 输出应包含libQt5Core.a, libQt5Gui.a, libQt5Widgets.a, libxcb.a, libXau.a, libXdmcp.a, libxkbcommon.a如果缺了libXau.a立刻回去编译libXauwget https://ftp.x.org/pub/individual/lib/libXau-1.0.11.tar.bz2 tar -xf libXau-1.0.11.tar.bz2 cd libXau-1.0.11 ./configure --hostaarch64-unknown-linux-musl \ --prefix/opt/x-tools/aarch64-unknown-linux-musl \ --enable-static \ --disable-shared make sudo make install经验每次新增一个第三方静态库如libXau必须重新运行一遍 Qt 的configure因为configure会缓存pkg-config的结果。直接make不会重新检测新库。正确的做法是make confclean然后重新./configure ...再make。6. 实战避坑指南那些文档里绝不会写的 7 个致命细节我把过去两年在 5 个不同 aarch64 平台上踩过的坑浓缩成 7 条血泪经验。每一条都对应一个真实故障且网上几乎找不到解决方案。6.1 坑一-static-libgcc和-static-libstdc必须加在QMAKE_LFLAGS里而不是LIBSQt 的configure脚本会把LIBS -static-libgcc当作普通链接库处理结果ld报错cannot find -lstatic-libgcc。正确做法是在qtbase/mkspecs/linux-aarch64-gnu-g/qmake.conf里追加QMAKE_LFLAGS -static-libgcc -static-libstdc否则即使你的二进制显示statically linked运行时仍可能因libstdc.so.6版本不匹配而崩溃。6.2 坑二qmake的QMAKE_CXXFLAGS会覆盖你设置的-O2必须用QMAKE_CXXFLAGS_RELEASE很多教程教你在pro文件里写QMAKE_CXXFLAGS -O2这会导致 Debug 和 Release 都用-O2Debug 版本失去调试信息。正确写法是QMAKE_CXXFLAGS_RELEASE -O2 -flto-fltoLink Time Optimization能让 LTO 在链接阶段优化跨模块调用实测可减少 12% 体积。6.3 坑三libxcb的xcb_xkb模块必须用--enable-xkb编译且xkbcommon必须在xcb之前安装xcb的configure脚本会检查xkbcommon头文件如果xkbcommon没装它就静默禁用xcb_xkb不会报错。结果qmake检测通过但运行时键盘事件全丢。验证方法aarch64-unknown-linux-musl-pkg-config --modversion xcb-xkb必须返回版本号。6.4 坑四-no-opengl不等于禁用所有 GPU 加速必须显式指定-qpa linuxfb如果你用-no-openglQt 默认用eglfs后端而eglfs依赖libEGL.so。正确做法是./myapp -qpa linuxfb # 或者在 pro 文件里加 QMAKE_TARGET_QPA linuxfblinuxfb直接操作/dev/fb0零依赖兼容性最好。6.5 坑五libfreetype的--with-harfbuzzauto会引入libharfbuzz.so必须强制--with-harfbuzznoHarfbuzz 是复杂文本整形引擎对中文影响不大但它的动态依赖会让你前功尽弃。编译freetype时./configure --hostaarch64-unknown-linux-musl \ --prefix/opt/x-tools/aarch64-unknown-linux-musl \ --enable-static \ --disable-shared \ --with-harfbuzzno \ --without-bzip2 \ --without-png \ --without-zlib6.6 坑六qmake生成的 Makefile 里QMAKE_LIBS可能漏掉libXdmcp.a必须手动补全有时qmake检测到libxcb但没检测到libXdmcp因为libxcb的.pc文件没声明这个依赖。打开Makefile找到QMAKE_LIBS行在末尾加上QMAKE_LIBS -L/opt/x-tools/aarch64-unknown-linux-musl/lib -lxcb -lxcb-xkb -lxkbcommon -lXau -lXdmcp6.7 坑七strip工具必须用交叉链的不能用宿主机的strip宿主机strip会破坏 aarch64 的 ELF 结构。必须用aarch64-unknown-linux-musl-strip --strip-unneeded hmi-app实测--strip-unneeded比-s更安全它只删调试符号和重定位信息不碰代码段。最后分享一个技巧编译完成后用size hmi-app查看各段大小。如果.text段超过 5MB说明你可能没禁用exceptions或rtti如果.data段超过 2MB检查是否启用了icu或openssl。一个精简的 Qt 5.14.2 静态 GUI 应用.text应该在 1.8~2.5MB 之间总大小含资源控制在 8MB 以内才能放进大多数嵌入式 Flash。