1. 为什么你大概率需要这份手册
做嵌入式Linux开发的同行应该都明白,目标板子跑的是aarch64架构,开发机却是x86_64的PC,这种组合下给板子准备Qt运行环境,就绕不开交叉编译。如果你只是做动态库版本,把编译好的so扔到板子上,用系统自带的依赖碰运气,那倒还省事。可一旦遇到设备需要离线部署、系统环境精简、或者客户要求单文件直接跑的场景,静态编译就成了唯一靠谱的出路。
我这次折腾Qt 5.14.2的aarch64静态交叉编译,前后踩了三天坑,查遍各种资料才理清头绪。市面上的教程不少,但要么针对老版本Qt,要么零零散散只讲其中一步,很少有从零到一、把工具链准备到最终程序跑上板子全流程讲透的。所以我把整个搭建过程、每一个坑、每一条命令完整记录下来,整理成这份手册。
这篇内容适合三类人:一是要给aarch64板卡移植Qt应用、但没跑通过交叉编译的嵌入式开发;二是需要在离线环境下交付GUI程序的工程师;三是想搞懂Qt交叉编译原理、不想只会复制粘贴命令的初学者。读完这份手册,你能独立完成一套可复用的aarch64静态Qt环境,并且明白每一步在做什么、为什么这么做。
先声明一点,整个方案我基于常见的aarch64目标板,比如树莓派、瑞芯微、全志系列这样的Linux环境,使用的宿主机是x86_64的Ubuntu 20.04/22.04系统。如果你的板子用的是glibc版本特别老的话,后面关于sysroot的章节一定不能跳过。
2. 为什么选择静态交叉编译,而非动态方案
2.1 静态编译能解决什么问题
交叉编译本身不新鲜,但静态交叉编译在使用场景上有它的独到之处。先说说我为什么坚持要上静态,而不是用更省事的动态库方案。
最直接的原因就是部署成本。动态方案做出来,产物是一堆so加一个可执行文件,你得把这些东西一起打包、一起分发、还要考虑目标板上的Qt依赖是否齐全。遇到系统版本不一致的板子,比如开发时用glibc 2.31,现场设备却是glibc 2.28,运气好能跑,运气不好直接报版本符号找不到这种诡异错误。而静态编译的可执行程序,依赖都在自己身上,拷过去就能跑,glibc版本差异只要不太离谱,基本不影响运行。
第二个原因在于稳定性。动态方案下,Qt插件目录、qml模块路径、字体库、平台插件全部依赖运行时环境,环境变量稍微配不对,程序起来就是黑屏或者段错误。静态编译把所有插件全部链接进可执行文件,省去了一堆QTDIR、QT_QPA_PLATFORM_PLUGIN_PATH这类运行时配置,程序行为更可控。这一点在交付给现场、由不熟悉Qt的人去部署的场景下,优势特别明显。
第三个原因和板子资源有关。很多aarch64嵌入式板卡Flash空间只有几百MB甚至更小,动态装一套完整的Qt运行库,加上必要的插件和依赖,占用轻松超过100MB。而静态编译出来的单个可执行文件,即便把Qt全部打进去,通常也就是20到30MB,对存储空间的压力小得多。
2.2 静态方案需要付出的代价
静态编译并不是银弹,付出的代价也必须说清楚。
最痛的一点是体积。Debug版本随便编译一下就是上百MB,Release版本压缩后25MB左右,跟动态方案的几MB比起来确实大很多。但考虑到嵌入式设备上省掉的运行库体积,整体算下来往往还是静态更划算。
第二个代价是编译时间。全套Qt静态编译,在8核心16线程的机器上大概需要40分钟到1小时,动态编译差不多能快一半。如果第一次配置错了,返工重编的时间成本更高。
第三个代价是license和合规问题。如果你的Qt是商业授权,静态链接时需要留意L/GPL条款的要求;如果是开源项目,LGPLv3在静态链接场景下有提供relink条件的义务。我这里用的是Qt 5.14.2开源版,如果只是内部使用和分发自己的应用,一般是没问题的,但如果要商业化闭源交付,建议先和公司法务确认清楚。
把这些代价想清楚,再回去看自己的需求,是选择静态还是动态,答案就很清楚了。如果你的应用要和系统里其他Qt程序共享运行环境、频繁升级,动态更合适;如果像我一样是整机设备交付、软件环境完全自控,静态是更好的选择。
3. 交叉编译环境的完整搭建
3.1 宿主机系统与基础工具准备
开始在环境搭建之前,先检查一下宿主机的系统版本和架构。
我用的是Ubuntu 22.04,在x86_64环境下工作。交叉编译最怕的就是工具链和系统环境不匹配,所以第一步先把基础的编译工具链装齐。
sudo apt update sudo apt install -y build-essential g++ gcc make cmake ninja-build \ mesa-common-dev libgl1-mesa-dev libxkbcommon-dev \ libfontconfig1-dev libdbus-1-dev libgles2-mesa-dev \ libssl-dev libicu-dev libasound2-dev gperf bison flex \ libclang-dev python3这里每个包都有自己的用途。build-essential提供宿主机自编译的基础工具,mesa和libgl相关的是为了后面处理OpenGL相关依赖,libfontconfig是Qt字体渲染的依赖,libssl和libicu是Qt网络和国际化模块需要的,gperf、bison、flex是Qt编译过程中生成代码的工具。
需要注意的是,宿主机上安装的这些开发库,严格来说只服务于Qt源码的配置检测阶段,真正链接时用的是后面为aarch64准备的sysroot。但有些检测项在宿主机上没有对应库会直接报错,所以索性都装上,省得中途卡住。
3.2 交叉编译工具链选择
工具链选择是整个交叉编译里最核心的决策点。我对比过三种方案:Linaro GCC、ARM官方GNU工具链、以及Buildroot生成的工具链。
我最后选的是ARM官方GNU-A工具链,gcc版本10.3,下载的时候选aarch64-linux-gnu的x86_64 Linux版本就行。
wget https://developer.arm.com/-/media/Files/downloads/gnu/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz sudo mkdir -p /opt/toolchains sudo tar -xf gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz -C /opt/toolchains解压后,把工具链的bin目录加进PATH:
export PATH=/opt/toolchains/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin:$PATH验证是否正常:
aarch64-none-linux-gnu-gcc -v能看到gcc version 10.3.0的输出就说明工具链没问题。
为什么选这个而不选Linaro的?主要原因是ARM官方工具链的glibc版本比较新,搭配较新Ubuntu宿主机时兼容性更好,不太会出现头文件不匹配的问题。Linaro的维护活跃度这几年明显下降,而且它的工具链版本和老内核的板子配起来虽然没问题,但匹配新系统时容易出现奇怪的链接错误。
3.3 Sysroot的准备与配置
sysroot是交叉编译里容易被忽视、却极其关键的一环。简单来说,sysroot就是目标板系统根文件系统的一个拷贝,包含板子上Linux系统的头文件、标准库、以及各种底层依赖库,让交叉编译工具链在编译时能正确引用目标系统的API和库文件。
这里最容易踩坑:Qt的很多依赖是宿主机上没有的,必须先准备好aarch64版本的依赖库,放到sysroot里,然后再编译Qt。要不然就算交叉编译工具链没问题,配置阶段会报各种头文件找不到的错误。
我准备sysroot的方式是直接从目标板子上拷贝。如果你的板子已经跑了一个完整的Linux系统,可以直接在板子上执行:
rsync -avx / <宿主机IP>:/opt/sysroot/aarch64/如果板子还没有系统,或者不太方便拷贝,可以在宿主机上用debootstrap做一个:
sudo debootstrap --arch=arm64 --foreign bookworm /opt/sysroot/aarch64注意,debootstrap这种纯手工方式做出来的sysroot一般只有基础的glibc,后面编译Qt时大概率还是缺各种依赖库,一样得自己手动往sysroot里补充aarch64的库。所以我个人最推荐的方式是在目标板上先装好需要的系统库,然后再整体rsync出来。
我用树莓派4B(aarch64,Debian系统)做实验时,先在板子上安装这些依赖库:
sudo apt install -y libfontconfig1-dev libdbus-1-dev libfreetype6-dev \ libxkbcommon-dev libxcb1-dev libxcb-keysyms1-dev libxcb-image0-dev \ libxcb-shm0-dev libxcb-util1-dev libxcb-xinerama0-dev \ libxcb-xkb-dev libxkbcommon-x11-dev libgl1-mesa-dev libgles2-mesa-dev \ libssl-dev libicu-dev libasound2-dev装完后rsync整个根文件系统到宿主机。用真实板子的sysroot,能最大程度保证编译环境和运行环境的一致性,后面出问题的概率小很多。
这里还有个小细节需要注意:rsync拷回来的sysroot里的动态库,很多都是符号链接。比如libc.so.6可能指向libc-2.31.so。做交叉编译时一定要保留这些符号链接,拷贝时记得加-l参数,否则之后工具链链接时会因为找不到真名而报错。
3.4 全局环境变量设置
所有环境都准备完毕后,建议把环境变量写到一个文件里,每次新开终端source一下就行。
# /opt/sysroot/env.sh export CROSS_COMPILE=aarch64-none-linux-gnu- export PATH=/opt/toolchains/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin:$PATH export SYSROOT=/opt/sysroot/aarch64 export CC=${CROSS_COMPILE}gcc export CXX=${CROSS_COMPILE}g++ export AR=${CROSS_COMPILE}ar export RANLIB=${CROSS_COMPILE}ranlib export LD=${CROSS_COMPILE}ld export STRIP=${CROSS_COMPILE}strip export CFLAGS="--sysroot=$SYSROOT" export CXXFLAGS="--sysroot=$SYSROOT" export LDFLAGS="--sysroot=$SYSROOT"这些变量在后面编译各种第三方依赖库时经常用到,提前配好能省下大量的重复劳动。
4. Qt 5.14.2源码获取与静态编译配置
4.1 源码下载与目录结构规划
Qt源码下载很简单,直接到官方仓库或者镜像拉取。我用的是清华镜像,速度快得多。
mkdir -p ~/qt-build cd ~/qt-build wget https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/5.14/5.14.2/single/qt-everywhere-src-5.14.2.tar.xz tar -xf qt-everywhere-src-5.14.2.tar.xz解压后可以看到完整的目录结构:qtbase是Qt的核心模块,qtserialport、qtcharts这些是附加模块。虽然qt-everywhere-src里包含全套模块,但嵌入式场景下没必要全部编译,只挑需要的模块编译可以大幅缩短编译时间。
Qt 5.14.2是Qt 5.15之前比较稳定、兼容性较好的版本,aarch64支持已经比较成熟,很多嵌入式产品公司至今仍把它作为首选版本。它的configure参数体系非常完善,静态编译的支持度也好。
4.2 configure参数逐项解析
进入源码目录,开始配置。configure参数是整个Qt交叉编译中最重要的,一个参数错了,轻则编译出来的库功能不全,重则直接编译失败。
我最终使用的configure命令如下,然后逐项解释:
cd qt-everywhere-src-5.14.2 mkdir -p build-static && cd build-static ../configure -prefix /opt/qt5.14.2-static-aarch64 \ -static \ -release \ -opensource \ -confirm-license \ -xplatform linux-aarch64-gnu-g++ \ -nomake examples \ -nomake tests \ -no-compile-examples \ -skip qtwebengine \ -skip qt3d \ -skip qtcanvas3d \ -skip qtpurchasing \ -skip qtvirtualkeyboard \ -skip qtscript \ -skip qtspeech \ -skip qtdoc \ -skip qtandroidextras \ -skip qtmacextras \ -skip qtwinextras \ -skip qtquickcontrols \ -skip qtquickcontrols2 \ -skip qtmultimedia \ -no-opengl \ -no-glib \ -no-icu \ -no-dbus \ -no-feature-dbus \ -qt-libpng \ -qt-libjpeg \ -qt-zlib \ -qt-freetype \ -qt-harfbuzz \ -qt-pcre \ -no-xcb \ -no-eglfs \ -linuxfb \ -no-cups \ -no-iconv \ -no-evdev \ -no-gif \ -no-feature-printdialog \ -v一个一个参数说:
- -prefix:指定安装路径,后续make install会把头文件、库文件装到这里。
- -static:核心中的核心,告诉Qt要生成静态库而不是动态库。
- -release:编译release版本,体积更小、性能更好。
- -opensource和-confirm-license:自动接受开源协议。
- -xplatform linux-aarch64-gnu-g++:告诉Qt使用哪个交叉平台配置。Qt自带这个平台文件,在qtbase/mkspecs/devices/目录下可以找到linux-aarch64-gnu-g++这个mkspec,它是专门针对aarch64 Linux场景的。
- -nomake和-skip:干掉不需要的模块和构建目标,缩短编译时间。
接下来说明一些关键的feature开关:
- -no-opengl:这个要重点解释。很多嵌入式板子没有完整的OpenGL驱动支持,即便有,静态编译时链接OpenGL也是一堆麻烦事。如果不需要GPU加速渲染,直接关掉OpenGL可以省掉大量依赖问题。需要注意,如果你的程序依赖Qt Quick 2D渲染或者需要GPU加速,那就不能关,反而要去配置eglfs和对应的GPU驱动。
- -no-icu:ICU负责Unicode和文本布局,体积巨大。如果目标平台不需要复杂的国际化文本处理,关闭后编译时间和体积都能减少很多。如果要做网页渲染或者复杂排版,就需要打开。
- -no-dbus:D-Bus是Linux桌面环境的进程间通信,纯嵌入式场景基本用不上,关掉。
- -qt-libpng/-qt-jibjpeg/-qt-zlib等一堆-qt开头的参数:让Qt使用自己携带的第三方库源码,而不是去系统sysroot里找。这一步可以极大减少对sysroot内容的要求,打包时也不用纠结库版本兼容性。
- -linuxfb:启用Linux Framebuffer平台插件。在无窗口系统的嵌入式板子上,这是最基础的GUI渲染方式,直接往/dev/fb0写像素。如果你的板子只有LCD屏没有桌面环境,这个参数确保有平台插件可用。
- -no-xcb和-no-eglfs:既然走了framebuffer路线,这两类显示后端都不需要,关掉减少依赖。
这里我用了-no-eglfs,如果你要接HDMI屏且GPU支持KMS/DRM,可以把-no-eglfs去掉,改成-eglfs,然后在运行时通过QT_QPA_PLATFORM=eglfs来指定平台插件。选择linuxfb还是eglfs,取决于你的显示方案和硬件能力,这一点在后续运行阶段还需要根据实际效果调整。
4.3 静态编译的系统依赖处理细节
上面的configure参数已经用了大量-qt开头参数让Qt自带第三方库,但有些系统库是绕不开的,必须让Qt使用sysroot里提供的版本,比如libfontconfig、libfreetype、libssl。如果你的程序用到字体渲染、网络请求这些功能,这些库是必需的。
这里有个容易犯的错误:为了让fontconfig正常工作,要把-fontconfig保留(不要加-no-fontconfig),但在编译之前,需要确认sysroot里有aarch64版本的fontconfig头文件和库文件。如果没有,Qt的configure会检测不到fontconfig,然后回退到使用内部的freetype,字体渲染效果会差一些。
检的方法很简单:
ls $SYSROOT/usr/include/fontconfig/fontconfig.h ls $SYSROOT/usr/lib/aarch64-linux-gnu/libfontconfig.so如果文件不存在,回到第3.3节,在板子上装库后重新同步sysroot。这一步保证Qt发现的fontconfig是我们准备的目标板系统版本,而不是宿主机x86_64的。
4.4 开始编译与常见编译错误现场
configure通过之后就开始编译。编译时间取决于机器性能,我用了8核心16线程的机器,大概40分钟。
make -j$(nproc)整个编译过程比较漫长,期间可能出现几个比较典型的错误:
第一个常见错误是“cannot find -ltsan”。这是工具链sysroot里缺少libtsan导致。检查一下sysroot/usr/lib/aarch64-linux-gnu下有没有libtsan相关的库,没有的话从板子上拷过来,或者直接apt安装libtsan0。
另一个是“GL/gl.h: No such file or directory”。就算加了-no-opengl,有些模块仍然会去检查OpenGL头文件。解决办法是在sysroot里装上libgl1-mesa-dev的aarch64版本,或者检查configure时是否真的排除干净了qt3d等涉及GL的模块。
还有一个容易遇到的,“error: ‘__GLIBC_PREREQ’ is not defined”。这个问题通常是sysroot和工具链版本不匹配导致的,比如老的工具链配新的glibc sysroot。我用的是gcc 10.3和配套的glibc,整体匹配度比较好,基本没遇到。
编译结束后安装:
make install安装完成后检查一下安装目录:
ls /opt/qt5.14.2-static-aarch64/lib/你会看到大量.a结尾的静态库文件,这就是我们想要的静态Qt库。
4.5 交叉编译Qt应用工程的qmake配置
Qt库编译安装完成后,给具体的Qt应用程序配置交叉编译环境就是最后一公里。这里常见的问题是qmake找不到合适的交叉工具链,或者编译时依然调用了宿主机的gcc。
在项目工程目录下,先确保Qt的bin目录在PATH里:
export PATH=/opt/qt5.14.2-static-aarch64/bin:$PATH用qmake生成Makefile,并确认工具链:
cd ~/projects/myapp /opt/qt5.14.2-static-aarch64/bin/qmakeqmake会根据安装时记录的mkspec自动选择交叉编译器。检查Makefile里是否出现aarch64-none-linux-gnu-g++,如果没有,那就是qmake没有按照预期工作。
比较稳妥的方式是创建一个qmake的交叉编译配置文件,放在设备mkspecs下面。这里我直接用一个简单的办法:在项目根目录建一个名叫“qmake-aarch64.conf”的文件,内容如下:
QMAKE_CC = aarch64-none-linux-gnu-gcc QMAKE_CXX = aarch64-none-linux-gnu-g++ QMAKE_LINK = aarch64-none-linux-gnu-g++ QMAKE_AR = aarch64-none-linux-gnu-ar cqs QMAKE_STRIP = aarch64-none-linux-gnu-strip然后在项目目录执行:
/opt/qt5.14.2-static-aarch64/bin/qmake -spec /opt/qt5.14.2-static-aarch64/mkspecs/linux-aarch64-gnu-g++ qmake-aarch64.conf再执行make,就能看到用交叉编译器在编译。编出来的可执行文件用file命令查看:
file myapp输出里有“ELF 64-bit LSB executable, ARM aarch64”就说明交叉编译成功。
5. 一个完整可运行的交叉编译工程示例
5.1 示例程序代码
理论部分说完,用一个完整的示例程序把整个流程串起来。目标很简单:一个Qt Widgets窗口程序,界面上有一个按钮,点击后弹出一个对话框。这个例子虽然小,但覆盖了静态交叉编译的主要节点。
先在项目目录新建main.cpp:
#include <QApplication> #include <QPushButton> #include <QMessageBox> int main(int argc, char *argv[]) { QApplication app(argc, argv); QPushButton button("Click Me"); QObject::connect(&button, &QPushButton::clicked, [&]() { QMessageBox::information(nullptr, "Info", "Hello from aarch64!"); }); button.resize(320, 240); button.show(); return app.exec(); }再新建工程文件myapp.pro:
QT += core gui widgets TARGET = myapp TEMPLATE = app CONFIG += c++17 SOURCES += main.cpp这个例子虽然简单,但已经用到了Qt Core、Gui、Widgets三个最核心的模块。如果这三个模块的静态链接都成功,其他模块基本也问题不大了。
5.2 完整编译与运行验证
按第4.5节的方法执行qmake并make:
cd ~/projects/myapp export PATH=/opt/qt5.14.2-static-aarch64/bin:$PATH /opt/qt5.14.2-static-aarch64/bin/qmake make -j$(nproc)make完成后,会生成一个静态链接的myapp可执行文件。用file命令确认架构和链接方式:
file myapp应该看到“ELF 64-bit LSB executable, ARM aarch64, ... statically linked”。
复制到目标板,直接执行:
./myapp -platform linuxfb如果前面配置正确,屏幕上会显示一个带按钮的窗口,点击按钮弹出提示框。整个过程不需要设置QTDIR,也不需要拷贝任何Qt库,这就是静态编译的价值所在。
5.3 平台插件选择说明
理论上,如果configure用了linuxfb,运行时需要用-platform linuxfb参数指定平台插件。不过我实测下来,如果只有linuxfb一个插件,Qt有时会默认选择它就启动,不需要额外指定。
如果你的系统还有eglfs插件,直接运行时不指定平台参数可能报“could not find a platform plugin”,这时用-platform eglfs或者-platform linuxfb指定一个就行。
静态编译的程序选择平台插件有一点需要注意:平台插件是“链接”进程序里的,所以运行时用-platform参数指定的是编译进去的插件之一。configure里编译了哪些平台插件,运行时就能用哪些。
6. 现场移植经验与问题避坑指南
6.1 sysroot缺失依赖导致配置失败
这是我最开始最容易犯的错。configure阶段报各种头文件缺失,后来才发现sysroot里缺了大量库。如果你是从板子上rsync的sysroot,先用这个命令检查依赖:
for f in /opt/sysroot/aarch64/usr/lib/aarch64-linux-gnu/*.so; do echo "== $f ==" aarch64-none-linux-gnu-readelf -d "$f" 2>/dev/null | grep NEEDED done这样可以一览无余地看到sysroot里的库依赖关系。如果有些库没在sysroot里,在板子上补装再重新同步即可。
6.2 静态链接时的strip策略
静态编译的可执行文件里包含大量的符号信息,体积膨胀得很厉害。我build完release版本大约35MB,经过strip操作能降到约17MB:
aarch64-none-linux-gnu-strip --strip-unneeded myapp这里有个取舍。strip之后,如果程序在板子上崩溃,gdb回溯堆栈时看不到符号名,排查问题困难很多。所以我一般保留一个没strip的版本用于调试,真正部署时再strip。
6.3 字体与中文显示问题
静态编译的程序在板子上运行,最常见的坑之一就是中文乱码或者字体发虚。原因是系统字体没有随程序一起部署。
最简单的解决办法:在程序代码里直接指定字体文件,用绝对路径加载:
#include <QFontDatabase> // 程序启动时加载外部字体 QFontDatabase::addApplicationFont("/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"); QFont font("Noto Sans CJK SC"); QApplication::setFont(font);前提是目标板上有这个字体文件。如果板子是精简系统,可能连字体文件都没有,那就需要把字体文件一起打包进去,并在代码里指定相对路径或固定路径。
6.4 Qt插件静态链接的初始化顺序
静态编译Qt时还有一个容易出问题的地方:插件和模块的初始化顺序。Qt使用Q_IMPORT_PLUGIN宏在编译期显式导入插件。如果程序运行时报“no such plugin”错误,尽管插件已经链接进程序了,通常是因为缺少Q_IMPORT_PLUGIN声明。
在main函数里加上:
#include <QtPlugin> Q_IMPORT_PLUGIN(QLinuxFbIntegrationPlugin)如果还需要其他插件,比如字体、图片格式的插件,可以继续往这里加对应的Q_IMPORT_PLUGIN。
不过,如果configure和qmake的处理都正常,qmake会自动生成plugin import文件,一般不需要手动添加。仅在程序报找不到插件时才需要检查这一步。
6.5 版本选择建议:Qt 5.14.2还是更高版本
最后聊一下版本选择的经验。Qt 5.14.2是我验证过的、在aarch64静态交叉编译场景下最稳的版本。如果你问为什么不用5.15 LTS或者6.x,说说我的看法。
5.15 LTS虽然维护周期长,但源码包不太容易直接下载,需要走在线安装器,自动化脚本集成起来比较麻烦。Qt 6.x的构建系统换成了CMake,配置逻辑变化很大,aarch64静态编译的坑比5.14.2多不少,除非你的新项目从设计上就需要Qt 6,否则没必要在那个上面折腾。
Qt 5.14.2恰好处于一个很微妙的位置:模块足够完整,QML/Qt Quick已经能正常使用,我对它的交叉编译configure行为非常熟悉,网上能找到的资料也足够多,遇到问题排查起来方便很多。对于生产环境的嵌入式项目,稳定性优先的同事,我的建议是先上5.14.2,等Qt 6的交叉编译生态成熟一些再考虑升级。
7. 我还有几句实在话要说
这套环境搭起来之后,它就成了我手上所有aarch64板卡Qt应用开发的标准底座。每次新起一个项目,直接用它来编译,省掉了重复搭建环境的时间。如果哪天我需要编译其他模块比如Qt Charts,只需要回到源码目录,单独qmake和make对应模块,再make install就能增量加上去,不需要重新编译整个Qt。
另外补充一个很少被提到的小经验:在编译Qt之前,建议先用一条简单的交叉编译命令验证工具链和sysroot能不能配合:
echo 'int main(){return 0;}' | aarch64-none-linux-gnu-gcc --sysroot=$SYSROOT -x c - -o /tmp/test && file /tmp/test如果这一步都不能生成aarch64可执行文件,那问题就在工具链或者sysroot,不要浪费时间去跑Qt的configure。很多次configure阶段报的莫名其妙的错误,根源就是这一步没做好。
交叉编译说到底是环境工程,环境搭对了,后面让Qt工作就是顺水推舟的事。希望这份手册能帮你少走几段弯路。如果你在实操中遇到我没写到的坑,欢迎去社区讨论,这类问题很多时候一个环境细节就能卡住好几天。