ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

aarch64静态交叉编译Qt5.14.2完全指南

aarch64静态交叉编译Qt5.14.2完全指南 1. 为什么aarch64静态交叉编译这么容易劝退先说个真实感受Qt的交叉编译资料其实不少但绝大多数都是讲动态编译——configure、make、install然后目标板上放一堆so文件最后靠LD_LIBRARY_PATH把程序拽起来。这套流程一旦跑通后面编译应用确实方便因为什么依赖都在目标板文件系统里躺着程序启动时按需加载就行。但是落地到真实产品动态方案经常让人头大。比如客户要求程序拷进板子就能跑不能有请先安装Qt运行库这种操作又比如做的是无人值守的Linux设备rootfs被精简到几十兆根本没有Qt目录的位置再比如内核升级后so路径变动原本能跑的程序一夜之间起不来。这时候静态编译就成了解药整个Qt库直接揉进可执行文件单文件拷贝、零依赖、跑哪算哪。静态交叉编译难在哪三个字全静态。默认情况下Qt主动加载一堆系统库libxcb、fontconfig、freetype、harfbuzz、glib这些一个都不能少而且它们也要静态版本才能和Qt真正抱死在一起。绝大多数工具链只带.so不带.a你configure的时候就会看到一行比一行多的skip和error最后干脆失败。这就是为什么网上Qt静态交叉编译的帖子年年有人写年年有人回帖说编译不过。我这次做的是Qt5.14.2在aarch64ARMv8 64位目标硬件上的静态交叉编译。选这个版本没有特别的理由5.14.2是Qt5时代在嵌入式领域口碑比较稳的版本补丁少、资料全而且它还保留着传统的qmake工程体系不强制走CMake对老项目的迁移成本极低。整套流程从零开始涉及工具链准备、sysroot构建、configure参数判定、依赖静态库处理、最终App验证每一步都是可以照着抄的。看完这篇文章你完全没必要再从零去踩一遍我踩过的坑。2. 动手前的选择题工具链和sysroot到底怎么搭先说结论aarch64静态编译的所有麻烦有一大半源自于工具链和sysroot不配对。工具链负责把代码编成机器码sysroot负责提供头文件和库文件如果这两个东西不是同一个体系生成的编译过程中各种找不到符号头文件不匹配的报错会把你活活耗死。2.1 工具链的三个来源怎么选发行版软件源直接装Ubuntu、Debian这些都有gcc-aarch64-linux-gnu、g-aarch64-linux-gnu包装完直接用。优点是省事缺点是它配套的sysroot来自libc6-dev-arm64-cross库版本普遍比较旧而且很多静态库libgcc.a、libstdc.a需要额外装libstdc-*-dev-arm64-cross这类包经常被人忽略。Buildroot产出Buildroot是嵌入式领域的老把式它能一次性帮你生成工具链加rootfs两者的兼容性有官方保证而且还可以顺手把tslib、sqlite、zlib这些第三方库一起编成静态版本。代价是Buildroot本身的学习曲线不低第一次跑要会配menuconfig下载源码也要点时间。Yocto SDKYocto生成的SDK带环境变量脚本source一下就能用兼容性同样很好但整个Yocto系统偏重只是为了交叉编译一个Qt去折腾Yocto性价比不高。我这次用的方案是Buildroot生成的工具链版本比较新gcc 9.x关键点在于它的sysroot里静态库非常齐全后面少掉好几轮缺这个缺那个的循环。如果你手头已经有能用的Linaro工具链也没问题但务必确认下面这点。提示动手之前先检查工具链的自带库是否完整尤其是$SYSROOT/usr/lib/aarch64-linux-gnu/目录下面有没有libgcc.a、libstdc.a、libc.a。没有的话后面编译几乎不可能成功。检查命令长这样aarch64-linux-gnu-gcc -print-sysroot拿到sysroot路径然后去lib目录里ls一遍。2.2 sysroot载体的取舍sysroot其实就是一块临时文件系统它决定了Qt configure时的系统环境。我强烈建议用目录型的sysroot而不是直接把整个SD卡/NFS根文件系统塞进来当sysroot理由很简单目录型sysroot干净不会误把板子上正在运行的进程或动态生成的临时文件当真库。交叉编译的配置和后续目标板镜像的制作可以解耦该往rootfs放什么、不该放什么你自己说了算。如果选择Buildroot生成出来的output目录下会有host/aarch64-buildroot-linux-gnu/sysroot/这个直接就能用来当--sysroot参数。如果自己手工收茅库那就新建一个/opt/aarch64-sysroot目录把目标板rootfs里的/usr/include、/usr/lib、/lib等内容往里复制注意保留符号链接别用cp -r把软链解开了否则到时候链接阶段一头的cannot find -lxxx。3. configure参数逐项拆解一个都不能少Qt5.14.2的configure脚本可以说是整个编译里最核心的一步。参数不是乱给的每一项都需要知道它解决什么问题。我给出的这套参数是实测跑通的下面把每个参数的目的讲清楚。3.1 完整参数清单cd qt5.14.2源码目录 ./configure \ -prefix /opt/qt-5.14.2-aarch64-static \ -xplatform linux-aarch64-gnu-g \ -sysroot /opt/aarch64-sysroot \ -static \ -release \ -opensource \ -confirm-license \ -nomake examples \ -nomake tests \ -skip qtlocation \ -skip qtwebengine \ -skip qtdeclarative \ -no-opengl \ -no-eglfs \ -no-gbm \ -qt-xcb \ -qt-freetype \ -qt-harfbuzz \ -qt-pcre \ -qt-zlib \ -qt-libpng \ -qt-libjpeg \ -qt-sqlite \ -no-feature-assistant \ -no-feature-designer \ -no-feature-qml-debug \ -no-feature-remoteobjects \ -no-feature-dbus3.2 逐项解释-prefix安装目录它不是目标板上的路径而是你本机上的路径交叉编译产物最后install到哪里由它决定。很多人误以为-prefix是目标板的安装位置导致编译完把整个Qt文件夹拷到板子上这是完全没有必要的。静态链接完成后程序身上已经带了Qt的一切这个prefix目录只是个中间仓库。-xplatform目标平台描述文件。Qt的源码里已经自带linux-aarch64-gnu-g这个mkspec但如果你的工具链前缀不是默认的aarch64-linux-gnu-就要去qtbase/mkspecs/里拷贝一份改成自己的前缀。我用Buildroot工具链时前缀是aarch64-buildroot-linux-gnu-所以我在mkspec里把QMAKE_CC、QMAKE_CXX、QMAKE_LINK都替换成了aarch64-buildroot-linux-gnu-gcc、aarch64-buildroot-linux-gnu-g。这一步不做Qt编出来的是x86版本掉进这个坑的人不少。-sysroot告诉编译器头文件和系统库去哪找。这个参数最终会以--sysroot的形式传给gcc。配了它你就不需要手动往-I和-L里硬塞路径编译器会自动去sysroot下的usr/include和usr/lib里找系统依赖。-static本次编译的核心开关直接决定Qt库以.a形式产出而不是.so。但它只对Qt自身的库生效第三方依赖xcb、fontconfig等能不能静态取决于你的sysroot里有没有.a文件。-release去掉调试符号生成体积更小的库。嵌入式设备存储空间本来就紧张这一步必须加。-opensource -confirm-licenseQt5.14.2还允许你选商用版还是开源版开源版协议主要是LGPL/GPL直白点说应用按LGPL要求动态链接也没问题但你已经静态编译了如果应用程序使用静态链接Qt而没有开源自有代码存在合规问题。不同产品策略需要自己评估这里我的做法是编译前由法务确认过静态链接的许可证风险你自己做产品也一定不要绕过这一步。-nomake examples -nomake tests不编译示例和测试代码。交叉编译要的是Qt库本身examples和tests只会白白消耗几个小时还可能因为缺少某些目标板特有的库而中断整个构建。-skip系列跳过不需要的Qt模块。qtwebengine体积巨大还牵涉到CEF/Chromium的交叉编译铁定编不动qtlocation、qtdeclarative这种如果你的产品用不上关了能省不少时间。注意千万不要skip掉qtbase那是核心中的核心。-no-opengl -no-eglfs -no-gbm如果你的目标板不是GPU渲染的完整桌面环境这些图形后端不开也罢。我这次的目标板是纯控制类设备UI只是简单仪表盘软件渲染绰绰有余。-qt-xcb这是重点让Qt自己编译一份xcb库进去。xcb是X Window系统的C接口库静态链接Qt要显示到Linux的X11桌面就必须把xcb打包进程序里。后面你会在链接时看到一大堆Qt5XcbQpa相关的依赖都是这里种下的因。-qt-freetype-qt-harfbuzz-qt-pcre-qt-zlib-qt-libpng-qt-libjpeg-qt-sqlite全部用Qt自带的第三方库版本不依赖宿主机。这是静态编译能够成功的关键因为系统自带的这些库不一定有静态版本而且版本差异容易引发诡异问题。全部走Qt源码自带的虽然编译时间多了十几分钟但稳定太多。-qt-sqlite强制使用内置SQLite方便后续程序直接操作本地数据库不用目标板再装一个SQLite。-no-feature系列裁剪Qt内部非必需的feature配置目的是减少编译时间和最终静态库体积。特别是qml-debug和dbus控制类设备里很多时候根本用不到系统总线砍掉之后libQt5Core.a的尺寸能小一圈。3.3 configure失败的对照排查表报错情况可能原因针对性解法ERROR: The host system is not supported编译器前缀不对或缺少xplatform检查mkspec里的QMAKE_CC写没写对Cannot run aarch64-linux-gnu-g工具链不在PATH里把工具链bin目录export进PATH并测试gcc -vThe specified sysroot does not existsysroot路径拼错用绝对路径不搞相对路径The test for linking against libxcb will failsysroot里缺xcb相关库检查libxcb库是否齐全或者暂时用-no-xcb只验证基本编译最后再加xcbNo such file or directory: libGL.so没装OpenGL开发文件既然不用OpenGL加上-no-opengl即可4. 静态依赖清单按图索骥才不会乱Qt configure阶段会做很多link测试缺少哪个静态库都会在测试环节直接暴露。提前按照这个清单把依赖库准备到位conigure一遍过。4.1 核心系统库在aarch64的sysroot里至少要有这些静态库.a文件libc.aC标准库libstdc.aC标准库libm.a数学库libdl.a动态加载接口虽然静态程序一般不需要但Qt有些模块会引用libpthread.a线程库注意新版glibc把pthread合并到了libc里但保险起见还是要检查存在性libgcc.agcc底层支持库如果你的工具链是Buildroot生成的这些基本都齐如果是系统包管理器装的建议执行一次下面这行补装sudo apt install libc6-dev-arm64-cross libstdc-10-dev-arm64-cross4.2 图形与字体相关静态Qt面向X11时核心依赖包括xcb、X11、fontconfig、freetype、harfbuzz。凡是展示文字的界面程序没有字体处理能力就是黑屏。Buildroot里选上x11r7/xcb-proto、x11r7/libxcb、fontconfig、freetype、harfbuzz并且编译成静态库然后整体生成sysroot。如果你自己手工准备记住编译这些库时CFLAGS和CXXFLAGS里要带-fPIC参数否则.a文件在链接到可执行文件时会出现relocation R_AARCH64_ADR_PREL_PG_HI21 against symbol ... can not be used when making a shared object这类错误。这个坑相当隐蔽因为报错在最后链接阶段不会提前预警。4.3 网络与压缩库很多嵌入式程序会用到openssl做HTTPS通信Qt的network模块在编译时如果检测到openssl会默认启用加密支持。如果目标设备不需要加密通信可以显式加-no-openssl跳过如果需要openssl也必须提供.a静态库或者干脆用Qt源码里的-openssl-linked配合编译好的libssl.a和libcrypto.a。此外zlib、libpng、libjpeg这些我们已经在configure里统一指定了-qt-*所以它们不再需要外部准备。这场编译里凡是-qt-开头的选项就意味着这个库的源码在Qt目录内已经有备份直接用就行。4.4 依赖检查的终极大法等待configure结束打开config.log搜一下error单词。如果configure某一步link测试失败日志里会非常明确地写出找不到哪个函数、哪个文件。这是排查漏库的第一现场。例如缺fontconfig时config.log里会出现类似undefined reference to FcInitLoadConfigAndFonts、checking for Fontconfig... no之类的内容。看到这个别慌去sysroot里补上fontconfig的.a和头文件重新configure。5. 正式编译从configure到install的完整实操5.1 环境变量——这是最容易被忽视的先手棋configure之前务必先把环境变量按下面设置好尤其不能漏掉PKG_CONFIG_SYSROOT_DIR和PKG_CONFIG_LIBDIR这兄弟俩。如果不设置pkg-config会读取宿主机你当前PC的.pc文件那些.pc文件里写的是x86的路径和版本号要么找不到要么找到一堆不相干的库。# 换成你自己的工具链路径和sysroot路径 export PATH/opt/buildroot/output/host/bin:$PATH export SYSROOT/opt/buildroot/output/host/aarch64-buildroot-linux-gnu/sysroot export CROSS_COMPILEaarch64-buildroot-linux-gnu- export CC${CROSS_COMPILE}gcc export CXX${CROSS_COMPILE}g export AR${CROSS_COMPILE}ar export LD${CROSS_COMPILE}ld export RANLIB${CROSS_COMPILE}ranlib export STRIP${CROSS_COMPILE}strip export CFLAGS--sysroot$SYSROOT export CXXFLAGS--sysroot$SYSROOT export PKG_CONFIG_SYSROOT_DIR$SYSROOT export PKG_CONFIG_LIBDIR$SYSROOT/usr/lib/pkgconfig:$SYSROOT/usr/share/pkgconfig另外-I和-L不要随便加让--sysroot统一管理就好否则万一混进宿主机的头文件编译出来的库会埋下一颗随时爆炸的雷。5.2 make —— 按部就班别急着秀核数configure过了之后正式make。我的建议是刚开始不要一上来就make -j$(nproc)先make -j4跑个几分钟确认没有报错再加大并行数。因为交叉编译偶尔会出现个别头文件尚未生成、另一核心就去引用的竞态问题虽然不是每次都触发但一旦触发就要清掉重编相当浪费时间。我这次用make -j8全程编完大概花了35分钟左右。机器是普通8核工作站没有固态硬盘加持的话会再慢一些。如果想省时间可以只编需要的模块包make -j8 module-qtbasemodule-qtbase是核心库包含Qt Core、Qt GUI、Qt Widgets、Qt Network这些大头。如果你还需要qmake以外的其他工具再单独编对应包。中途如果某个子模块编译失败先别make clean重来看错误属于缺依赖还是源码报错。缺依赖通常改完sysroot补库后直接回到源码目录继续make就能接着走源码报错则需要查是不是mkspec写得不兼容、编译器版本不对之类的根因。5.3 install和产物验证make完成之后make install所有产物都会出现在/opt/qt-5.14.2-aarch64-static/下面重点检查这几个目录lib/里面是libQt5Core.a、libQt5Gui.a、libQt5Widgets.a等静态库这才是我们最终的弹药。bin/里面有qmake这是后续编译Qt应用的入口工具。include/头文件编译应用时需要引用。mkspecs/qmake的工程规范交叉编译应用时qmake会靠它识别目标平台。plugins/这里会生成平台的插件库比如platforms/libqxcb.a如果你后面遇到qt.qpa.plugin: Could not find the Qt platform plugin xcb这个运行时错误就是这里的东西没有正确嵌入程序。这一点后面专门讲。验证安装是否成功在终端里执行/opt/qt-5.14.2-aarch64-static/bin/qmake -v输出应该类似这样QMake version 3.1 Using Qt version 5.14.2 in /opt/qt-5.14.2-aarch64-static/lib到了这一步Qt本身的交叉编译宣告完成。但别急着庆祝真正折磨人的还在后面——用这套静态库去编译你的第一个程序。6. 用静态Qt库编译出第一个aarch64程序6.1 工程文件里的交叉编译配置写一个最简单的Qt Widgets工程工程文件如下QT core gui widgets TARGET helloaarch64 TEMPLATE app SOURCES main.cpp \ mainwindow.cpp HEADERS mainwindow.h # 静态编译版本的Qt库在链接时需要把插件和依赖库一并带上 CONFIG static # 如果需要用到xcb平台插件需要显式声明 QTPLUGIN xcb # 系统库和全局库的链接路径按你的sysroot实际情况填 LIBS -L/opt/aarch64-sysroot/usr/lib/aarch64-linux-gnu这里的CONFIG static告诉qmake当前工程要链接静态版本的Qt库qmake会去lib/下找.aQTPLUGIN xcb非常重要它会让qmake在应用程序里嵌入xcb平台插件。但QTPLUGIN xcb在Qt官方文档里有时写QT_PLUGIN实际使用qmake时两种写法都有我推荐用QTPLUGIN实际生成的Makefile里能直接看到它把-lqxcb之类的内容加进去了。6.2 CMake的交叉编译文件写法如果你项目是用CMake组织的写一个toolchain文件set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR aarch64) set(TOOLCHAIN_PREFIX aarch64-buildroot-linux-gnu-) set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc) set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g) set(CMAKE_SYSROOT /opt/buildroot/output/host/aarch64-buildroot-linux-gnu/sysroot) set(CMAKE_PREFIX_PATH /opt/qt-5.14.2-aarch64-static) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)然后CMakeLists.txt里正常用find_package(Qt5 COMPONENTS Widgets REQUIRED)CMake会顺路径找到静态库。唯一需要留意的是静态链接场景下CMake不会自动管理Qt插件和一堆系统依赖你需要手动把下面这些加到target_link_libraries里target_link_libraries(myapp PRIVATE Qt5::Widgets Qt5::Gui Qt5::Core xcb X11 fontconfig freetype dl pthread )顺序上先Qt库再系统库不要颠倒否则链接期会报一堆undefined reference。6.3 编译出来真的能跑吗编译完成后用file命令查看产物file helloaarch64输出应该类似helloaarch64: ELF 64-bit LSB executable, ARM aarch64, dynamically linked (uses shared libs)注意这里写的dynamically linked指的是程序动态链接了libc等少数系统库不是说Qt还是动态的。你可以用下面这条命令确认Qt是否真的静态进去了aarch64-linux-gnu-readelf -d helloaarch64 | grep NEEDED看到的依赖列表里只会有libc.so.6、libstdc.so.6、libgcc_s.so.1这些绝不会出现libQt5Widgets.so.5这一类。如果想再极致一点完全静态连libc都不依赖就在configure和工程里都加上-static-libgcc -static-libstdc并且在工具链编译时确保libc的.a可用。这样file输出才会变成statically linked。但说实话对于大多数嵌入式Linux设备而言程序动态依赖系统最小的libc并不是坏事后续动态加载某些系统插件会方便很多。6.4 部署到目标板验证把编译好的helloaarch64通过scp、U盘或烧盘工具传到目标板上chmod x之后直接跑./helloaarch64如果目标板上有X环境窗口会正常弹出如果只有framebuffer可以试试在程序里加-platform linuxfb参数./helloaarch64 -platform linuxfb静态版Qt程序的好处在这一刻体现出来你完全不用在意目标板有没有装各种Qt对应的so一个文件就是一个完整的应用。7. 避坑实录我踩过的几个深坑和完整排查过程这一节写几个我在这套流程里实际遇到过的具体问题把排查思路完整交代一下方便你遇到同类问题时快速定位。7.1 xcb插件缺失could not find the Qt platform plugin xcb这个问题几乎100%会遇到而且不是编译期报错是运行时崩溃。程序在开发机上跑得好好的拷到目标板就报错加载不到xcb平台插件。原因静态编译时平台插件默认不会自动嵌入主程序。动态编译时程序运行时会去$QTDIR/plugins/platforms/找libqxcb.so但静态版根本没有这个动态库。如果工程文件里没写QTPLUGIN xcbqmake不会主动把静态插件代码链接进来。解决路径检查工程文件确认QTPLUGIN xcb存在并且在qmake之后重新生成Makefile。如果写了还是不行打开Makefile搜qxcb看看链接行里有没有出现libqxcb.a这样的文件。确认Qt静态库本身编了xcb即configure时使用了-qt-xcb。如果当时没加需要回到第3节重新configure重新编译整个Qt。这步排查要提醒一点不要试图从动态版的Qt目录下面拷一个libqxcb.so放到静态编译程序旁边那样看起来凑巧能过但本质又回到了动态依赖你前面所有的静态努力都白费了。7.2 glibc NSS和hugepage警告别被吓住目标板运行时控制台偶尔会打出类似NSS: could not open database /usr/share/nss/nssdb或者MESA: warning: Failed to open swrast这些大多是程序在尝试加载宿主机的可选数据库或GPU驱动静态程序本身功能不受影响。NSS那个在普通Linux控制台上出现很正常因为程序带了dbus或者network相关模块尝试访问NSS用户数据库。处理办法是直接忽略或者在裁剪Qt模块时把dbus相关依赖关掉-no-feature-dbus已经干了一部分。MESA那个更不用担心说明程序尝试加载OpenGL软件渲染库但我们configure时已经关掉了OpenGL只是某些检测代码还会去打探一下忽略即可。7.3 内核驱动和framebuffer的confusion静态编译的Qt程序在目标板上用-platform linuxfb跑的时候如果屏幕一片黑先不要怀疑Qt库本身用dmesg看内核里有没有加载对应的DRM/fbdev驱动。很多开发板默认内核没有开启CONFIG_FB_*或者DRM渲染设备应用层再怎么挣扎都是黑屏。另外检查和/dev目录下有没有/dev/fb0。没有的话用uboot传给内核参数添加video或fbconsole或者在设备树dts里使能相应的显示节点。这属于目标板BSP层面的工作但它直接影响Qt的显示输出拿过来排查。7.4 链接阶段报一大片undefined reference to FcFreeTypeQueryFace类型错误的处理出现这种情况常发生在配置fontconfig和freetype顺序错了的场景里。Qt静态链接时符号解析顺序是按依赖反向排列的程序→QtWidgets→QtGui→QtXcbQpa→xcb→fontconfig→freetype。如果-lfontconfig在-lfreetype前面链接器处理到最后会找不到freetype里的符号瀑布效应就出来了。我的经验做法是如果看起来是字体相关的一堆未定义引用优先在LIBS里调整顺序被依赖的库放后面LIBS -lxcb -lX11 -lfontconfig -lfreetype -lpthread -ldl还有一个更省事的方案用pkg-config自动拼接依赖。静态库安装时会带.pc文件里面写清楚了依赖关系可以在pro文件里这样用CONFIG link_pkgconfig PKGCONFIG fontconfigqmake会自动把-l参数调整成正确顺序还顺带补上-I头文件路径。7.5 make时遇到cannot find -lgcc_s的兼容性问题这在部分工具链上会出现。链接阶段报找不到libgcc_s.so.1可能是工具链把gcc运行库放到了sysroot之外而链接器没有去那个目录找。我的处理方式# 查看gcc的库搜索路径 aarch64-buildroot-linux-gnu-gcc -print-search-dirs # 把包含libgcc.a的目录通过-L显式加进工程文件的LIBS里 LIBS -L/opt/buildroot/output/host/lib/gcc/aarch64-buildroot-linux-gnu/9.3.0或者更简单一点确保环境变量里LIBRARY_PATH包含gcc内置lib目录然后重新configure。不过加-L这种方案最直接遇到一个配一个。7.6 省时间的秘密构建缓存和并行裁剪的平衡最后分享一个效率层面的东西。Qt静态编译一次40分钟起步改一次configure参数可能又要全部重来所以有两个技巧每次改动配置前保留上一次编译好的/opt/qt-5.14.2-aarch64-static目录复制一份备份改出问题能快速回滚。如果只是加了一个feature有时候不需要全量重新make直接在build目录下执行对应子模块的增量make比如make -j8 module-qtbase会快很多。很多教程只会告诉你重新configure重新make实际上增量编译完全可行。conigure之后的config.summary文件会打印当前Qt的配置概貌务必扫一遍。我看到过有人编完之后发现Xcb那栏明明写着Yes程序运行时依然加载不了插件最后回头一看当初configure时写的是-qt-xcb没错但mkspec里QMAKE_INCDIR_XCB没配对xcb的头文件路径指向了宿主机编出来的插件架构是错的。这提醒我们看到summary里的Yes并不代表万事大吉还要确认它引用的路径和环境变量指向的是sysroot内部。8. 结语之外的一些话Qt5.14.2 aarch64 静态交叉编译这条路网上零零散散的帖子很多但能把每个步骤背后的原理和排查思路串成一条完整链路的太少。很多人卡在configure过不去更多人卡在最后链接阶段符号解析不出来但无论卡在哪一步回看本文的第3到第7节应该都能找到对应的解法。我在实际做这个项目时最大的体会是不要迷信一个命令跑通的魔法脚本。交叉编译的每一个环节都和你的目标板硬件、rootfs、工具链版本深度耦合参考别人的参数是捷径但真正动手时还是要逐项读configure的输出、逐段看config.log把你的sysroot当成唯一的真实现场。理清这套逻辑之后你以后给其他平台移植Qt、移植别的GUI框架基本都能做到心里有数。静态编译这一关虽然难啃但啃完是真踏实的——产品交付的时候你就知道自己递出去的每一个二进制文件都已经把该背的责任背好了。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进