aarch64 Qt5.12.12 交叉编译:sysroot 与 mkspec

发布时间:2026/9/20 11:40:22
aarch64 Qt5.12.12 交叉编译:sysroot 与 mkspec 简介面向嵌入式Linux与Qt开发者的交叉编译环境配置指南聚焦在Ubuntu 20.04上搭建Qt5.12.12搭配aarch64-linux-gnu工具链的完整流程。资源为1个PDF文档约4MB内容涵盖从petalinux2018.3中提取交叉编译器、配置环境变量与SYSROOT到修改qmake.conf、设置QPA平台抽象插件、安装音视频与图形依赖库、执行configure与make编译安装的全部环节并标注了Linaro GCC 7.3版本验证方式与无报错编译细节。文档以图文结合方式给出关键配置的终端回显还整理了qmake模板参考、OpenGL支持失败、make与g缺失等典型问题的排查思路以及Qt在线安装工具的版本选择建议强调交叉编译库与主机工具链的一致性。目前已有12360人学习适合需要在ARM架构设备上运行Qt应用的开发者参考能帮助读者快速理解交叉编译平台的配置逻辑减少重复踩坑并可作为搭建类似ARM端Qt编译环境的对照手册。1. 从 x86 桌面到 aarch64 目标板Qt5.12.12 交叉编译要解决的三个错位在 Ubuntu 20.04 上敲一句apt install qt5-defaultqmake 是有了编出来的程序拷到 OrangePi CM5、树莓派 4B 这类 aarch64 板子上第一反应通常是Exec format error——因为那份 qmake 是给 x86_64 用的产出的是 x86 ELF指令集那一层就对不上。第二个错位在库路径即便你手工用交叉 g 把程序编出来了链接阶段找的是宿主机/usr/lib/x86_64-linux-gnu里的libQt5Core.soABI 不匹配直接报 incompatible。第三个错位在运行时板子上没有/opt/Qt5.12.12/lib字体目录为空、libQt5Gui.so加载不到程序一启动就死在平台插件初始化。这套环境要做的就是一次性把这三处对齐宿主机装aarch64-linux-gnu工具链用一份和目标板 rootfs 同源的 sysroot 顶掉宿主机头文件与库再把 Qt 5.12.12 源码按 aarch64 重新 configure 一遍产出一套能整体 rsync 到板子上的 Qt。做完之后宿主机上一次 qmake、一次 make产物直接上板能跑。适合做嵌入式 HMI、工控屏、机器人上位机这类需要在 ARM 板子上跑 Qt 界面的场景。2. aarch64-linux-gnu 交叉编译工具链在 Ubuntu 20.04 上的安装与自检2.1 apt 源里的工具链和厂商 SDK 自带那份怎么选Ubuntu 20.04 官方源里就有gcc-aarch64-linux-gnu、g-aarch64-linux-gnu装完前缀是aarch64-linux-gnu-落地在/usr/bin。它带来的好处是版本稳定、头文件齐全、和宿主机的 glibc 同代编 Qt 这种体量的工程不容易在头文件上卡住。缺点是它面向的是通用aarch64-linux-gnu目标不带任何厂商的启动流程和特殊浮点选项——但对编 Qt 用户态库这件事这一点无所谓。另一条路是用板卡厂商 SDK 里那份工具链或者芯片原厂发布的预编译包。它的优势是 ABI、浮点 ABIhard/soft、glibc 版本这些细节和官方 BSP 完全一致最不容易出玄学问题。代价是要手工加 PATH而且不同厂商的目录嵌套风格差别很大脚本不好写通用。我的建议是先用 apt 那份把整条链路跑通确认 Qt 能在板子上起来等真的要交付再换成厂商 SDK 那份重编一次。两条路除了QMAKE_CC那几行的路径不同其余流程完全一致。# 宿主机 Ubuntu 20.04安装 aarch64 交叉工具链 sudo apt update sudo apt install -y gcc-aarch64-linux-gnu g-aarch64-linux-gnu \ binutils-aarch64-linux-gnu \ qemu-user-static rsync cmake ninja-build # 如果是多架构先确认自己没把 arm64 当外架构源误加进去 dpkg --print-foreign-architectures这几条命令里qemu-user-static是给后续本地跑 aarch64 二进制做验证用的binutils单独列出来是因为有时候 apt 只装了 gcc 没把aarch64-linux-gnu-ld带上。最后那条dpkg --print-foreign-architectures用来确认当前系统有没有被误加过arm64外架构——如果有后面装依赖包时 apt 会尝试去拉 arm64 的 dev 包覆盖 amd64 的很容易把宿主机环境搞坏看到非空输出要先dpkg --remove-architecture arm64清掉。2.2 交叉工具链的三条自检命令装完不要直接进 Qt 源码目录先用三条命令确认工具链是活的。aarch64-linux-gnu-gcc -dumpmachine aarch64-linux-gnu-gcc -v 21 | tail -n 3 aarch64-linux-gnu-g -print-sysroot第一条应该输出aarch64-linux-gnu出现x86_64说明 PATH 里被别的同名工具抢了第二条看它报的 target 和线程模型确认没有把arm-linux-gnueabihf的配置混进来第三条打印默认 sysrootapt 装的这套通常输出为空或者/说明它直接用宿主机的/usr/include——这也正是后面必须显式加--sysroot的原因。三条都符合预期再往下走。2.3 用一段最小 C 程序验证链接与运行真正跑一次编译链接比看版本号靠谱。// hello.cpp验证工具链能否编出 aarch64 可执行文件 #include cstdio #include string int main() { std::string s hello aarch64; std::printf(%s\n, s.c_str()); return 0; }# 静态编译避免本地 qemu 跑的时候缺 aarch64 版 libstdc aarch64-linux-gnu-g -static hello.cpp -o hello_arm64 file hello_arm64 qemu-aarch64-static ./hello_arm64-static是刻意加的本机没装 aarch64 版的 libstdc动态链接时 qemu 会报找不到.so.6静态链接把这层绕过去只验证「编得出、链接得过、能执行」三件事。file输出里出现ARM aarch64才算过。这一步用不了 qemu 也没关系把hello_arm64scp 到板子上跑一遍同样能确认。若file报的是x86-64说明用了错误的编译器回去检查qmake.conf或命令里的前缀。检查项期望输出异常时的常见原因-dumpmachineaarch64-linux-gnuPATH 被同名 x86 工具覆盖file产物ELF 64-bit LSB, ARM aarch64用了宿主 g 而非交叉 gqemu-aarch64-static运行正常打印动态链接缺 aarch64 libc-print-sysroot为空或/正常需命令行显式指定3. 目标板 sysroot 的抓取与 Qt5.12.12 依赖库的交叉编译3.1 从板子 rsync 一份 sysroot 到宿主机Qt 编 aarch64 版本时会去找一堆系统库的头和.solibdrm、libpng、libpthread、libfontconfig等。这些包在宿主机的/usr/include里全是 x86_64 的版本直接拿过去编会撞 ABI。最省力的做法是把目标板上的运行环境整体抓一份下来当 sysroot。# 在宿主机执行从板子拉取运行环境 sudo mkdir -p /opt/sysroot sudo rsync -avz --delete \ --exclude/proc --exclude/sys --exclude/dev \ --exclude/run --exclude/tmp \ --exclude/etc/ssh \ root192.168.1.100:/lib /opt/sysroot/ sudo rsync -avz root192.168.1.100:/usr/lib /opt/sysroot/usr/ sudo rsync -avz root192.168.1.100:/usr/include /opt/sysroot/usr/-a保留符号链接这一点很关键很多发行版里/lib是指向/usr/lib的软链如果 rsync 把链接解开成实体目录链接期会因为路径重复报警告甚至-rpath-link找不到库。--exclude掉/proc、/sys、/dev是避免抓到挂载点和字符设备节点/etc/ssh只是个人信息卫生习惯跟编译无关。抓完检查一下ls /opt/sysroot/lib/ld-linux-aarch64.so.1是否存在这是交叉链接器最后的依赖缺了链接一定失败。3.2 哪些依赖能从 sysroot 拿哪些必须自己编从板子抓下来的 sysroot 通常只有运行时.so和少量.h没有.pc文件也没有-devpackage 里的静态库和头。判断某个依赖要不要自己编看三件事头文件在不在、.so符号链接在不在、.pc文件在不在。# 快速体检某个库是否可直接用于 Qt 编译 LIBlibpng16 ls /opt/sysroot/usr/include/libpng16/png.h # 头 ls /opt/sysroot/usr/lib/aarch64-linux-gnu/libpng* # 动态库与 .so 软链 find /opt/sysroot -name ${LIB}.pc # pkg-config 文件三样齐了就可以直接指向 sysroot 让 Qt configure 去用缺了.h或.pc就得自己交叉编译一份装进 sysroot。这个判断特别重要因为一旦漏了某个库Qt configure 会静默地把对应 feature 关掉你会在编到一半时才发现缺功能。注意不要试图用dpkg --add-architecture arm64加 ports 源来 apt 装 arm64 的 dev 包。Ubuntu 20.04 的 ports 源和 amd64 源混在一起之后很容易在下次apt upgrade里卸载掉宿主机的库风险远大于收益。sysroot 源码编译更可控。3.3 libpng、fontconfig、libxkbcommon 的交叉编译模板Qt 5.12 的 eglfs/linuxfb 平台里字体、图像、输入是三个最常缺的环节。下面这套模板改改--host就能套用到大部分 autotools 库。# 以 libpng 为例交叉编译并安装到 sysroot ./configure --hostaarch64-linux-gnu \ --prefix/opt/sysroot/usr \ --enable-shared --disable-static \ CFLAGS--sysroot/opt/sysroot \ LDFLAGS--sysroot/opt/sysroot -Wl,-rpath-link,/opt/sysroot/usr/lib/aarch64-linux-gnu make -j$(nproc) sudo make install--host触发 configure 的交叉编译模式它会去找aarch64-linux-gnu-gcc--prefix直接指到 sysroot 的/usr这样装完不用再 copyCFLAGS/LDFLAGS里的--sysroot是为了让编译器不去翻宿主机的头-rpath-link告诉链接器在--sysroot之外再额外找一层运行库路径避免只链接不运行的场景下报 undefined。freetype、fontconfig、libxkbcommon都是同一套fontconfig编之前要先装libexpat同样方式交叉编进去否则它的 configure 会跳过 dev 分支。依赖用途是否可从 sysroot 直接拿编译注意libpng16QtGui 图像解码头 .so 常在 sysroot版本要和目标板运行库一致freetype2字体光栅化通常需自编依赖 zlib先编 zlibfontconfig字体查找通常需自编依赖 expat注意 xml 路径libxkbcommoneglfs 键盘映射需自编用 meson 时加 cross filelibdrmeglfs/KMS通常可从 sysroot版本和内核 DRM 头要匹配4. Qt 5.12.12 源码 configure 参数拆解与 mkspec 定制4.1 复制 linux-aarch64-gnu-g 并改写 qmake.confQt 5.12 自带qtbase/mkspecs/linux-aarch64-gnu-g这个规格但它默认走宿主机头文件也没有 sysroot需要基于它改一份。# qtbase/mkspecs/linux-aarch64-gnu-g/qmake.conf 关键段落 include(../common/linux.conf) include(../common/gcc-base-unix.conf) include(../common/g-unix.conf) QT_QPA_DEFAULT_PLATFORM linuxfb QMAKE_CC aarch64-linux-gnu-gcc QMAKE_CXX aarch64-linux-gnu-g QMAKE_LINK aarch64-linux-gnu-g QMAKE_LINK_SHLIB aarch64-linux-gnu-g QMAKE_AR aarch64-linux-gnu-ar cqs QMAKE_OBJCOPY aarch64-linux-gnu-objcopy QMAKE_NM aarch64-linux-gnu-nm -P QMAKE_STRIP aarch64-linux-gnu-strip SYSROOT /opt/sysroot QMAKE_CFLAGS --sysroot$$SYSROOT QMAKE_CXXFLAGS --sysroot$$SYSROOT QMAKE_LFLAGS --sysroot$$SYSROOT \ -Wl,-rpath-link,$$SYSROOT/usr/lib/aarch64-linux-gnu load(qt_config)QMAKE_LINK_SHLIB必须和QMAKE_LINK一致否则 QtWebEngine、QtMultimedia 这类会编共享库的模块在链接阶段会用回宿主 g报一堆 ABI 不匹配。QT_QPA_DEFAULT_PLATFORM linuxfb决定程序不指定-platform时的默认后端板上只有 framebuffer 就写linuxfb接了 GPU 走 KMS 就写eglfs。-rpath-link那行是最后兜底的链接共享库时-sysroot只能保证编译期找得到.so符号解析不到时还得靠-rpath-link指定目录。4.2 configure 参数逐条说明# 在 qt-everywhere-src-5.12.12 根目录执行 ./configure -prefix /opt/Qt5.12.12-aarch64 \ -xplatform linux-aarch64-gnu-g \ -sysroot /opt/sysroot \ -opensource -confirm-license \ -release -shared \ -nomake examples -nomake tests \ -no-opengl -no-xcb -no-gtk \ -linuxfb -eglfs \ -qt-libpng -qt-libjpeg -qt-zlib -qt-freetype -qt-harfbuzz \ -no-feature-cups -no-iconv -no-glib \ -skip qtwebengine -skip qt3d -skip qtcharts \ -v 21 | tee configure.log-prefix是安装目录编完后所有.so、头文件、qmake 都在这里-xplatform指定用刚才改的 mkspec-sysroot是 Qt 5.12 特有的开关会把这个路径塞进所有编译单元。-no-opengl -no-xcb是嵌入式最常见的选择板上没 X11、没桌面 GL这两个开了只会浪费编译时间还会引入一堆依赖需要 GPU 时把-no-opengl换成-opengl es2并保证libEGL、libGLESv2在 sysroot 里。-qt-libpng -qt-zlib这类前缀是让 Qt 用自带的第三方源码而不是去 sysroot 里找好处是零依赖风险缺点是体积略大如果你已经在 sysroot 装了 libpng把-qt-libpng换成-system-libpng能让产物更小但要确保版本一致。最后那几个-skip是把不需要的模块整个跳过QtWebEngine 依赖 Chromium交叉编译耗时巨大除非业务需要一律 skip。参数作用嵌入式场景推荐值-xplatform指定 mkspec自定义的 linux-aarch64-gnu-g-sysroot全局系统根目录从板子 rsync 的目录-no-xcb关闭 X11 后端板上无 X 时必加-linuxfbframebuffer 平台插件无 GPU 时的默认-eglfs无窗口系统 GL 后端走 KMS/GPU 时启用-qt-freetype用内置 freetype不想折腾系统库时用-opengl es2GL ES 2.0HDMI GPU 时启用4.3 make 阶段的报错定位方法configure 通过不代表能编过去Qt 5.12 全量编译在 8 核机器上大概 40 分钟到 1 小时报错通常出现在qtbase/src/plugins/platforms或qtdeclarative。make -j$(nproc) 21 | tee build.log grep -n -E error:|Error [0-9]|No such file build.log | head -n 30-j$(nproc)把核数用满tee保证日志可回查。一旦停下先 greperror:最常见的是cannot find -lXXX这表示链接器在-L路径里找不到某个.so要么是依赖库没编进 sysroot要么是库名版本不对需要libfoo.so软链而不是libfoo.so.1。第二常见的是头文件找不到几乎都是忘了--sysroot回头看 build.log 里那条命令是不是缺了这个参数。第三种是feature冲突比如开了-eglfs但 sysroot 里没有libdrm编译到一半才暴露——这类问题 configure 阶段日志里会有WARNING: Feature eglfs ...回去翻configure.log比翻build.log快。本文还有配套的精品资源点击获取