尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Qt 5.14.2 aarch64静态交叉编译环境从零搭建实战指南

Qt 5.14.2 aarch64静态交叉编译环境从零搭建实战指南 搞嵌入式 Linux 的兄弟应该都有过这种经历在 x86 主机上编译好的 Qt 程序拷到 ARM 板子上要么动态库版本对不上要么缺这个少那个最后在目标板上折腾半天。我这次做的这个项目就是从零开始搭一套完整的 Qt 5.14.2 静态交叉编译环境目标平台是 aarch64ARMv8 64 位一套组合拳打下来产出的可执行文件直接拷到板子上就能跑连动态库都不带。这篇手册我会把从工具链选择、sysroot 准备、configure 参数配置到编译部署的完整链路都拆开讲清楚中途踩过的坑、试错的细节也会一并整理出来希望能帮那些正在搞 Qt 交叉编译尤其是想用静态链接方案的朋友少走几个弯路。先说结论这套方案做完之后你得到的不是一个孤立的 Qt 编译产物而是一整套可复用的交叉编译基础设施。以后团队里谁要编 Qt 应用直接在这套环境里跑就行编译出来的二进制在 ARM 板子上直接执行不需要再操心库文件拷贝和链接路径的问题。适合人群也很明确做嵌入式 Linux 开发、车载设备、边缘网关、工控 HMI 的工程师以及那些被动态库部署折磨过、想彻底解决运行时依赖问题的朋友们。在正式开工之前我强烈建议你先搞清楚一个核心问题为什么要用静态编译静态编译意味着所有 Qt 库的代码都被直接塞进了你最终的可执行文件里程序跑起来不再需要libQt5Core.so、libQt5Gui.so这些外部的动态库。好处非常直接第一是部署简单一个文件拷过去就完事第二是版本不会乱不会因为升级了系统库导致程序崩掉第三是在某些需要开机自启、精简 rootfs 的场景下静态编译能让你的程序完全自包含。代价也很明显可执行文件的体积会变大而且如果涉及 GPL 协议你需要留意相关的开源合规义务。但就嵌入式发布而言静态编译绝对是最省心的一条路。这套环境的宿主机器我推荐直接用 Ubuntu 20.04 或 22.04 x86_64 系统不要拿 Windows 的 WSL 做生产环境我试过文件权限和路径长度的问题会让人崩溃。准备好一台干净的 Linux 主机确认磁盘剩余空间不少于 50GB因为 Qt 源码加编译产物加起来相当占地方。下面进入正题。1. 整体方案设计与核心思路拆解1.1 为什么不直接用 apt 装 qmake而要自己编译很多刚上手的朋友第一反应是直接apt install qt5-qmake然后再装个gcc-aarch64-linux-gnu是不是就行了这个想法本身没毛病但你打开仓库看一眼就会发现问题发行版仓库里的 Qt 包基本都是针对宿主架构编译的动态库版本即使你装了libqt5gui5那也是 x86_64 的二进制。你需要的是能在编译期给 aarch64 目标板生成代码的交叉工具链以及那个目标板上的 sysroot 环境。用 apt 装出来的 qmake 是个原生 x86_64 程序它配置出来的 Qt 模块、特性开关全是按照桌面环境来的。你拿它去做 aarch64 的交叉编译首先它不知道头文件在哪也不知道目标平台的库该去哪里找就算你把-sysroot参数硬塞给它它内部检测逻辑也会乱套。最要命的是一些 Qt 的 feature 检测在交叉环境下根本跑不了直接导致 Qt 库编译不出来正确的平台插件。所以结论就是想搞一套真正好用的 aarch64 静态 Qt必须从源码编译而且要用 Qt 官方提供的交叉编译机制让 configure 阶段生成一套专属于目标的配置后续所有应用的 qmake 都走这套配置才能保证整个链路的统一和稳定。1.2 方案选型Sysroot 交叉工具链 静态 Qt 的组合拳这套方案的核心理念是三个独立的部分拼成一个完整的闭环aarch64 交叉工具链包括aarch64-linux-gnu-gcc、g、ar、strip等目标板根文件系统sysroot提供 aarch64 的基础 libc 和内核头文件Qt 5.14.2 源码包通过静态配置生成 aarch64 专用库把这三个部分准备好之后用./configure指定-xplatform linux-aarch64-gnu-g和-static就能让 Qt 的构建系统在宿主机器上编译出面向 aarch64 的静态库。之后的每一个 Qt 应用工程都用这套环境里的 qmake 来生成 Makefile编译出来的程序自然就是静态的。这里要解释一下 sysroot 是什么。交叉编译器默认的目标环境和你这只是个编译器可不够编译器在编译过程中需要找到目标平台的系统头文件和库文件。--sysroot参数就是告诉编译器往这个目录里去寻找/usr/include和/usr/lib等内容。sysroot 目录里的内容怎么来最靠谱的办法是拿一块和目标板系统同版本的 rootfs比如你板子的操作系统是 Ubuntu base 或 Debian rootfs直接把它拷出来放到一个目录下然后用sysroot-relativelink.py脚本把软链接修正一下保证库文件路径都是相对的即可。1.3 为啥选 Qt 5.14.2 而不是新版本Qt 5.15 之后官方把开源版本的 LTS 支持政策调整了很多离线安装包变得不那么好找。5.14.2 是 Qt 5.14 系列的最后一个补丁版本稳定性经过了大量工业应用的验证在嵌入式领域尤其活跃。很多摄像头方案、工业平板方案都基于这个版本开发的社区讨论多踩坑资料丰富。5.14.2 对 boards 和 toolchains 的兼容性也是一个考量。aarch64 的交叉编译在这个版本上属于完全成熟的路线configure 配置脚本对 ARM 平台的支持已经非常完善不再需要像早期版本那样打一大堆 patch。再加上 5.14.2 的源码包在 Qt 官网和国内镜像站都能直接下载不需要注册账号对自动化构建来说非常友好。你要是贪新鲜去用 Qt 6配置方式又有变化模块划分也调整了除非你有特别的需求否则做嵌入式静态编译5.14.2 是个极其稳妥的选择。2. 工具链与 sysroot 准备2.1 交叉编译工具链的安装与版本验证Ubuntu 主机上安装交叉工具链非常简单直接用 aptsudo apt update sudo apt install -y build-essential sudo apt install -y gcc-aarch64-linux-gnu g-aarch64-linux-gnu这个包名在 Ubuntu 20.04 和 22.04 都有版本是 GCC 9 或 GCC 10编译 Qt 5.14.2 完全没压力。装完之后验证一下编译器是否能正常执行aarch64-linux-gnu-gcc --version看到类似aarch64-linux-gnu-gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0这样输出就说明工具链正常。这里有个细节工具链的版本不要追求太新太新的 GCC 有时候会在编译 Qt 源码时抛出新的警告甚至错误反而得不偿失。GCC 9 系列的兼容性是最稳妥的。我见过有人为了追求性能去装 Linaro 或者 ARM 官方工具链Linaro 的版本更新更快但说实话编译 Qt 这种大型项目Ubuntu 自带的交叉工具链已经足够。Linaro 工具链的优势主要体现在一些高度优化的数学库上面对于绝大多数 Qt 应用场景差别可以忽略不计。2.2 构建 sysroot从基础 rootfs 到编译环境目录一份理想的 sysroot就是目标板根文件系统的精简副本。最简单的方法是先下载一个目标平台的 Ubuntu base rootfsmkdir -p ~/aarch64-sysroot cd ~/aarch64-sysroot wget http://cdimage.ubuntu.com/ubuntu-base/releases/20.04/release/ubuntu-base-20.04.5-base-arm64.tar.gz sudo tar -xzf ubuntu-base-20.04.5-base-arm64.tar.gz -C ~/aarch64-sysroot解压后获得的~/aarch64-sysroot内部结构就是经典的 Linux 根文件系统有usr、lib、etc等目录。不过直接这样拿到手的 sysroot 有两个问题需要处理。第一个是动态库符号链接问题。rootfs 里的.so文件普遍是软链接链接到具体版本的库文件这些软链接如果带绝对路径交叉编译器拿到之后会往宿主机路径去搜索直接找不到。解决办法是使用sysroot-relativelink.py这个脚本把软链接从绝对路径改成相对路径。这个脚本在多个开源项目仓库里都有也可以自己写核心逻辑就是遍历 sysroot 下所有的符号链接如果链接目标是绝对路径就把它改成相对于链接所在目录的相对路径。第二个问题是你可能还需要额外安装一些依赖库到头文件。比如如果 Qt 要支持libpng、libjpeg这些图片格式这些库的 aarch64 头文件和.so就得提前放进 sysroot。可以用chroot外加qemu-aarch64-static的方式进入 sysroot 然后apt install也可以直接在宿主机上用apt download加dpkg -x的方式手动解压。我推荐后面这种简单粗暴不容易出错。2.3 工具链与 sysroot 的统一验证在正式编译 Qt 之前建议先编译一个最小的 C 程序来验证工具链和 sysroot 之间的配合是否正常aarch64-linux-gnu-gcc --sysroot$HOME/aarch64-sysroot -o hello hello.c file hello如果输出的文件类型是ELF 64-bit LSB executable, ARM aarch64那说明工具链、sysroot 的配合没有问题。这一步虽然看起来简单却能节省后面排查问题的巨量时间。我在第一次配置的时候跳过这个验证结果 configure 阶段报了一堆找不到头文件的错误最后才发现是 sysroot 路径没有写对白白浪费了半小时。3. Qt 5.14.2 源码获取与 configure 配置3.1 源码下载与目录规划Qt 5.14.2 的源码包命名是qt-everywhere-src-5.14.2.tar.xz体积大概在 600MB 左右。下载地址可以在 Qt 官方仓库的 archive 目录找到国内也有很多高校镜像站、云厂商镜像站同步了这份源码包挑个网络距离近的下就行。下载完成后解压把源码目录和编译输出目录分开这样方便以后清理和重复编译mkdir -p ~/qt-build tar -xJf qt-everywhere-src-5.14.2.tar.xz -C ~/qt-build cd ~/qt-build/qt-everywhere-src-5.14.2为什么要分开因为 Qt 的源码目录在做完 configure 之后会生成大量 Makefile 和.o中间文件这些中间文件占空间不说如果直接放在源码目录里想找一个干净的源码树做对比就会很痛苦。另外Qt 支持 shadow build也就是在源码目录之外的地方编译产物和源码隔离后续如果想打一个干净的补丁集只要重新解压源码即可。3.2 configure 参数逐项解析-static、-xplatform、-prefix 等这是整个流程里最关键的一步配置参数会直接决定你编译出来的 Qt 长什么样。这里给出我实际使用的配置命令行./configure \ -prefix /opt/qt5.14.2-aarch64 \ -xplatform linux-aarch64-gnu-g \ -static \ -release \ -opensource \ -confirm-license \ -nomake examples \ -nomake tests \ -skip qtdeclarative \ -skip qtquickcontrols2 \ -no-opengl \ -no-icu \ -no-dbus \ -no-feature-cups \ -sysroot $HOME/aarch64-sysroot \ -device-option CROSS_COMPILEaarch64-linux-gnu-逐个参数讲一下背后的逻辑-prefix /opt/qt5.14.2-aarch64表示编译完成之后安装的路径。这个路径会被写进 qmake 的配置里后续所有使用这个 qmake 编译的应用都会用这个路径找 Qt 库和头文件。对于嵌入式交叉编译来说这个 prefix 并不需要真的创建在目标板上它只是一个逻辑路径qmake 在交叉编译时会自动拼接 sysroot 和 prefix 来找到对应的资源。-xplatform linux-aarch64-gnu-g是告诉 Qt 的构建系统你手头这套工具链的目标平台是 aarch64。Qt 源码里mkspecs目录下预先定义了各种平台的编译规则linux-aarch64-gnu-g就是其中之一它对应 GCC 交叉编译器的一套标准配置。如果你的工具链不是标准的aarch64-linux-gnu-前缀需要在这个 mkspec 文件里修改QMAKE_CC和QMAKE_CXX。-static是核心中的核心直接决定编译产物是静态库.a文件而不是动态库.so文件。一旦选择静态编译Qt 的所有模块会被打成.a文件你后续的应用编译时会把这些库文件链接到最终可执行文件中。-no-opengl和-no-icu是面向嵌入式场景的裁剪。很多板子都用不到桌面级 OpenGL如果屏上没有 GPU 加速opengl 的库只会增加编译时间和 sysroot 依赖。ICU 库非常庞大在没有复杂的文本排版和 Unicode 要求时直接关掉能省下一大截编译时间还能避开 sysroot 需要额外提供 libicuuc.so 等库的麻烦。-skip qtdeclarative跳过 QML 相关的模块。如果你们的产品界面是纯 Widgets 的这一刀切下去会让编译速度快很多。QML 的 JIT 引擎在静态编译时也有不少需要注意的细节不是不能用而是没必要给自己加戏。同样的-skip qtquickcontrols2也是这个逻辑。-no-feature-cups关闭打印机支持。Qt 的 configure 会检测到 sysroot 里可能没有 cups 的头文件为了保险起见直接禁用这个 feature免得配置阶段自动检测失败导致 configure 中断。-sysroot $HOME/aarch64-sysroot就是告诉交叉编译器目标根文件系统的位置编译器会在这个目录下找/usr/include、/usr/lib等路径。-device-option CROSS_COMPILEaarch64-linux-gnu-是给 mkspec 指定交叉编译器的前缀。这样 qmake 会去 PATH 里找aarch64-linux-gnu-gcc和aarch64-linux-gnu-g。3.3 静态编译需要额外处理的细节仔细观察上面 configure 参数你会发现我没有写-no-xcb。Qt 在 Linux 下的 GUI 后端默认是 xcb但静态编译的时候这个插件是有坑的。为了精简链路我通常会在 configure 时加上-no-xcb除非你的目标板上确实跑着 X11 Server。绝大多数嵌入式 Qt 应用用的是 linuxfb 或者 eglfs这两个插件在静态编译时不需要额外依赖 X11 的库。另外还有一个小细节静态编译时 Qt 的 SQL 驱动插件默认是不会自动加载的。如果你用了 Qt SQL 模块需要在代码里手动 import 对应的 driver plugin或者用 Q_IMPORT_PLUGIN 宏。因为静态插件不会像动态插件那样在运行目录里扫描 .so你必须在代码里显式地把插件编译进去。这个点后面在验证环节我还会提。关于 configure 阶段的检测Qt 会尝试编译一些小测试程序来验证某些特性是否可用。交叉编译环境下这些测试程序默认是不能在宿主机上直接运行的Qt 本身有一套交叉检测机制它只会编译不会运行然后根据编译是否成功来判断 feature 是否开启。所以有些特性比如某些依赖运行时行为的检测在交叉编译时可能默认被关闭这是正常的不用慌。3.4 make 编译与常见加速技巧配置成功之后会生成 Makefile这时候开始正式编译make -j$(nproc)$(nproc)是取 CPU 核数根据自己的机器配置调整并行度。如果机器内存小于 16GB建议不要开满所有核因为每个编译进程都会吃不少内存开满内存不够会直接 OOM。我自己的机器是 8 核 16GB 内存用make -j8比较稳。如果内存确实比较小可以用make -j4无非就是多等一段时间。编译 Qt 静态库整个过程会持续大概 40 到 90 分钟取决于机器性能。这期间得上点心时不时看一眼屏幕因为有些文件因为依赖顺序问题会触发并行编译的竞争条件偶尔会出现个别文件编译失败的情况。如果看到失败先不要急着重新 configure直接再跑一次make -j4往往就能通过。编译完成后执行安装make install安装目录就是之前指定的/opt/qt5.14.2-aarch64。安装完成后可以检查目录下是否生成了静态库文件find /opt/qt5.14.2-aarch64 -name *.a | head看到一堆.a文件落盘说明静态库编译成功。4. 应用工程的交叉编译与静态链接部署4.1 qmake 环境变量配置与工程文件编写Qt 库编译好之后下一步就是编译我们自己的应用。这里要先设置环境变量让系统能找到交叉 qmakeexport PATH/opt/qt5.14.2-aarch64/bin:$PATH export QMAKE/opt/qt5.14.2-aarch64/bin/qmake export LD_LIBRARY_PATH/opt/qt5.14.2-aarch64/lib:$LD_LIBRARY_PATH关于这三个环境变量多说两句。PATH 是为了让qmake命令行直接可用QMAKE 有些脚本里会显式指定 qmake 的绝对路径提前导出方便后面调用LD_LIBRARY_PATH 其实是给宿主机上运行的 qmake 找它依赖的库。qmake 本身是个 x86_64 程序但它的 Qt 库位于交叉编译的前缀目录下而这些 Qt 库又可能是我们编译出的 x86_64 版本的辅助工具依赖的。这里容易晕简单记忆就是编译时用的工具链是 aarch64 的但宿主上运行的 qmake 和辅助工具还是 x86_64 的它们依赖的库是独立的。工程文件.pro的写法有一个关键参数必须加上QT core gui greaterThan(QT_MAJOR_VERSION, 4): QT widgets TARGET myapp TEMPLATE app SOURCES main.cpp mainwindow.cpp HEADERS mainwindow.h静态 Qt 的应用和自己写链接脚本不同qmake 的TEMPLATE app会自动替你做静态链接你不需要在.pro里写CONFIG static因为工具的 qmake 本身已经配置成静态模式了。如果你要用到 Qt 的插件比如 linuxfb 平台插件、图片格式插件需要在代码里加上导入声明#include QtPlugin Q_IMPORT_PLUGIN(QLinuxFbIntegrationPlugin) Q_IMPORT_PLUGIN(QGifPlugin) Q_IMPORT_PLUGIN(QJpegPlugin)静态插件的机制就是你编译进程序里的插件只有通过 Q_IMPORT_PLUGIN 显式声明之后Qt 的插件管理器才能在运行时认识到它们的存在。不加这些宏程序运行起来会提示no such platform plugin甚至直接黑屏。4.2 编译验证从 qmake 到最终二进制的完整链路编译工程/opt/qt5.14.2-aarch64/bin/qmake myapp.pro make -j4这里 qmake 生成 Makefile 的路径是要注意的。我建议在工程目录下直接编译这样 Makefile 就在当前目录生成。如果你把源码放到别的目录然后用 qmake 指定.pro文件的路径生成的 Makefile 会在当前目录这样也是可以的只是后续管理产物的思路要清楚。编译完成后检查产物类型file myapp输出应该类似myapp: ELF 64-bit LSB executable, ARM aarch64, dynamically linked (uses shared libs), for GNU/Linux 3.7.0注意这里显示的还是dynamically linked主要是因为它还链接了 libc、libstdc 这些系统库。如果追求真正的完全静态连 libc 都不想依赖可以加-static-libgcc -static-libstdc参数或者干脆在.pro里加QMAKE_LFLAGS -static但要提醒一句完全静态的 Qt 程序在 glibc 环境下有时候会有 getaddrinfo 和 NSS 相关的隐患如果你用到了网络功能比如访问域名需要特别注意。我的建议是Qt 库静态链接但 libc 保持动态链接这样既避免了复杂的部署问题又规避了 glibc 完全静态的坑。在嵌入式板子上libc 基本都是自带的基础组件不存在版本适配的问题。4.3 部署到 aarch64 目标板的正确姿势把编译好的myapp传到板子上比如用 scpscp myapp root192.168.1.100:/usr/local/bin/如果 Qt 库是静态链接的那这一步就结束了。直接在板子上chmod x然后运行chmod x /usr/local/bin/myapp /usr/local/bin/myapp板子上不需要设置LD_LIBRARY_PATH不需要把/opt/qt5.14.2-aarch64/lib拷贝过去也不需要安装任何 Qt 运行时。这就是静态编译最大的爽点拷过去能跑。如果我的 Qt 还链了一些第三方静态库比如 libssl、libcrypto那编译时确保它们也是.a文件或者使用-static选项产物仍然能够自包含。如果你在板子上跑 GUI 程序需要确保使用 linuxfb 平台插件./myapp -platform linuxfblinuxfb 插件会直接写帧缓冲设备/dev/fb0前提是板子上的 framebuffer 设备已经初始化好了。如果你的板子用 DRM 驱动也可以试试eglfs或者linuxfb的 DRM 变种但最简单的验证方式还是 linuxfb。5. 常见问题与排查技巧实录5.1 configure 报错 “The specified sysroot is invalid”这个报错很常见通常是 sysroot 路径写错或者 sysroot 目录下缺少必要的子目录。Qt 的 configure 脚本会检查 sysroot 是否存在/usr/lib等关键目录如果不存在就认为 sysroot 无效。检查方式ls $HOME/aarch64-sysroot/usr/lib如果发现解压的 rootfs 里没有usr/lib只有lib很可能是你下载的 rootfs 把库放在/lib下了。Ubuntu base 的 arm64 rootfs 默认会把库放到/usr/lib/aarch64-linux-gnu和/lib/aarch64-linux-gnu而/usr/lib本身是存在的。如果你用的是精简过度的 rootfs可能需要手动创建目录结构或者换一个更完整的 rootfs。5.2 编译 QObject 相关代码时出现 “undefined reference to vtable”这个问题一般出现在静态编译环境中。你在源码里定义的 QObject 子类如果类里包含了Q_OBJECT宏元对象编译器moc需要把头文件生成对应的moc_xxx.cpp文件并参与编译。如果是 qmake 管理的工程qmake 会自动处理这个依赖关系但如果你是直接手动编译源代码绕过了 qmake就很容易忘记把 moc 生成的代码编译进去。解决方法是把整个工程纳入 qmake 管理确保头文件里声明了Q_OBJECT的类能被 qmake 正确检测。如果你是从别的构建系统迁移过来的可以在.pro文件中显式写HEADERS myclass.hqmake 会自动发现myclass.h里的Q_OBJECT并生成对应 moc 文件不需要手动运行 moc。5.3 程序运行时报 “This plugin does not support propagateSizeHints()”这个问题在 linuxfb 平台插件下偶有出现原因是 Qt 静态编译时没有正确导入linuxfb插件。我在 4.1 提到了Q_IMPORT_PLUGIN(QLinuxFbIntegrationPlugin)如果漏掉了这行Qt 默认只会尝试加载动态插件动态插件又不存在就会报这个错。另一个可能原因是 configure 时没有启用 linuxfb 插件。Qt 的 configure 参数里-linuxfb是默认启用的但如果你用了某些裁剪脚本把 feature 关了就会导致插件没有编译出来。检查方式find /opt/qt5.14.2-aarch64/plugins -name *linuxfb*如果找到libqlinuxfb.a文件说明插件是编译出来了的问题就只在于你的程序没把它链接进来如果压根没有这个文件那就说明 configure 时把插件禁用了需要回去检查 configure 参数。5.4 静态编译后程序体积过大如何针对性裁剪纯静态的 Qt Widgets 程序体积通常在 20MB 到 60MB 之间具体大小取决于你启用了哪些 Qt 模块。如果你觉得体积超标首先要做的就是检查是不是无意中链接了用不到的大型模块。我曾经遇到过有人只是写了个串口助手结果把 Qt Multimedia 和 Qt WebEngine 相关的库也拖了进去体积直接冲到 200MB。裁剪的思路是在 configure 阶段尽量-skip不需要的模块同时用-no-feature-*关闭不需要的特性。另外编译 release 版本身会去掉调试符号能减少一些体积。最后可以用strip工具对最终可执行文件做一次瘦身aarch64-linux-gnu-strip myappstrip 之后体积能再砍掉百分之十到二十而且不影响程序运行。需要注意的是strip 必须在 ARM 工具链下的 strip 做不能用 x86 的 strip否则会把 ARM 的可执行文件弄坏。5.5 交叉编译 Qt 应用时找不到第三方库OpenSSL、sqlite 等这个问题在实际项目中非常常见。如果你的 Qt 应用需要访问 HTTPS 或者用 SQLiteQt 的 configure 阶段会自动去 sysroot 里找 OpenSSL 和 SQLite 的头文件和库。找不到的话Qt 会自动禁用相关模块编译出来的 Qt 库就不带这些功能后续应用链接时就报 undefined reference。解决方法是先把这些第三方依赖库的 aarch64 版本装进 sysroot。对于 OpenSSL可以用交叉编译器直接编译一份静态库然后把头文件放到 sysroot 的/usr/include把.a文件放到/usr/lib/aarch64-linux-gnu。更省事的方案是直接拿板子同版本的 rootfs 里的库文件拷贝到 sysroot 中。我自己一般直接用静态 OpenSSL 编译 Qt这样最终可执行文件里就带了 SSL 功能。static 版本的 OpenSSL 编译参数大致是./Configure linux-aarch64 no-shared --prefix$HOME/aarch64-sysroot/usr make make install装好之后回头重新 configure 一次 Qt确认 configure 输出中有OpenSSL: yes就可以放心用了。5.6 板上运行 GUI 出现花屏或宽高不对花屏问题多半和 framebuffer 的分辨率与色深配置有关。Qt 的 linuxfb 插件默认会读/etc/fb.modes或通过fbdev设备节点拿到当前显示参数。如果你的板子在内核启动参数里设置了video或者fbcon确保这些参数的格式正确。另外可以在启动 Qt 程序时手动指定屏幕尺寸./myapp -platform linuxfb:fb/dev/fb0:width1024:height600:depth32这样可以强制覆盖 framebuffer 的分辨率和色深避免因为内核初始化的显示参数不匹配引发的显示异常。6. 整个方案的扩展思考与后续优化方向这套环境沉淀下来之后不只是 Qt 应用开发能用。你在交叉编译 nginx、phantomjs 这类源码包的时候sysroot 和工具链都是同一套底子直接指定 CC 和 sysroot 就能用。我在完成 Qt 构建之后顺便在同一个 sysroot 底下把 nginx 的 aarch64 版本也编了一遍用的就是这套工具链非常顺手。做性能测试的人如果需要在 gem5 模拟器里跑 SPEC2006也能用这套工具链编译出 aarch64 指令集的 benchmark 程序整体投入产出比很高。后续可以优化的方向有这么几个一是工程化封装。现在整个流程是手工命令一步步敲的你可以把工具链配置、sysroot 准备、Qt configure、应用编译封装成一套 CI 脚本提交代码之后自动出 aarch64 静态可执行文件团队其他成员不用关心编译细节直接拿产物去板子上刷。二是多板型适配。不同板子的 framebuffer、GPU 驱动不一样但 Qt 库本身是通用的。你只要在应用层做好分辨率和输入设备的自适应配置一套 Qt 库可以覆盖多个产品线的板子后续维护成本能降不少。三是版本升级路径。Qt 5.14.2 这套老环境可以保留新项目可以直接用 Qt 5.15 或 Qt 6 做同样的静态交叉编译。到时候 configure 参数会有小幅调整但核心原理是一样的把这份手册里讲的逻辑迁移过去就行。最后再补充一个我觉得很有价值的细节把 configure 的参数完整记录到 README 里包括每台机器的编译日期、sysroot 来源、工具链版本、补丁情况。你永远不知道半年后回来看这套环境时会不会忘记当初为什么加了一个奇奇怪怪的-no-feature-cups。文档化所有构建参数能让这套环境真正成为团队的基础设施而不是个人脑子里的经验。根据我的实际操作体验静态交叉编译 Qt 这事的难点不在编译本身而在于把编译过程和后续的应用开发流程打通。只要 configure 参数合理、sysroot 完整、工具的链路清晰后面所有的工程都会变得很顺。哪怕你之前从来没有碰过 ARM 开发照着这篇手册把环境搭起来编译出第一个能在板子上跑起来的静态 Qt 程序你就能直观感受到这套方案的强大之处了。
返回列表