ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

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

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 MBstrip 之后会小一些和编译时间长全量编译一两个小时很正常。对“部署简单、环境干净”有硬要求的项目这笔交换是值的。1.3 这套手册适合谁严格来说这套流程适合三类人第一类目标是 ARM64 Linux 板子板子跑精简 rootfs没有条件装 Qt 运行环境第二类程序功能相对固定不需要在板子上频繁加载外部 Qt 插件也不需要做动态更新的二次开发第三类做交付型项目希望把“环境搭建”这个不可控因素从交付清单里划掉的人。反过来如果你需要在板子上长期做二次开发每次改代码都重新全量编译一个几十 MB 的静态程序或者你的程序要按设备动态加载第三方插件那还是老老实实走动态方案。静态不是银弹它是用编译期的复杂换运行期的简单。2. 开始前的环境准备主机、工具链与 sysroot2.1 主机环境与基础软件我这套流程在 Ubuntu 20.04 x86_64 上完整验证过18.04 也可以再老的版本建议先升级。主机先装基础工具sudo apt update sudo apt install -y build-essential perl wget gitbuild-essential提供宿主机的gcc、g、makeQt 的 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-gcc和aarch64-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 rootboard_ip:/lib/ ./sysroot/lib/ rsync -avz rootboard_ip:/usr/lib/ ./sysroot/usr/lib/ rsync -avz --safe-links rootboard_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是核心必须留qtserialport、qtsvg、qtimageformats这类轻量的按需保留qtwebengine、qtwebview、qt3d、qtcharts、qtdatavis3d、qtmultimedia、qtscript、qtvirtualkeyboard、qtwayland这套重模块没有明确需求就直接-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 命令把前面的决策落到命令上完整配置如下。先创建安装目录再执行 configuresudo 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-pcreconfigure 跑完会输出一大段检测结果。重点看这几个字段FreeType: yes (bundled copy)、FontConfig: no、ICU: no、Xcb: 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 ~/hellohello.pro文件QT core gui widgets CONFIG static TARGET hello TEMPLATE app SOURCES main.cpp QTPLUGIN qlinuxfb qoffscreen qminimalmain.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 -latomiclibatomic是 aarch64 上比较常见的一个隐藏依赖某些原子操作需要它很多人第一次编完 Qt 却在链接 app 时翻车基本都是这个原因。关于最终链接方式这里说清楚三种选择。第一种是“Qt 静态 系统库动态”也就是默认行为不额外加链接参数Qt 的.a会进入二进制而 libc、libstdc 保持动态链接。第二种是半静态在.pro里加QMAKE_LFLAGS -static-libgcc -static-libstdc把 C/C 运行库也打成静态只剩 glibc 的动态部分。第三种是全静态加QMAKE_LFLAGS -staticglibc 也静态链入。全静态看起来最美但 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 MBstrip 之后能压到 8~15 MBaarch64-linux-gnu-strip hello ls -lh hello这个体积在大容量 SD 卡或 eMMC 上完全不是问题。如果你后续要追求极致体积可以再研究 UPX 压缩但生产环境我并不推荐 UPX它会拖慢程序启动节省的那几 MB 不值得。6. 部署到目标板从拷贝到稳定运行6.1 最简单的部署命令部署其实就是传一个文件过去scp hello rootboard_ip:/home/root/ ssh rootboard_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 offscreenlinuxfb 在 qemu 下没有/dev/fb0可用。7. 常见问题与排查技巧实录7.1 高频错误速查表这套流程跑了很多次真正高频的报错就那几十个。整理成速查表按出现频率排序报错信息原因处理办法cannot find -latomic或cannot find -lglib-2.0sysroot 缺少对应静态库安装跨平台库包如libatomic1-arm64-crossglib 系库若没必要就-no-glib关掉unknown module(s) in Qt: serialportconfigure 时跳过了 qtserialport或者使用的 Qt 构建里没有该模块不要-skip对应模块重新构建qtserialport是库模块静态链接后直接在.pro里QT serialport即可Could not find the Qt platform plugin linuxfb静态构建下平台插件未链入可执行文件在源码里Q_IMPORT_PLUGIN(QLinuxFbIntegrationPlugin)并在.pro里加QTPLUGIN qlinuxfbcannot find -lGLOpenGL 相关功能开启但 sysroot 没有 libGL确认 configure 带-no-opengl确有需要时给 sysroot 装 mesa aarch64 静态库qmake: ELF 64-bit LSB executable, x86-64但libQt5Core.a也是 x86-64-platform和-xplatform传反用-platform linux-g -xplatform linux-aarch64-gnu-g重配error: cannot run C compiler或 configure 中途退出缺少宿主机构建环境或交叉工具链未装安装build-essential与g-aarch64-linux-gnumake: 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 程序”这件事从最头疼的环节变成最放心的环节。
返回列表