news 2026/9/20 11:40:13

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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-default,qmake 是有了,编出来的程序拷到 OrangePi CM5、树莓派 4B 这类 aarch64 板子上,第一反应通常是Exec format error——因为那份 qmake 是给 x86_64 用的,产出的是 x86 ELF,指令集那一层就对不上。第二个错位在库路径:即便你手工用交叉 g++ 把程序编出来了,链接阶段找的是宿主机/usr/lib/x86_64-linux-gnu里的libQt5Core.so,ABI 不匹配直接报 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-gnug++-aarch64-linux-gnu,装完前缀是aarch64-linux-gnu-,落地在/usr/bin。它带来的好处是版本稳定、头文件齐全、和宿主机的 glibc 同代,编 Qt 这种体量的工程不容易在头文件上卡住。缺点是它面向的是通用aarch64-linux-gnu目标,不带任何厂商的启动流程和特殊浮点选项——但对编 Qt 用户态库这件事,这一点无所谓。

另一条路是用板卡厂商 SDK 里那份工具链,或者芯片原厂发布的预编译包。它的优势是 ABI、浮点 ABI(hard/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 2>&1 | tail -n 3 aarch64-linux-gnu-g++ -print-sysroot

第一条应该输出aarch64-linux-gnu,出现x86_64说明 PATH 里被别的同名工具抢了;第二条看它报的 target 和线程模型,确认没有把arm-linux-gnueabihf的配置混进来;第三条打印默认 sysroot,apt 装的这套通常输出为空或者/,说明它直接用宿主机的/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++ 而非交叉 g++
qemu-aarch64-static运行正常打印动态链接缺 aarch64 libc
-print-sysroot为空或/正常,需命令行显式指定

3. 目标板 sysroot 的抓取与 Qt5.12.12 依赖库的交叉编译

3.1 从板子 rsync 一份 sysroot 到宿主机

Qt 编 aarch64 版本时,会去找一堆系统库的头和.solibdrmlibpnglibpthreadlibfontconfig等。这些包在宿主机的/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 \ root@192.168.1.100:/lib /opt/sysroot/ sudo rsync -avz root@192.168.1.100:/usr/lib /opt/sysroot/usr/ sudo rsync -avz root@192.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 编译 LIB=libpng16 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 --host=aarch64-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,这样装完不用再 copy;CFLAGS/LDFLAGS里的--sysroot是为了让编译器不去翻宿主机的头;-rpath-link告诉链接器在--sysroot之外再额外找一层运行库路径,避免只链接不运行的场景下报 undefined。freetypefontconfiglibxkbcommon都是同一套,fontconfig编之前要先装libexpat(同样方式交叉编进去),否则它的 configure 会跳过 dev 分支。

依赖用途是否可从 sysroot 直接拿编译注意
libpng16QtGui 图像解码头 + .so 常在 sysroot版本要和目标板运行库一致
freetype2字体光栅化通常需自编依赖 zlib,先编 zlib
fontconfig字体查找通常需自编依赖 expat,注意 xml 路径
libxkbcommoneglfs 键盘映射需自编用 meson 时加 cross file
libdrmeglfs/KMS通常可从 sysroot版本和内核 DRM 头要匹配

4. Qt 5.12.12 源码 configure 参数拆解与 mkspec 定制

4.1 复制 linux-aarch64-gnu-g++ 并改写 qmake.conf

Qt 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 2>&1 | tee configure.log

-prefix是安装目录,编完后所有.so、头文件、qmake 都在这里;-xplatform指定用刚才改的 mkspec;-sysroot是 Qt 5.12 特有的开关,会把这个路径塞进所有编译单元。-no-opengl -no-xcb是嵌入式最常见的选择:板上没 X11、没桌面 GL,这两个开了只会浪费编译时间还会引入一堆依赖;需要 GPU 时把-no-opengl换成-opengl es2并保证libEGLlibGLESv2在 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/platformsqtdeclarative

make -j$(nproc) 2>&1 | 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快。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 11:37:56

xiaomusic在线搜索配置:4步配好小爱搜全网

xiaomusic在线搜索配置&#xff1a;4步配好小爱搜全网 【免费下载链接】xiaomusic 使用小爱音箱播放音乐&#xff0c;音乐使用 yt-dlp 下载。 项目地址: https://gitcode.com/GitHub_Trending/xia/xiaomusic xiaomusic 的在线搜索给小爱音箱接了一根在线曲库的水管&…

作者头像 李华
网站建设 2026/9/20 11:36:33

模型报错 401?OpenClaw 的 Base URL 指向 TaoToken 的 api

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 11:36:02

Dify 三部曲收官:Cherry Studio 跑 MCP fetch,Key 用 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 11:35:49

机器学习实战源码解析:蜥蜴书第三版高效学习指南

简介&#xff1a;面向Python机器学习学习者的实战源码压缩包&#xff0c;对应《机器学习实战&#xff08;蜥蜴书第三版&#xff09;》一书&#xff0c;以Jupyter Notebook为主要载体&#xff0c;旨在帮助读者通过动手编码&#xff0c;系统掌握从数据处理、特征选择、模型构建到…

作者头像 李华