Qt 5.14.2 aarch64静态交叉编译实战:摆脱动态库依赖的完整指南

发布时间:2026/9/15 3:49:22
Qt 5.14.2 aarch64静态交叉编译实战:摆脱动态库依赖的完整指南 做嵌入式Linux图形界面开发的朋友大概率都有过这种经历在x86开发机上跑得好好的Qt程序交叉编译完丢到aarch64板子上一启动就报error while loading shared libraries: libQt5Core.so.5: cannot open shared object file接下来就是满世界拷so、改LD_LIBRARY_PATH、对比版本号一个晚上就这么耗过去了。为了彻底摆脱这种动态库依赖带来的部署噩梦我专门花时间把Qt 5.14.2的aarch64静态交叉编译环境从零搭建了一遍这篇手册就是把完整过程、关键配置、踩过的坑和最终取舍全部记录下来给后面需要做同样事情的人一份可以直接照着干的参考。1. 为什么需要静态交叉编译一个部署问题的复盘1.1 动态库部署的“连锁反应”有多痛先聊一个真实的场景。之前我负责一个ARM64平台的工业平板项目程序是基于Qt Widgets做的开发机上是Ubuntu x86_64编译时用的是aarch64交叉工具链Qt库也交叉编译成了动态库。一开始在开发板上联调没问题等到要批量部署到现场设备时问题接连不断每台设备的文件系统版本有差异有的缺libQt5Widgets.so.5有的缺libicuuc.so有的glibc版本偏老程序跑起来直接段错误。更麻烦的是动态链接的依赖是一棵“树”——QtCore依赖libpthread、libdl、libzQtGui又依赖freetype、png、jpeg、xcb等一大堆。你拷了主库还得把它的所有依赖库全部对齐稍有疏漏某个设备就是起不来。现场调试只能靠ldd一个个比对效率极低。1.2 静态编译为什么更适合嵌入式交付静态交叉编译就是在x86主机上用aarch64工具链把Qt库和应用代码全部编译成位置无关的机器码再把所有依赖进最终可执行文件里。出来的东西只有一个二进制拷到目标板上chmod x就能跑目标系统只需要有最基本的Linux内核和glibc实际上连glibc都建议静态链接进去这个后面细说。这带来的好处很明显部署成本接近于零一个文件搞定不需要维护so依赖树运行时性能更稳定不受目标板系统库版本影响调试现场问题时环境变量、LD_LIBRARY_PATH这些干扰因素全部消失。代价也不是没有可执行文件体积会从几个MB膨胀到二三十MB首次编译时间变长LGPL许可下若动态链接Qt可以不开放应用代码但静态链接Qt就需要考虑提供目标文件或采用商业授权。这一点在做商业项目时要提前和法务确认我这边因为是内部自用软件没有对外分发所以用静态编译没有法律障碍。1.3 什么时候不建议静态编译也不是所有场景都适合静态。比如你的产品有大量第三方插件机制需要运行时动态加载so那静态就把路堵死了再比如界面要用到OpenGL ES硬件加速并且部分GPU驱动库如Mali、PowerVR的用户态驱动本身只提供动态库硬要静态链接会出现符号冲突。这种场景建议只把Qt交叉编译成动态库配合固定工具链和统一rootfs交付比强行静态更省心。所以我的建议比较简单纯Widgets应用、逻辑层代码占大头、目标板系统环境混乱优先考虑静态涉及插件体系、GPU私有驱动、以及对体积特别敏感的老老实实做动态。2. 主机环境与交叉工具链的选型搭配2.1 推荐的主机构建环境静态交叉编译对主机的硬件要求不算高但磁盘和内存建议给够。我的构建机配置是i7-8700六核十二线程、32GB内存、Ubuntu 20.04 x86_64系统。Qt全模块编译时编译目录会占到20GB以上所以至少留出30GB空闲磁盘。Ubuntu 18.04到22.04我都试过20.04是踩坑最少的GCC版本、Python版本和autoconf工具链都比较合适。需要注意的是Qt 5.14.2的configure脚本依赖perl、python 2/3、make、g这些基础工具。装依赖时直接跑一遍sudo apt update sudo apt install build-essential perl python3 python \ libxkbcommon-dev libxcb1-dev libxcb-keysyms1-dev \ libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev \ libxcb-cursor0-dev libxcursor-dev libxrandr-dev \ libxi-dev libxext-dev libgl1-mesa-dev libts-dev \ libssl-dev pkg-config有的教程会让你把这些X11开发库全装上其实做纯aarch64嵌入式交叉编译时这些主机上的X11库只影响“是否能在主机上运行Qt工具”对最终交叉编译结果没有决定性作用。但装上能少很多configure阶段的探测错误省得它中途报“找不到xcb”直接退出。2.2 交叉工具链的两种选择与对比aarch64交叉工具链我试过两种各有优劣。第一种是Ubuntu官方源的gcc-aarch64-linux-gnu直接安装sudo apt install gcc-aarch64-linux-gnu g-aarch64-linux-gnu对应编译器是aarch64-linux-gnu-gcc版本随系统源走20.04上是GCC 9.3。优点是安装方便、glibc头文件齐全和Ubuntu的用户态天然兼容缺点是版本偏新如果目标板是老旧文件系统编译出的程序在目标板上可能因为目标板的glibc太老而出现版本符号不兼容。第二种是Linaro提供的GCC工具链可以精确选择GCC 7.5、8.3等版本。早期我用Linaro比较多因为那时候Ubuntu源里的aarch64工具链对Qt 5.14的某些模块兼容性不好。现在Ubuntu 20.04源的GCC 9已经相当稳定我就直接用apt源了。这里给个建议先用aarch64-linux-gnu-gcc -v确认工具链版本如果目标是树莓派、Jetson这类主流ARM64开发板直接apt装没问题如果是自己定制的rootfs且glibc版本低于2.28最好去Linaro或ARM官网下载与目标系统glibc匹配的工具链避免踩glibc符号版本的坑。2.3 验证工具链是否可用工具链装好后先写一个最普通的C程序验证交叉编译环境。// hello.c #include stdio.h int main(void) { printf(aarch64 cross toolchain works!\n); return 0; }然后执行aarch64-linux-gnu-gcc hello.c -o hello_aarch64 file hello_aarch64输出应该是hello_aarch64: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1看到ARM aarch64就说明工具链正常。如果这步都不通过后面Qt编译必然一堆编译错误先把工具链问题解决再继续。3. Qt 5.14.2源码的裁剪策略哪些模块该留哪些该扔3.1 源码获取与目录结构Qt的发布包要从官方下载或国内镜像站拉取我习惯用中科大镜像速度快很多wget https://mirrors.ustc.edu.cn/qtproject/archive/qt/5.14/5.14.2/qt-everywhere-opensource-src-5.14.2.tar.xz解压后目录里有qtbase、qtdeclarative、qtmultimedia、qtsvg、qtimageformats、qtquickcontrols、qtwebengine等几十个模块目录。这里必须说清楚qtbase是Qt整个体系的地基包含QtCore、QtGui、QtWidgets、QtNetwork这些最核心的库以及qmake、moc、rcc等工具其他模块都是在qtbase之上按需展开的。很多第一次做交叉编译的同学上来就./configure makeQt默认会尝试编译所有模块qtwebengine这一个模块就要编译几个小时还特别容易因为GCC版本问题中途失败。所以裁剪是第一门课。3.2 按业务需求裁剪模块我这次项目只用Qt Widgets和Qt Network顶层模块就只留qtbase再加一个qtsvg用来显示矢量图标可选。具体的做法是configure时用-skip参数跳过不需要的大模块。核心取舍原则不做QML/Qt Quick界面的qtdeclarative、qtquickcontrols、qtgraphicaleffects全部跳过这几个模块编译时间长且静态链接后体积很大不需要浏览器内核的qtwebengine一定要跳过它本身依赖Chromium交叉编译难度极大静态链接更是不现实不玩3D的qt3d、qtgamepad、qtwayland这些也skip掉多媒体的qmultimedia如果想用可以留但静态编译时gstreamer后端的动态加载机制会有点问题建议要么不用要么单独评估。每个模块的选择背后都是编译时间和最终体积的权衡。我这边实际只编qtbase和qtsvg从configure到make install大概40多分钟就完成了非常舒服。3.3 第三方库用Qt自带的还是系统的静态编译最头疼的问题之一就是第三方库。Qt的configure支持两种方式一种是用-system-zlib、-system-libpng这种方式链接系统里已有的第三方库另一种是用-qt-zlib、-qt-libpng这种方式使用Qt源码包内置的第三方库。在交叉编译场景下我强烈建议全部用-qt-系列让Qt使用源码自带的库。原因很简单你主机上apt装的那些libpng、libjpeg都是x86的交叉编译链接它们没有任何意义而去交叉编译一份aarch64的libpng、libjpeg、freetype又会引入新的构建配置问题。Qt源码目录里本身就包含这些库的交叉编译适配直接-qt-一把梭省心又可靠。至于OpenSSLQt 5.14的QtNetwork默认在configure时探测OpenSSL如果探测不到就退化为不支持https。如果程序需要访问https接口必须提前用aarch64工具链交叉编译一份OpenSSL静态库然后在configure里加-openssl-linked并指定头文件和库路径。这一步工作量不小建议确有必要时再做。3.4 特性裁剪no-icu、no-dbus、no-glib除了模块裁剪configure还支持按特性裁剪。Qt默认会启用ICU、DBus、GLib等一堆特性这些特性在嵌入式静态场景下基本都是负担ICU提供Unicode和本地化能力但体积巨大静态链接后光它就能吃掉15MB以上纯嵌入式界面根本用不上直接-no-icuDBus是Linux桌面环境下进程间通信的框架嵌入式单进程程序用不到-no-dbusGLib是GObject系统的基础库QtNetwork和QtDBus某些路径会依赖它静态编译时会导致大量符号冲突-no-glib。这三个参数切掉后configure阶段少了几个系统检测编译阶段也少了很多麻烦。4. configure与mkspec定制静态编译的核心一仗4.1 mkspec是什么为什么它如此重要mkspec是Qt的一套平台描述文件里面记录了编译器名、编译参数、链接参数、架构相关宏定义等。Qt源码自带的qtbase/mkspecs/linux-aarch64-gnu-g/目录里就有一份针对aarch64 Linux的工具链配置qmake会读取它生成Makefile。大多数情况下直接用这份现成的mkspec就够了。我在实际项目中只是打开qmake.conf确认了以下几点include(../common/linux.conf) include(../common/gcc-base-unix.conf) include(../common/g-unix.conf) QMAKE_INCDIR_LIBGCC QMAKE_LIBS_LIBGCC -L$$[QT_SYSROOT]/usr/lib/gcc/aarch64-linux-gnu -lgcc如果configure时指定了-sysrootqmake.conf里的路径会自动带上sysroot前缀。用apt的gcc-aarch64-linux-gnu时默认sysroot是/usr/aarch64-linux-gnuQt的工具链脚本会自动探测并适配一般不需要手动改。4.2 手动新建mkspec的完整步骤如果你用的是Linaro等非标准路径的工具链或者想自定义优化参数建议自己复制一份mkspec出来改成独立的这样以后换了Qt版本还能复用cp -r qtbase/mkspecs/linux-aarch64-gnu-g qtbase/mkspecs/linux-aarch64-static-g cd qtbase/mkspecs/linux-aarch64-static-g然后编辑qmake.conf把QMAKE_CC、QMAKE_CXX指向自己的编译器路径并追加静态编译参数QMAKE_CC /opt/toolchain/bin/aarch64-linux-gnu-gcc QMAKE_CXX /opt/toolchain/bin/aarch64-linux-gnu-g QMAKE_LINK /opt/toolchain/bin/aarch64-linux-gnu-g QMAKE_LINK_SHLIB /opt/toolchain/bin/aarch64-linux-gnu-g QMAKE_CFLAGS_RELEASE -Os -fno-exceptions -fno-rtti QMAKE_CXXFLAGS_RELEASE -Os -fno-exceptions -fno-rtti-Os是优化体积的选项对静态编译产物瘦身非常有效。-fno-exceptions和-fno-rtti是否能开取决于你的应用代码是否大量使用异常和RTTI如果是从头开发的项目建议直接开如果集成了第三方库先确认它们不依赖异常特性再开。4.3 configure参数的完整清单与含义我最终使用的configure命令长这样cd qt-everywhere-opensource-src-5.14.2 ./configure \ -prefix /opt/Qt5.14.2-aarch64-static \ -opensource -confirm-license \ -xplatform linux-aarch64-gnu-g \ -static \ -release \ -optimize-size \ -no-opengl \ -eglfs \ -linuxfb \ -qt-zlib -qt-libpng -qt-libjpeg -qt-freetype -qt-pcre \ -no-icu -no-dbus -no-glib \ -no-xcb -no-xkbcommon \ -skip qtwebengine -skip qtwebview -skip qtdeclarative -skip qtquickcontrols \ -nomake examples -nomake tests \ -no-compile-examples \ -no-feature-accessibility逐条解释一下关键项-static核心开关告诉Qt的配置和构建系统所有库编译成静态库.a连接时不做动态链接-xplatform linux-aarch64-gnu-g指定目标平台为aarch64上的GNU C编译器集合-prefix /opt/Qt5.14.2-aarch64-static安装目录。这个目录只在编译机上存在产物拷到目标机时不需要这个路径但qmake生成的链接脚本里会记录这个路径所以建议固定下来别改-release -optimize-size编译release版且优化目标为体积实测能比默认优化减少5%~10%的最终二进制体积-no-opengl关掉OpenGL模块。如果不涉及GPU硬件加速这个必须关否则configure会去探测EGL/GLES头文件找不到直接报错退出。注意-eglfs后的那行如果不开OpenGLeglfs实际也无法工作我之所以保留-eglfs是因为某些Qt模块构建脚本里检测到eglfs会多生成一些框架代码对后续扩展有利-linuxfb启用Linux Framebuffer平台插件这是嵌入式无桌面环境下最简单也最靠谱的显示后端-no-xcb -no-xkbcommon禁用X11相关支持嵌入式设备一般不跑X Server不关的话configure会去交叉探测xcb库大概率失败-no-feature-accessibility关掉辅助功能屏幕阅读器等能省内存和老代码里的回调处理。4.4 configure失败的高频原因与对策configure阶段最容易挂的地方是“qtbase的configure脚本在交叉检测时执行了它无法运行的测试程序”。Qt的configure在交叉编译时有两种检测模式编译后运行的测试会和交叉工具链冲突。典型报错是The test for linking against libxcb failed!或者ERROR: Feature system-xcb was enabled, but the pre-condition libs.xcb failed.这种问题90%的原因是configure探测时用了主机上不该用的库。对策就是前面说的把-no-xcb、-no-xkbcommon、-no-opengl这些不用的特性显式关掉别让configure去猜。另一个原因是sysroot路径不对可以用-sysroot /usr/aarch64-linux-gnu显式指定。还有个小技巧如果configure中途报错不要急着从头再来去config.log文件里看最后的报错信息它会显示是哪条测试命令失败根据命令内容判断是缺库还是路径问题比反复试错高效得多。5. 编译Qt库的完整命令与四个高频报错排查记录5.1 正式编译与安装configure通过之后编译就相对机械了。我一般用make -j$(nproc)八核机器上编译qtbaseqtsvg大约30分钟左右。如果内存小于8GB建议-j4而不是-j$(nproc)因为Qt在编译QObject派生类较多的模块时GCC的模板实例化和moc代码生成会吃大量内存物理内存不足时会直接OOM被杀报错信息还很迷惑往往只显示Killed。编译完成后安装到prefix目录make install安装完成后检查一下ls /opt/Qt5.14.2-aarch64-static/lib/如果能看到一堆.a文件比如libQt5Core.a、libQt5Gui.a、libQt5Widgets.a说明静态库构建成功。同时注意/opt/Qt5.14.2-aarch64-static/plugins/platforms/目录下应该有libqlinuxfb.a这样的静态平台插件库。5.2 四个高频编译报错及完整排查链路报错一找不到EGL/GLES头文件In file included from /path/to/qopengl.h:46:0, from /path/to/qwindow.h:45:0, from ... fatal error: EGL/egl.h: No such file or directory这个报错的本质是configure阶段没有真正关掉OpenGL模块某些源文件依然继承了OpenGL相关头文件。排查链路先用grep -r egl config.log确认configure检测EGL的结果再看Makefile里是否加了-DQT_NO_OPENGL宏。最直接的解决方法是回到configure阶段再加-no-opengl并且确保没有在命令行同时设置-opengl desktop或-opengl es2。报错二找不到xkbcommon头文件fatal error: xkbcommon/xkbcommon.h: No such file or directory这个通常是因为configure检测到某些库存在而开了xcb键盘支持但交叉编译头文件路径没有正确指向sysroot。排查时去qtbase/config.summary看QT_XKB_COMMON如果是auto状态且路径为空说明检测失败但后续构建流程仍然走了xcb分支。解决方法是configure时显式加-no-xkbcommon -no-xcb让Qt彻底不依赖X11生态。报错三libQt5Core.a链接阶段大量“undefined reference”undefined reference to pthread_once undefined reference to dlopen undefined reference to gzdopen这个问题一般出现在编译用户程序而不是编译Qt库本身时但如果你是在make install之后做验证编译时遇到就一起说了。本质是静态链接时链接器是按照目标文件顺序解析符号的而libQt5Core.a内部各目标文件互相引用之前动态链接时由动态加载器处理的符号静态链接时全部交给链接器处理导致缺少系统库。解决方法是给qmake生成的Makefile追加系统库LIBS -ldl -lpthread -lz -lm -lrt在.pro文件里写unix:!macx { LIBS -ldl -lpthread -lz -lm -lrt }报错四moc生成的C文件编译错误In file included from moc_xxx.cpp:10:0: fatal error: ../../include/QtCore/qobject.h: No such file or directory这个报错多发生在从源码编译一个应用的场景本质是include路径没有指向静态Qt的安装目录。解决方法是直接把Qt的bin目录加到PATH环境变量优先使用刚刚交叉编译出来的qmakeexport PATH/opt/Qt5.14.2-aarch64-static/bin:$PATHqmake会从自身的安装位置推导头文件和库文件路径只要prefix路径对这个报错不会再出现。5.3 问题排查汇总表现象根因解决方案configure阶段EGL检测失败开启了OpenGL但未安装交叉头文件configure加-no-opengl编译时找不到xkbcommon未显式禁用X11生态configure加-no-xcb -no-xkbcommon链接时undefined reference静态链接缺少系统库LIBS追加-ldl -lpthread -lz -lm -lrtmoc相关头文件找不到qmake没进PATH或prefix不对export PATH指向静态Qt的bin目录make时被Killed并行编译进程过多导致OOM降低-j并行数6. 应用工程静态链接要点QPA插件注册与链接选项6.1 为什么运行时会提示找不到platform pluginQt的架构里窗口系统后端被封装成QPA插件。动态编译时Qt在运行时去plugins/platforms目录加载libqlinuxfb.so静态编译时系统里没有这个so如果你在代码里不主动把插件静态注册进去程序启动会报This application failed to start because no Qt platform plugin could be initialized.这个问题排在静态Qt应用跑不起来原因的第一位几乎每个人都会遇到。解决办法是在main函数所在文件的头部加上插件导入声明#include QApplication #include QtPlugin Q_IMPORT_PLUGIN(QLinuxFbIntegrationPlugin) int main(int argc, char *argv[]) { QApplication app(argc, argv); // ... return app.exec(); }这行宏的作用是在当前目标文件里生成一段静态初始化代码强制链接器把libqlinuxfb.a里对应的目标文件链进最终可执行文件。因为静态库的默认行为是“用到哪个目标文件才链哪个”没有这行宏链接器看到没有代码引用linuxfb插件的符号就直接把它忽略了。6.2 .pro文件里如何配合有了上面的代码宏还需要在.pro文件里声明插件QT core gui widgets TARGET myapp TEMPLATE app QTPLUGIN qlinuxfb DEFINES QT_STATIC unix:!macx { LIBS -ldl -lpthread -lz -lm -lrt } SOURCES main.cppQTPLUGIN变量让qmake在链接时也把插件库加到库搜索路径和依赖列表里和源码里的Q_IMPORT_PLUGIN配合使用才能保证万无一失。DEFINES QT_STATIC是告诉Qt的头文件适配“静态编译模式”有些内联函数和导出宏在不同模式下定义不同少了这个宏可能遇到莫名其妙的编译错。6.3 链接器选项的进一步加固qmake生成的Makefile默认会加-static因为没有加全局静态的选项时qmake会根据configure阶段的-static参数自动处理。但保险起见我一般还会在.pro里追加QMAKE_LFLAGS -static-libgcc -static-libstdc这两个参数强制将GCC的运行库也静态链接进去避免目标板上缺少libstdc.so.6导致程序起不来。目标板的glibc版本如果足够新全静态链接不带动态glibc也可以但如果程序要调用NSS域名解析、getpwnam这类需要动态加载的系统功能建议保留glibc动态链接只把C运行库和Qt库静态进去。这个取舍要在稳定性和体积之间权衡我这边因为目标环境完全可控就全静态了。6.4 用file和readelf验证静态链接结果编译完成后不要急着拷贝先在主机上验证链接状态aarch64-linux-gnu-readelf -d myapp | grep NEEDED如果输出为空说明所有动态依赖都被去除了这是全静态成功的标志。还可以用file myapp看myapp: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked注意这里必须是statically linked。如果显示dynamically linked说明static参数没生效回去检查.pro里的QMAKE_LFLAGS和configure阶段的-static。还有一种半静态的情况Qt库是静态的但应用自身的第三方库是动态的。这时的readelf输出会显示依赖了某些so用ldd在目标板上也能看到。这种情况部署时依然要把第三方so带着不算真正的单文件交付。7. 目标板上验证运行与体积优化7.1 拷贝与运行编译得到的myapp直接拷贝到目标板任意目录赋予执行权限chmod x myapp ./myapp -platform linuxfb如果只有一个framebuffer设备也可以省略-platform linuxfb因为静态插件已经注册Qt默认会优先用编译进内核的插件。但为了明确问题建议首次运行时显式带上参数。如果程序起不来最常见的问题是framebuffer设备没有读权限export QT_QPA_FB_DRM1 # 某些内核版本需要 ./myapp -platform linuxfb:/dev/fb0另外在串口终端里运行Qt应用会看到一条告警QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to /tmp/runtime-root这个不是致命错误但会影响某些需要写配置文件的场景。在启动脚本里加上export XDG_RUNTIME_DIR/tmp/runtime-root mkdir -p $XDG_RUNTIME_DIR chmod 700 $XDG_RUNTIME_DIR就可以消除。7.2 体积的实测数据与优化手段我这次做的Widgets测试程序功能很简单一个主窗口、两个按钮、一个网络请求源码编译出来strip之前接近50MBstrip之后降到28MB左右。strip命令永远是体积优化的第一选择aarch64-linux-gnu-strip myapp第二选择是configure阶段的-optimize-size这个在编译时就已经生效了。第三选择是进一步开裁剪特性比如-no-feature-animation、-no-feature-printdialog这种按实际需求关掉不需要的Qt特性宏能再省2~3MB。UPX压缩我也试过aarch64版本的UPX可以把28MB压到9MB左右运行时在内存里解压。但嵌入式设备上有个风险UPX解压时可能触发不可执行内存页的保护机制部分内核含SELinux策略会直接拒绝运行。我帮客户项目的评估结果是稳定性优先级更高所以最终没有在生产环境用UPX。7.3 实际运行中的两个隐藏坑静态编译的程序在目标板上跑起来之后有两个隐藏坑容易忽略。第一个是时区与本地化。静态Qt默认只链接了C库的UTC时区如果你的业务界面需要显示本地时间必须在代码里调用qputenv(TZ, Asia/Shanghai); tzset();并且确保系统里有对应的时区数据文件一般是/usr/share/zoneinfo。第二个是字体。Qt的字体引擎在静态编译下不会自动扫描目标板所有字体目录如果你的程序显示中文乱码或方块检查一下目标板是否有中文字体文件或者直接在代码里指定字体路径QFontDatabase::addApplicationFont(/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc);说到最后静态交叉编译本身并没有太多黑魔法核心就是configure的-static、mkspec的编译器指向、QPA插件的静态注册这三板斧。但真正把所有步骤跑通并在实际项目中稳定运行确实需要在一堆报错信息里沉住气做排查。我自己在这一路踩坑过程中最大的体会是在configure阶段多花一点时间把平台参数、模块裁剪、第三方库策略全部理清后面编译和应用移植就会顺畅得多。如果你也是第一次搭aarch64的Qt静态编译环境建议就按这份手册的顺序走一遍只要每一步的输出都验证正确大概率一次就能跑通。