资讯动态

Qt 5.14.2 aarch64静态交叉编译:从工具链到目标板部署全攻略

发布时间:2026/9/14 9:39:49 来源:尧图企业网站定制
接到一个新项目要在国产ARM板卡aarch64架构上跑一个基于Qt 5.14.2的图形界面程序板子本身资源有限、系统精简到连包管理器都没有更别说在板子上现场编译。这就逼着我把Qt 5.14.2在x86开发机上做一次完整的静态交叉编译产出一个aarch64架构、静态链接的Qt库再把应用也静态链成单一可执行文件直接拷到板子上就能跑。整套东西从工具链安装到最终应用运行前前后后折腾了两周多踩了不少坑。现在把整个流程从零开始整理成一份可直接照做的手册给同样需要做Qt aarch64静态交叉编译的朋友省点时间。这篇文章不是简单贴几个命令我会把每一步背后的原理、参数取舍、依赖关系都讲清楚。内容按“为什么这么做”和“具体怎么做”两条线展开覆盖工具链搭建、sysroot构建、依赖库交叉编译、configure配置、实际编译、应用移植到目标板以及最后的问题排查。无论你是第一次接触交叉编译的新手还是已经入坑但被各种链接错误折磨过一轮的开发者这份手册都能直接参考。1. 为什么是Qt 5.14.2 aarch64 静态编译组合背后的思路1.1 这个组合到底解决什么问题先聊清楚选型的逻辑不然很多人照着博客敲完命令换一个场景就不会变通了。Qt 5.14.2是Qt公司在5.x分支里一个非常特殊的版本。它属于LTSLong Term Support周期官方持续维护周期长而且这是最后一个能免费使用全部开源模块的LTS版本后续的5.15虽然也有LTS但新模块开始逐步收紧6.x更是调整了模块划分和授权边界。对于嵌入式产品团队来说5.14.2功能够用、社区资料多、踩坑案例网上随便搜属于“稳”字优先的选择。aarch64是ARM 64位指令集对应的是树莓派3B以后的64位模式、飞腾、鲲鹏、以及各种国产化板卡。这类板子的共同特点是性能比传统单片机强很多但生态碎片化严重不同板卡的系统环境千差万别。交叉编译是嵌入式的常态手段——开发机跑x86_64目标板跑aarch64两者架构不同自然要在开发机上生成目标架构的二进制。静态编译解决的是部署问题。嵌入式Linux板卡普遍没有包管理工具动态库版本五花八门你要是带了几个Qt的so文件过去很可能出现glibc版本不兼容、libstdc找不到、Qt插件目录不对等各种问题。静态编译把Qt库和应用链成一个独立的可执行文件唯一需要关心的是目标板内核支持以及glibc版本是否兼容部署成本降到最低。微信那种动态更新的方式在嵌入式里不现实静态单文件拷贝过去双击就能跑运维省心太多。1.2 静态交叉编译的整体工作流程理解整个编译流程脑子里要建立一条链工具链交叉编译器→ 目标系统根目录sysroot→ 依赖库 → Qt源码 → 应用工程。开发机上装的gcc只能生成x86_64的机器码必须用aarch64的交叉工具链比如aarch64-linux-gnu-gcc。编译器本身需要知道目标板的系统头文件和库文件在哪里不能去翻开发机自己的/usr/include因为那是x86_64环境的。这里就要搭一个sysroot即目标板根文件系统的副本里面包含目标板的/lib、/usr/include、/usr/lib等目录。交叉编译器加上sysroot才具备真正生成目标板可运行程序的条件。接下来是依赖库。Qt本身依赖很多底层库zlib压缩、libpng图片、opensslhttps、sqlite数据库等。虽然Qt源码自带一部分第三方库src/3rdparty目录但openssl这种受系统限制比较大的库官方默认不内置建议外部独立编译并静态链接。依赖库的交叉编译要在sysroot里完成这样Qt configure的时候才能找到。然后是Qt本身的configure。这一步是整个流程中最核心也最考验经验的环节。configure会探测目标环境其实是依赖sysroot里的交叉编译器决定启用哪些模块、禁用哪些模块、使用哪种Qt平台抽象QPA后端插件。静态编译意味着所有模块编译成.a静态库QPA插件也要随应用一起链进去没有运行时加载so的便利。最后是应用编译。Qt库编译安装完成后用它的qmake工具生成应用的Makefile整个应用静态链接。这一步常见问题包括找不到库文件路径没配、找不到头文件include路径错了、链接报undefined reference通常是依赖库链接顺序问题。链接顺序这个坑很大后面会专门讲。2. 环境准备与工具链搭建从零开始的第一步2.1 主机环境与版本选型先说我实测通过的环境组合组件版本/说明开发机系统Ubuntu 20.04 LTS x86_64交叉工具链gcc-linaro-7.3.1-2018.04-x86_64_aarch64-linux-gnuQt源码qt-everywhere-opensource-src-5.14.2.tar.xz目标板系统自精简的Linux 4.19内核 glibc 2.28Ubuntu 20.04自带的gcc是9.x和Linaro 7.3.1的gcc没有直接冲突因为它们是不同target的编译器通过各自目录下的bin里面的aarch64-linux-gnu-gcc来调用。选择一个Linaro工具链而不是Ubuntu自带的gcc-aarch64-linux-gnu原因是Linaro工具链自带配套的sysroot目录结构清晰方便替换成目标板库而且经过大量嵌入式场景验证和Qt这种大型项目的兼容性更稳定。Ubuntu源里的交叉编译器也能用但它默认链接的是Ubuntu自带的aarch64运行时库和精简后的目标板系统往往对不上还是需要自己再折腾sysroot没必要。不建议在Ubuntu 22.04上做这套流程风险在于它默认的gcc版本太高glibc、binutils版本都和Linaro老工具链存在兼容性问题可能会报一些莫名其妙的错误。如果只有22.04建议用Docker拉一个ubuntu:20.04镜像来搭环境这样最省心。2.2 交叉工具链安装与验证工具链安装不是apt装一下那么简单关键在目录规划。我习惯把所有交叉编译相关的东西放在独立目录方便后面换版本时整目录清理。这里以我们规划的目录为例mkdir -p /opt/aarch64-toolchain cd /opt/aarch64-toolchain wget https://releases.linaro.org/components/toolchain/binaries/7.3-2018.04/aarch64-linux-gnu/gcc-linaro-7.3.1-2018.04-x86_64_aarch64-linux-gnu.tar.xz tar xf gcc-linaro-7.3.1-2018.04-x86_64_aarch64-linux-gnu.tar.xz解压后工具链目录里会有bin、aarch64-linux-gnu、lib、sysroot等子目录。注意sysroot目录虽然自带了一份基本根文件系统但这份sysroot只能用于编译器自检真正编译Qt的时候要替换成你自己的目标板sysroot。然后配置环境变量。环境变量必须写清楚交叉编译过程中出现“找不到库”“找不到头文件”的报错八成是环境变量没配对export PATH/opt/aarch64-toolchain/gcc-linaro-7.3.1-2018.04-x86_64_aarch64-linux-gnu/bin:$PATH export CROSS_COMPILEaarch64-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注意以上变量建议写进~/.bashrc避免每次开终端都要重新export。但要注意做纯x86_64主机端编译时要把CC、CXX等变量unset掉不然会串味导致本机程序也用交叉编译器编译。验证工具链是否正常工作写一个最简单的C文件编译一下echo int main(){return 0;} test.c aarch64-linux-gnu-gcc -o test test.c file test输出应该显示ELF 64-bit LSB executable, ARM aarch64。看到这个工具链就绪了。2.3 源码下载与目录规划Qt 5.14.2的源码包是qt-everywhere-opensource-src-5.14.2.tar.xz包含了Qt Base、Qt Declarative、Qt WebEngine默认不编等所有模块。我们只需要Qt Base核心模块即GUI、Widgets、Network、SQL等但下载everywhere包没问题configure阶段会自行裁剪。目录规划建议mkdir -p /opt/qtaarch64/{source,build,install,sysroot} cd /opt/qtaarch64/source tar xf qt-everywhere-opensource-src-5.14.2.tar.xzbuild目录用来放configure和make的中间产物Qt支持out-of-source构建但5.14.2的qmake对源码内构建支持更好install目录是最终的Qt库安装位置。sysroot放目标板的根文件系统副本。这样分层的好处是万一编译到一半配置错了直接清空build目录重来不影响源码install目录单独挂一个版本号可以同时保留多套交叉编译结果方便对比不同配置的差异。3. 构建根文件系统sysroot与依赖库决定成败的幕后细节3.1 sysroot的组成与构建方式sysroot可以简单理解为目标板根目录的一个“精简镜像”交叉编译时编译器通过--sysroot参数找到目标系统的include和lib。这里需要包含目标板的基础运行库和头文件而不是开发机的。怎么拿到目标板的根文件系统副本两种方式方式一从目标板上打包拉取推荐。因为我手里有实际板卡直接在板子上打包cd / tar czvf sysroot.tar.gz --exclude/proc --exclude/sys --exclude/dev --exclude/tmp --exclude/run --exclude/var/log usr lib etc conf.d 2/dev/null但这样打出来的包往往很大几十MB甚至上百MB。要精简的话只拉关键目录/usr/include、/usr/lib、/lib、/lib/aarch64-linux-gnu等。实际操作时也不用太精细只要保证板子上跑的程序依赖的库和对应头文件都进去了就行。方式二用工具链自带sysroot作为底子按板子需要增补。Linaro工具链自带sysroot里有基本glibc运行库但缺少很多目标板上的专用库和头文件。可以在/opt/aarch64-toolchain/gcc-linaro-7.3.1-2018.04-x86_64_aarch64-linux-gnu/aarch64-linux-gnu/libc/里看到一份基础运行环境但实际项目不够用。我采用的策略是两者结合把工具链自带sysroot拷贝到 /opt/qtaarch64/sysroot 作为底座再把我目标板上额外的库比如板卡厂商提供的GPU库、编解码库从板卡上拷进来。注意拷贝时保持目录结构比如板卡上的库在/usr/lib/aarch64-linux-gnu就对应拷贝到sysroot的usr/lib/aarch64-linux-gnu。sysroot的内部结构通常长这样sysroot/ ├── etc ├── lib │ └── aarch64-linux-gnu ├── usr │ ├── include │ ├── lib │ │ └── aarch64-linux-gnu │ └── lib643.2 关键依赖库的交叉编译以openssl为例Qt的network模块做HTTPS必须依赖openssl。静态编译场景下openssl必须编译成静态库.a并且和Qt、应用一起链接进最终可执行文件。如果openssl编译成动态库运行时目标板上没有对应so应用启动就会报找不到库。openssl交叉编译相对简单它是一个自带Configure脚本的项目。我用的版本是OpenSSL 1.1.1系列为了和Qt 5.14.2兼容不要用3.x版本3.x去掉了不少Qt 5.14.2还在用的APIconfigure时可能报错。cd /opt/qtaarch64/source wget https://www.openssl.org/source/openssl-1.1.1t.tar.gz tar xf openssl-1.1.1t.tar.gz cd openssl-1.1.1t ./Configure linux-aarch64 \ --prefix/opt/qtaarch64/sysroot/usr \ --cross-compile-prefixaarch64-linux-gnu- \ no-shared \ no-asm \ no-tests make -j$(nproc) make install_sw参数解释linux-aarch64告诉openssl按aarch64 Linux平台生成Makefile--cross-compile-prefix指定交叉编译器前缀--prefix直接指到sysroot的usr目录这样头文件和库文件直接落到sysroot内部Qt configure时能自动找到no-shared强制只生成静态库这是关键选项no-asm在某些工具链上必须加因为openssl针对aarch64的汇编优化和Linaro 7.3.1工具链的编译选项可能冲突用同样的思路把zlib、libpng如果Qt要用png格式也交叉编译一遍。zlib比较特殊Qt依赖的zlib可以通过configure参数-qt-zlib让Qt用自己内置的3rdparty版本但如果你的应用还通过其他库间接用了zlib建议外部编一份静态zlib放sysroot里保证链接时版本统一。cd /opt/qtaarch64/source wget https://zlib.net/zlib-1.2.13.tar.gz tar xf zlib-1.2.13.tar.gz cd zlib-1.2.13 CCaarch64-linux-gnu-gcc \ ARaarch64-linux-gnu-ar \ RANLIBaarch64-linux-gnu-ranlib \ ./configure --prefix/opt/qtaarch64/sysroot/usr --static make -j$(nproc) make installopenssl和zlib这两个库基本够Qt Base的最小静态编译使用了。如果目标板有SQLite、JPEG等额外需求参照同样流程处理即可。核心逻辑是一样的用交叉编译器 sysroot前缀编出.a文件放进sysroot。4. configure配置详解参数背后的原理与取舍4.1 核心configure参数解析准备工作做完进入Qt源码目录开始configure。这一步是整个流程里最容易出问题的地方参数既要满足功能需求又要控制体积还要确保不误探测到开发机的x86_64库。先说我最终的configure命令然后解释关键参数cd /opt/qtaarch64/source/qt-everywhere-opensource-src-5.14.2 ./configure \ -prefix /opt/qtaarch64/install/Qt5.14.2-aarch64-static \ -xplatform linux-aarch64-gnu-g \ -release \ -static \ -opensource \ -confirm-license \ -nomake examples -nomake tests \ -no-opengl \ -no-xcb \ -no-compile-examples \ -qt-zlib \ -qt-pcre \ -qt-libpng \ -qt-libjpeg \ -qt-freetype \ -openssl-linked \ -I/opt/qtaarch64/sysroot/usr/include \ -L/opt/qtaarch64/sysroot/usr/lib \ -no-feature-cups \ -no-feature-icu \ -no-feature-glib \ -linuxfb \ -no-eglfs一项项看-xplatform linux-aarch64-gnu-g指定目标平台。Qt的qmake通过这个参数加载mkspecs/linux-aarch64-gnu-g目录下的qmake.conf其中定义了目标编译器、链接器、sysroot路径等。-static告诉Qt把所有模块和插件编译成静态库。对应地最终应用链接时qmake生成的Makefile里会带上全部的 .a 文件。-release编译release版去掉调试符号和调试代码体积和性能都更优。-qt-zlib、-qt-pcre、-qt-libpng、-qt-libjpeg、-qt-freetype让Qt使用源码自带的第三方库。这样我们不需要在sysroot里手工装libpng等一整套Qt自己搞定版本一致性最好。这也极大降低了构建依赖复杂度。-openssl-linked表示openssl使用静态链接方式。如果这个参数写成-openssl-runtime则Qt运行时去系统找libssl.so静态编译下这是不可接受的因为目标板未必有这套库。-I和-L指定sysroot里依赖库的头文件和库文件搜索路径。因为openssl、zlib之前都装到了sysroot/usr目录这里指过去Qt configure就能找到。-no-opengl -no-xcb关闭OpenGL和X11支持。嵌入式目标板跑的是精简Linux通常没有X服务器也没有GPU或者GPU驱动不兼容linuxfbLinux framebuffer是Qt在裸帧缓冲上的常用后端通过直接写/dev/fb0来显示界面。如果板子有GPU且能跑EGL可以做EGLFS方案那是另一套配置流程这里先不展开。-linuxfb显式启用linuxfb平台插件。4.2 静态编译需特别关注的选项静态编译下的一个核心问题插件怎么办。Qt有很多功能是靠插件实现的比如字体插件、平台集成插件、图片格式插件。在动态编译下插件是独立的.so文件放在plugins目录下由Qt运行时加载。而静态编译下插件无法外部加载必须在configure阶段指定哪些插件要编进静态库应用链接时再一起链进去。特定插件的enable/disable通过-qt-前缀的方式解决了一部分如-qt-libpng就是让Qt的png插件依赖内置库但平台插件、字体插件等还需要在configure命令里以-qt-plugin-xxx或者-no-feature-xxx的方式控制。上面命令里的-no-feature-cups、-no-feature-icu、-no-feature-glib都是直接裁剪掉不需要的feature减少编译时间和体积。这里要注意一个关键技巧当你在configure后想改变插件配置千万不要在build目录里反复修改最好的方式是重新建一个build目录再次运行configure。Qt的configure会把之前的配置缓存下来不清理的话改动很难生效。我习惯把每次的configure命令写成一个shell脚本比如build_qt_static.sh每次运行前先rm -rf build再执行保证干净。configure运行结束后要留意终端输出重点看两部分Qt的模块列表里有没有显示OpenSSL: yes一定是linked模式QPA backend部分是否有LinuxFB: yes这是后面能跑起来的保证如果显示XCB: no不用担心这是目标板没有X服务器的表现。如果OpenSSL: no说明openssl探测失败了要去查sysroot里的openssl是否编译成功。5. 编译与安装慢工出细活的make阶段5.1 make过程与常见编译错误configure成功只是万里长征第一步真正的考验在make阶段。在build目录里执行make -j$(nproc)这里要注意一个细节make的并行度不是越大越好。尤其静态编译过程中大量编译单元并发会极大消耗内存。如果你开发机内存不够8GB以下建议-j4或-j2免得编译器自己把自己OOM kill掉。我这次机器是32GB内存所以直接-j16跑大约40分钟编完。编译过程中常见的错误有几种第一种编译器突然报cc1plus: out of memory。解决办法是降低-j参数或者加swap空间。Qt的编译对内存确实比较敏感。第二种报某个头文件找不到。这通常是sysroot的include路径不对检查configure的-I参数以及qmake.conf里的交叉编译器配置是否正确。第三种报multiple definition of ...。这是链接时符号重复多见于第三方库重复指定。检查configure参数是不是某个库既用了外部版本又用了内置版本比如同时指定了-openssl-linked但sysroot里又有libcrypto.aconfigure时因为路径问题找到了a实际编译时依赖顺序不对导致符号冲突。解决方法是确保sysroot里不要混放多个版本的同一库。make顺利通过后执行安装make install安装完成后install目录下会出现bin、lib、include、mkspecs、plugins等子目录。静态编译的Qt库文件都以.a结尾比如libQt5Core.a、libQt5Gui.a、libQt5Widgets.a等。同时qmake工具也会安装到bin目录下这个qmake是aarch64交叉编译版后面编译应用时要用它。5.2 qmake配置与第一个静态应用Qt库本身编译完只是完成了平台基础真正的应用移植才是最终目标。我建议这里先写一个最简单的Qt测试程序只要一个QApplication显示一个空窗口先把整条链路打通再移植正式业务代码。测试工程文件hello.proQT core gui widgets CONFIG c11 TARGET hello_static TEMPLATE app SOURCES main.cppmain.cpp#include QApplication #include QLabel int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel label(Hello aarch64 Qt Static); label.show(); return app.exec(); }然后用刚编译出来的qmake生成Makefileexport PATH/opt/qtaarch64/install/Qt5.14.2-aarch64-static/bin:$PATH cd hello_project qmake hello.pro make -j$(nproc)这里会出现一个很常见的问题make以后链接报错比如undefined reference to qt_plugin_platform_linuxfb()这个错误是因为Qt静态编译后平台插件是作为静态库的一部分存在的但默认情况下插件不会被自动链入主程序。需要在工程文件里手动声明要引入哪些插件QTPLUGIN qlinuxfb或者在main.cpp里显式include插件头文件并初始化不推荐麻烦。更简单的办法是在hello.pro里加上QTPLUGIN.platforms qlinuxfb CONFIG staticqmake生成Makefile时会自动把平台插件的静态库追加到链接命令的末尾。这个细节特别重要网上很多教程没提导致一堆人在这个坑里卡半天。链接命令最终会长成这样注意顺序是Qt自身库在中间插件库在最前面aarch64-linux-gnu-g -o hello_static /opt/qtaarch64/install/.../lib/libqlinuxfb.a -lQt5Widgets -lQt5Gui -lQt5Core -lpthread -ldl -lz ...看到这串命令说明qmake已经把QTPLUGIN的插件追加到前面了静态链接正式成立。编译出来的hello_static文件用file hello_static验证ELF 64-bit LSB executable, ARM aarch64, dynamically linked ...注意“dynamically linked”这个描述出现过不必恐慌。它只表示ELF头里记录了动态加载器信息这里说的动态链接指的是glibcc库仍然是动态链接的。因为glibc静态链接有许可证和NSSName Service Switch兼容问题所以通常只把Qt和openssl、zlib这些静态链进去glibc保持动态链接。目标板上只要有基本的glibc运行环境即可。如果你追求完全独立可以加-static-libgcc -static-libstdc但glibc不建议贸然全静态。5.3 目标板运行与插件部署把hello_static拷贝到目标板的普通用户目录加上执行权限scp hello_static usertarget_board:/home/user/ ssh usertarget_board chmod x hello_static ./hello_static -platform linuxfb如果目标是纯命令行启动不带-platform参数Qt会按顺序探测可用的平台插件。由于静态编译时我把平台插件都编进去了它会自动选择linuxfb。加上参数更明确排查问题时也方便建议加上。运行后如果屏幕出现一个“Hello aarch64 Qt Static”的窗口说明整个链路完全打通。如果程序直接崩了先看是否缺少字体文件嵌入式精简系统往往没有/usr/share/fonts目录Qt字体插件在找不到字体时会直接退出。Qt Base自带一个最小字体引擎但字体文件需要自己提供。最简单的办法是把一个.ttf字体文件放到目标板的/usr/share/fonts/truetype/dejavu/目录下或者通过QT_QPA_FONTDIR环境变量指定字体路径。字体这个坑我印象太深了第一次上板跑的时候程序秒崩用-platform minimal一测发现是字体问题。Qt静态编译后如果不指定-qt-freetype字体插件也可能编不进去渲染中文会完全空白。所以configure阶段必须-qt-freetype同时准备一个中文字体文件比如思源黑体的ttf放到目标板这样界面中文才能正常显示。6. 避坑实录与排查技巧6.1 常见问题速查表现象根因解决方案configure报Basic XLib functionality test failedconfigure自动检测X11系统无X11开发库加-no-xcb -no-xcb-xlib明确禁用X11编译到一半报cannot find -lGL系统装了libgl但缺libgl-dev开发符号链接加-no-opengl禁用OpenGL模块或补齐libGL.so链接链接报undefined reference to qt_plugin_platform_linuxfb静态插件未显式声明在.pro里加QTPLUGIN.platforms qlinuxfb运行时提示qt.qpa.plugin: Could not find the Qt platform plugin linuxfb平台插件不在可执行文件内或plugin路径错误确认configure时linuxfb是yes且应用.pro里有QTPLUGIN声明提示no such file or directory启动即退出通常是动态库找不到或系统缺库用readelf -d hello_static | grep NEEDED检查依赖保证目标板有这些库运行后界面白屏或中文变方块字体引擎或字体文件缺失确认configure有-qt-freetype目标板放中文字体文件link时大量undefined reference链接顺序问题或依赖库缺失检查是哪个符号在哪层库调整.pro里LIBS顺序静态库顺序必须先依赖后使用configure时OpenSSL检测失败sysroot里openssl没装好或者路径不对单独用aarch64-linux-gnu-gcc -I... -L... -lcrypto编译测试程序验证openssl环境编译完体积巨大静态编译包含全部模块configure缩减模块禁用不需要的featurerelease版加strip6.2 独家避坑心得第一link顺序问题值得专门说透。静态库按依赖顺序理解如果A.a依赖B.a链接时A.a必须在B.a前面。Qt的模块库之间互相依赖手工写LIBS排序容易出错。qmake会在生成的Makefile里自动排序但因为QTPLUGIN这种机制有时会乱。我从实践中总结的一个技巧如果遇到undefined reference优先检查.pro里有没有重复写LIBS以及LIBS的顺序把被依赖的库放到末尾。也就是“依赖的库排后面”这条规则在gcc链接里百试百灵。第二不要小看sysroot里的文件结构。很多人在交叉编译openssl时图省事直接--prefix/opt/qtaarch64/sysroot而不是--prefix/opt/qtaarch64/sysroot/usr导致头文件安装到了sysroot/include而Qt默认找的是sysroot/usr/include。这种路径错位往往排查起来比编译错误还费时。建议统一约定所有交叉编译的第三方库一律安装到sysroot/usr目录下configure时始终用同一套-I sysroot/usr/include -L sysroot/usr/lib。第三使用-no-feature-系列要谨慎。Qt的feature机制裁剪的是编译器宏如果应用中用到了被裁剪的API编译时不会报错头文件里宏判断后把函数定义隐藏了但链接时会出现undefined reference非常隐蔽。建议项目功能稳定前保守裁剪只裁剪确定不用的组件如cups、glib等其他保留。第四目标板glibc版本兼容性。静态编译的Qt库在链接时使用的是开发机sysroot里的glibc头文件实际运行依赖的是目标板的glibc动态库。如果开发机sysroot里的glibc比目标板的版本新程序运行可能报version GLIBC_2.XX not found。解决办法是确保sysroot从实际目标板打包用3.1节的方式一而不是用工具链自带的。这块踩过的人一定懂我说的是什么意思。第五善用Qt自带的qmake特性变量。静态编译场景下qmake会自动把libQt5Xxx.a按依赖顺序链入但Qt插件库需要在.pro里声明。完整的做法QTPLUGIN.platforms qlinuxfb QTPLUGIN.imageformats qjpeg qpng QTPLUGIN.accessible qtaccessiblewidgets这三个分别对应平台插件、图片格式插件和无障碍插件。除了platforms另外两个可以在用到时再加。这样Qt的插件机制在静态环境下才算全部闭环。最后聊一点个人体会。嵌入式Qt静态交叉编译本质上是一场关于“环境”的博弈工具链选型、sysroot一致、依赖库版本、configure参数每一环都紧密相扣。我之前也试过用Docker封装整个交叉编译环境效果不错团队多人协作时能确保每个人拿到的环境完全一致。如果你也要长期做这块建议把工具链、sysroot、configure脚本、编译脚本全部纳入版本管理别指望脑子记住所有细节。这套手册写出来的所有命令我都在干净的Ubuntu 20.04环境里重跑过至少两遍确认无遗漏。照着走能让你少走我当初那两周的弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价