ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ARM64平台Qt开发环境搭建:编译器、源码编译与QtCreator Kit配置

ARM64平台Qt开发环境搭建:编译器、源码编译与QtCreator Kit配置 前几天帮人在一台国产 ARM64 服务器上装 Qt 开发环境从下午三点一直折腾到第二天中午才算是把 QtCreator、编译链、Kit 全部跑通。这活儿难吗单看命令其实就那几条难的是 ARM64 这个平台上的资源分布跟 x86 完全是两套逻辑Qt 官方的 Linux 离线安装包绝大多数是给 amd64 准备的发行版仓库里的 Qt 版本又往往偏旧只要你想上 Qt 5.15.2 这种最后的 5.x基本就得自己在 ARM64 上把源码 configure 一遍。这篇东西我按实际操作顺序重新捋了一遍从系统盘查、依赖补齐到源码编译、QtCreator 的 Kit 配置、命令行验证、打包发布最后把十几个真实踩过的报错整理成速查表。不管你是刚在信创平台上接手一个 Qt 项目还是手里只有一块 ARM64 开发板想跑个界面出来都可以照着往下抄。核心关键词就四个ARM64、Qt、编译器、QtCreator。1. ARM64上装Qt先把编译器这个词捋清楚1.1 ARM64和amd64到底差在哪些细节上很多人以为 ARM64 和 amd64 的区别只是指令集不一样反正装包命令都一样真上手就会发现处处不一样。最直观的是包名和库路径Debian 系在 amd64 上装库是/usr/lib/x86_64-linux-gnu到了 ARM64 就变成/usr/lib/aarch64-linux-gnuRPM 系上一个是/usr/lib64配x86_64的 rpm 名另一个是aarch64后缀的 rpm。这个差异看着小但你在.pro文件里手写-L/usr/lib/x86_64-linux-gnu的那一刻链接器就会告诉你找不到-lproj。再往下是页大小。ARM64 服务器允许 4K、16K、64K 三种内存页大小getconf PAGESIZE一敲就知道。有些平台默认 64K 页这时候那些按 4K 页对齐编译出来的预编译二进制会直接段错误崩掉表现得像是程序没报错但一跑就没了。碰到这种情况只有两条路要么找 64K 页兼容的构建产物要么老老实实源码编译。所以第一步永远是uname -m加getconf PAGESIZE两个结果记下来再动手。还有一个容易混的点是国产化平台不等于 ARM64。龙芯 3A5000 之后是 LoongArch 架构跟 ARM64 的二进制完全不通用兆芯、海光是 x86 系。所以热词里那些ARM64 和 x64 有何不同的问题答案不只在指令集还在包管理、库路径、页大小、内核配置这一整条线上。1.2 编译器、编辑器、IDE、Kit四个词别串线我见过不止一个新手在这四个词上绕圈。编译器compiler干的事只有一件把源码翻译成机器码ARM64 上通常是/usr/bin/gcc和/usr/bin/g背后是 GNU 工具链也可能是 clang。编辑器editor只负责让你敲字vim、nano 都算。IDE 是把编辑器、编译器调用、调试器、工程管理装进一个窗口的东西QtCreator 就是典型。而 Kit 是 QtCreator 独有的概念它把四样东西捆在一起Qt 版本一堆头文件和库、编译器哪个 g、调试器哪个 gdb、构建系统qmake 还是 CMake。把这个关系理清楚很多报错就不迷惑了。比如热词里提到的编译器未包含 main 类型实际对应的是链接期报undefined reference to main这跟编译器装没装好毫无关系是你工程文件没把main.cpp加进去或者main函数签名写错了。再比如有人做 MCU 开发时遇到 Keil 的compiler heap space那是 ARMCC 编译器在单片机环境下的堆空间限制跟 ARM64 上的 Qt 完全不是一码事别把这两个arm 编译器混成一个。1.3 三条安装路线怎么选先看表格再动手ARM64 上装 Qt实际可选的就三条路。选错了不是不能救是浪费一天时间。路线典型做法拿到的版本耗时适合什么场景发行版仓库apt install qtbase5-dev或dnf install qt5-qtbase-devel通常是 5.11 到 5.15 之间Qt6 在较新发行版有十分钟只求能编译版本不敏感官方离线/在线安装器跑.run安装器勾组件6.x 有 linux_arm645.15.x 基本只有 x64半小时到一小时网络受限、想快速要 Qt6源码编译configuremake任意版本完全可控半天到一天要指定 5.15.2、要裁剪模块、要 64K 页兼容我的建议是第一次在陌生平台上装先用发行版仓库的包把能不能跑起来验证掉确认系统、显卡、X11 都没问题之后再上源码编译。反过来先啃源码编译中间任何一步报错你都分不清是 Qt 的问题还是系统的问题。1.4 没有实体ARM64机器时怎么练手手头只有 x86 笔记本的情况下用qemu-system-aarch64装一个 ARM64 虚拟机是可行的或者走容器路线配合 QEMU 的用户态模拟跑aarch64镜像docker run --platform linux/arm64就能直接在里面跑 ARM64 的二进制。这条路验证配置、验证命令、验证依赖清单非常好用。但有一个数字必须提前知道QEMU 用户态模拟下编译 Qt 源码性能损失是十倍级别的。qtbase 全量编译在实体 ARM64 上可能是四十分钟在 QEMU 里就是七八个小时加上 qtdeclarative 基本可以过夜。所以我把这条路线定位成验证逻辑真要出包还是得找实体机或者云端 ARM64 实例。别在模拟环境里跑完整编译也不要拿模拟环境的耗时去判断真实机器的性能。2. 编译前的环境盘查与依赖补齐这步偷懒必还债2.1 用五条命令摸清系统底细动手装任何东西之前我习惯先把这五条命令跑一遍把输出存成一个小文本后面出问题回头对照特别省事。uname -m # aarch64 才是我们要的 getconf PAGESIZE # 4K 还是 64K决定能不能用预编译产物 cat /etc/os-release # 发行版和版本号决定用 apt 还是 dnf gcc -v # 有没有编译器版本多少 nproc free -h df -h / # 并行度、内存、磁盘决定 -j 开多少nproc和free -h的结果直接影响你的编译参数后面第 3 节会讲怎么算。df -h也要看一眼Qt 源码编译的中间产物比你想象的大得多qtbase 一个模块的 build 目录就能吃掉十几个 G。这几个数字我在盘查阶段就会写下来因为编译到一半发现磁盘满了那种感觉相当难受。2.2 依赖清单一次装齐按包管理器分两套依赖缺失是 ARM64 上最常见的隐性杀手很多库在 x86 上默认装了ARM64 的精简镜像里没有。下面这套清单是我实际编译 Qt 5.15 和 Qt 6 时用的Debian 系含 Ubuntu、Kylin 桌面版用第一条RPM 系含 openEuler 系发行版用第二条。# Debian / Ubuntu / Kylin 桌面版 sudo apt install -y build-essential gcc g make cmake ninja-build pkg-config \ git python3 perl bison flex gperf \ libgl1-mesa-dev libglu1-mesa-dev libegl1-mesa-dev \ libxkbcommon-dev libxkbcommon-x11-dev \ libfontconfig1-dev libfreetype6-dev libharfbuzz-dev \ libx11-dev libx11-xcb-dev libxext-dev libxfixes-dev libxi-dev \ libxrender-dev libxcb1-dev libxcb-util0-dev libxcb-cursor-dev \ libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev \ libxcb-render-util0-dev libxcb-shape0-dev libxcb-sync-dev \ libxcb-xfixes0-dev libxcb-xkb-dev libxcb-glx0-dev libxcb-icccm4-dev \ libssl-dev libsqlite3-dev libicu-dev libxslt1-dev# RPM 系 sudo dnf install -y gcc gcc-c make cmake ninja-build pkgconfig git \ mesa-libGL-devel mesa-libGLU-devel mesa-libEGL-devel \ libxkbcommon-devel libxkbcommon-x11-devel \ fontconfig-devel freetype-devel harfbuzz-devel \ libX11-devel libXext-devel libXfixes-devel libXi-devel libXrender-devel \ libxcb-devel xcb-util-devel xcb-util-image-devel xcb-util-keysyms-devel \ xcb-util-renderutil-devel xcb-util-wm-devel xcb-util-cursor-devel \ openssl-devel sqlite-devel libicu-devel libxslt-devel这套包清单里xcb 那一串是最关键也最容易漏的。Qt 在 Linux 上的默认平台插件就是 xcb少一个xcb-util-cursor-devel程序编译能过一运行就报平台插件加载失败排查起来还挺费劲。所以我的做法是宁可多装把所有xcb-util-*一次装完。提示如果在麒麟或者统信的系统上apt和dnf可能同时存在或者都不叫这个名字先用command -v dnf || command -v apt确认一下别照着教程硬敲。2.3 内存、磁盘、swap 的预留直接决定编译能不能过这一步很多人跳过然后卡在make跑到 80% 的时候被系统杀掉进程。规则很简单并行编译的任务数乘以单个编译进程的内存占用要小于可用内存。g 编译 Qt 这种模板密集型代码单进程峰值普遍在 1 到 1.5G链接阶段更狠单个ld吃 2 到 4G 很常见。给两个实测参考值8G 内存的机器-j4比较稳-j8大概率会 OOM16G 内存以上-j8没问题-j$(nproc)要看 nproc 是不是 32 以上是的话就手动压到-j8。磁盘方面源码包解压后大约 5 到 10G编译中间产物建议单独预留 60 到 100G装到/opt之前先确认那个分区够大。swap 也别省物理内存 8G 的机器建议开 4 到 8G swap。虽然编译过程大量换页会变慢但比被 OOM killer 干掉强。判断是不是 OOM 的方法很直接dmesg | tail -20 # 看有没有 Out of memory: Killed process free -h # 编译过程中另开一个终端盯着如果make报的是internal compiler error: Killed (program cc1plus)或者ld terminated with signal 9 [Killed]八成不是代码问题是内存被吃干净了。这两条报错我在速查表里也会再列一遍。2.4 拿到第三方预编译ARM64程序时先做三件事有些场景下你会拿到别人编译好的 ARM64 可执行文件比如某个老版本的工具、某个内部流传的二进制。这类东西在 ARM64 桌面上跑之前我建议花两分钟做三件事file xxx看它到底是不是 aarch64、readelf -d xxx | head -30看它依赖哪些库、ldd xxx看这些库在不在。如果这个二进制来源不明、还带着已知的风险记录最稳妥的做法是丢进一个独立的容器或者独立用户里跑别直接放在生产环境的家目录里执行。这个习惯花不了多少时间但能避免很多说不清的事故尤其是内网环境里那些没人维护的老程序。3. Qt本体安装从仓库包到源码编译的完整路径3.1 发行版仓库最快但版本通常偏旧这条路适合先把环境跑通的验证阶段。Debian 系一条命令sudo apt install -y qtbase5-dev qtdeclarative5-dev qttools5-dev-tools qtcreatorRPM 系sudo dnf install -y qt5-qtbase-devel qt5-qtdeclarative-devel qt5-qttools-devel qt-creator装完之后qmake -v看版本一般落在 5.11 到 5.15 之间。Qt6 的话对应包名是qt6-qtbase-devel和qt6-qtdeclarative-devel不过不是每个 ARM64 发行版都打了 Qt6 的包dnf search qt6先搜一下比较稳。这条路最大的优点是依赖自动解决qtcreator装好后 Kit 基本是开箱能用的适合快速验证显卡驱动、X11 环境有没有问题。缺点也明显版本旧、模块裁剪过像 QtSerialPort、QtWebEngine 这些模块发行版可能压根没打包你要用还得单独装。3.2 官方离线包ARM64上要挑对版本再下这里有个坑必须说清楚。Qt 官方在 Linux 上的离线安装包绝大部分是给 amd64 准备的目录名一般是gcc_64或者linux_x64ARM64 的包在 6.x 系列才开始有目录名会是gcc_arm64或者linux_arm64。所以热词里常出现的qt 离线安装包下载 5.145.15.2 下载安装在 ARM64 上基本对不上号下载下来会发现根本装不上白等一场。判断方法很简单.run文件下下来之后先别急着执行chmod x qt-opensource-linux-xxx.run ./qt-opensource-linux-xxx.run --dump-binary-data -o /tmp/qtpkg ls /tmp/qtpkg | head # 看目录名里是 x64 还是 arm64如果目录名是gcc_64直接删掉别浪费时间。另外安装器在无图形界面的服务器上跑有时候会卡在正在准备安装的界面不动加--platform minimal参数能绕开一部分 X11 相关的初始化问题./qt-opensource-linux-xxx.run --platform minimal网络受限的环境里不要在在线安装器上反复重试登录、校验、下载组件每一步都可能卡住直接走离线包或者源码编译更省心。3.3 源码编译ARM64上最稳的一条路如果非 5.15.2 不可或者需要 64K 页兼容源码编译就是唯一选择。以 5.15.2 为例先在qt-everywhere-src-5.15.2解压目录里 configure./configure -prefix /opt/Qt/5.15.2-arm64 \ -opensource -confirm-license \ -release -nomake examples -nomake tests \ -qt-zlib -qt-libpng -qt-libjpeg -qt-freetype \ -xcb -opengl desktop \ -skip qtwebengine -skip qtwayland \ -no-feature-sql-oci每个参数背后都有理由我把关键的几个解释一下。-prefix决定装到哪我强烈建议装到/opt而不是/usr一是权限干净二是将来多版本共存好管理。-nomake examples -nomake tests能省掉三成以上的编译时间这两个目录对开发没影响。-qt-zlib -qt-libpng -qt-libjpeg -qt-freetype的意思是让 Qt 内嵌这些第三方库的源码自己编译而不是链系统上的版本这样能避免 ARM64 上系统库版本不一致导致的悬空符号问题代价是编译时间长一点。-xcb明确启用 xcb 平台插件-opengl desktop在服务器上比默认的 es 更省事。-skip qtwebengine必须加因为 QtWebEngine 里面是整个 Chromium 内核在 ARM64 上编译要几十 G 内存加好几个小时除非你确定要用浏览器控件否则一律跳过。编译阶段根据前面算好的并行度来make -j4 # 8G 内存 make -j8 # 16G 以上 make install如果你想验证单个模块的编译是否正常可以在中间另开终端tail -f看日志。判断还在正常跑的方法很简单ls -lt | head看有没有新生成的.o文件。Qt6 的编译改成 CMake 流程参数名也换了一套cmake -S qt-everywhere-src-6.5.3 -B build -GNinja \ -DCMAKE_INSTALL_PREFIX/opt/Qt/6.5.3-arm64 \ -DQT_BUILD_EXAMPLESOFF -DQT_BUILD_TESTSOFF \ -DINPUT_openglno -DFEATURE_xcbON cmake --build build --parallel 4 cmake --install build3.4 单独补一个模块以 QtSerialPort为例源码编译完你会发现有些模块默认没编进去比如热词里反复出现的Unknown module(s) in QT: serialport。这通常不是配置错了是 qtserialport 这个模块不在你看的那份源码包里或者发行版压根没打包。补装方式很直接单独拿源码编一遍git clone -b 5.15.2 https://code.qt.io/qt/qtserialport.git cd qtserialport /opt/Qt/5.15.2-arm64/bin/qmake . make -j4 make install判断模块到底装没装别靠猜看两个地方就够了ls /opt/Qt/5.15.2-arm64/lib/cmake/ | grep -i serial以及ls /opt/Qt/5.15.2-arm64/lib/ | grep -i serial。前者是给 CMake 工程找包用的后者是运行时库。两个都在.pro里的QT serialport才不会报错。3.5 目录规划与环境变量多版本共存别打架最后说一个很容易忽略的点。ARM64 桌面发行版自己带了一套 Qt桌面环境就是用它写的如果你把 Qt 的库路径塞进/etc/profile或者~/.bashrc的LD_LIBRARY_PATH系统里其他 Qt 程序下次启动可能就会因为加载了你/opt下的库而崩掉这种问题排查起来特别费时间。我的做法是环境变量一律只写在启动脚本里不写进全局配置。比如给一个项目写个env.shexport QTDIR/opt/Qt/5.15.2-arm64 export PATH$QTDIR/bin:$PATH export LD_LIBRARY_PATH$QTDIR/lib:$LD_LIBRARY_PATH用的时候source env.sh开新终端就干干净净。多版本共存则完全交给 QtCreator 的 Qt Versions 管理不用在命令行切来切去。qmake -query可以列出 Qt 记录的所有内置路径换机器、查前缀特别有用。4. QtCreator安装与Kit配置红叉问题的根源都在这4.1 QtCreator的三条获取途径第一条是发行版仓库apt install qtcreator或dnf install qt-creator最省事缺点是版本可能比你的 Qt 库还旧一截。第二条是从 Qt 官方安装器的 6.x 包里勾选 Qt Creator这个在 ARM64 上是可以的装出来的 Creator 版本比较新。第三条是源码编译先保证某个 Qt 已经装好然后拿qt-creator-opensource-src源码/opt/Qt/5.15.2-arm64/bin/qmake加make -j420 到 60 分钟能出结果。这里有一个非常典型的坑Qt 官方给 Linux 发布的 QtCreator 独立二进制包或者压缩包里带的 QtCreator绝大多数是 x86_64 的。你在 ARM64 上解压运行会得到一句cannot execute binary file: Exec format error。看到这条报错不要怀疑系统直接用file确认一下那个可执行文件的架构是 x86-64 就说明下错平台了老老实实走仓库包或者源码编译。4.2 Kit的三要素Qt版本、编译器、调试器QtCreator 里 Kit 配置是全部问题的集中地。我把四个必填字段和常见填错方式整理成表配置的时候对着看。字段该填什么常见填错后果Qt Versions/opt/Qt/5.15.2-arm64/bin/qmake填成 x64 的 qmake编译能过但跑不了或直接报错Compilers (C)/usr/bin/gABI 选 arm-linux-generic-elf-64bitABI 自动识别成 x86Kit 上出现红色感叹号Debuggers/usr/bin/gdb路径没填或指向交叉调试器无法断点调试CMake/usr/bin/cmake版本与 Qt 匹配用了过旧的 CMake配置阶段就报错操作顺序是这样的。打开 QtCreator 的工具 → 选项 → Kits先切到Qt Versions页点添加选/opt/Qt/5.15.2-arm64/bin/qmake点 Apply看下面那行提示有没有变红。如果这里就红了说明 qmake 本身有问题可能是依赖库缺失命令行里直接跑一次qmake -v再看ldd qmake就能定位。然后切到编译器页添加一个 GCC 的 C 编译器路径/usr/bin/g把 ABI 手动改成arm-linux-generic-elf-64bit。这一步是 ARM64 上最容易漏的QtCreator 偶尔会把 ABI 识别成 x86 的结果 Kit 汇总页上就给你一个红叉报ABI 不匹配。改过来立刻就好。最后到构建套件(Kit)页添加一个新 KitQt 版本选刚刚加的 5.15.2编译器选 GCC arm64调试器选 gdb设备类型选 DesktopCMake 工具选一个版本够新的。点 OK 保存红叉消失这条链路就通了。4.3 用一个小工程把整条链路验一遍光看 Kit 页面对了不算数得真跑一个程序。我习惯用一个同时验证Qt 库正常加载JSON 读写正常架构信息正确的最小工程。.pro文件很简单QT core gui widgets TARGET armdemo TEMPLATE app SOURCES main.cppmain.cpp里做三件事打印架构、打印 Qt 版本、读写一个 JSON#include QApplication #include QLabel #include QJsonObject #include QJsonDocument #include QSysInfo #include QDebug int main(int argc, char *argv[]) { QApplication app(argc, argv); qDebug() arch: QSysInfo::currentCpuArchitecture(); qDebug() qt: qVersion(); QJsonObject obj; obj[arch] QSysInfo::currentCpuArchitecture(); obj[qt] qVersion(); obj[page] check with getconf PAGESIZE; QByteArray data QJsonDocument(obj).toJson(QJsonDocument::Indented); qDebug().noquote() QString::fromUtf8(data); QLabel label(QString::fromUtf8(data)); label.show(); return app.exec(); }跑起来日志里能看到arm64和正确的 Qt 版本号界面上能看到那段 JSON说明 Qt 库、平台插件、编译链、Kit 全部没问题。以后每换一台机器这个工程跑一遍比翻配置文件快得多。5. 从命令行到打包把编译结果真正落地5.1 命令行验证绕开IDE先确认工具链IDE 出问题时我喜欢退回到命令行这样能把问题范围缩小到工具链本身。qmake 工程在命令行里跑就两步cd armdemo /opt/Qt/5.15.2-arm64/bin/qmake armdemo.pro make -j4 ./armdemomake跑起来之后如果想确认它用的到底是哪个编译器别猜直接看生成的编译命令make -n | head -20输出的第一行里会带-I头文件路径和/usr/bin/g之类的编译器路径。如果这里出现了一个你没见过的交叉编译器或者头文件路径指向了 x86 的目录那就说明这个工程的环境被污染了得回去查环境变量。5.2 CMake工程验证CMAKE_PREFIX_PATH是关键Qt6 和多数新工程走 CMake。一个最小的CMakeLists.txtcmake_minimum_required(VERSION 3.16) project(armdemo LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) find_package(Qt5 COMPONENTS Core Gui Widgets REQUIRED) add_executable(armdemo main.cpp) target_link_libraries(armdemo PRIVATE Qt5::Core Qt5::Gui Qt5::Widgets)配置的时候重点在CMAKE_PREFIX_PATHcmake -S . -B build \ -DCMAKE_PREFIX_PATH/opt/Qt/5.15.2-arm64/lib/cmake \ -DCMAKE_BUILD_TYPERelease cmake --build build --parallel 4find_package找不到 Qt 的报错九成是CMAKE_PREFIX_PATH写错了。常见的错误写法是指到/opt/Qt/5.15.2-arm64/lib正确的是指到lib/cmake那一层因为 CMake 的包配置文件Qt5Config.cmake就放在那儿。这个细节在 x86 上不明显因为系统装了 Qt 之后路径是全局的ARM64 上自己编的 Qt 必须显式指定所以踩的人特别多。5.3 链接第三方库以PROJ为例的两种写法实际项目里经常要链第三方库比如地理信息相关的 PROJ。ARM64 上库文件的路径是/usr/lib/aarch64-linux-gnu手写的.pro长这样INCLUDEPATH /usr/include LIBS -L/usr/lib/aarch64-linux-gnu -lproj -lsqlite3这种写法能用但很脆换一台机器库路径变了就得改。更稳的做法是让 pkg-config 去查CONFIG link_pkgconfig PKGCONFIG proj sqlite3前提是目标机器上装了libproj-dev。命令行里先验证一下pkg-config --cflags --libs proj能不能正常输出能输出再往.pro里写。这个写法的好处是 pkg-config 会自己给出 aarch64 的正确路径你不用关心是/usr/lib还是/usr/lib/aarch64-linux-gnu跨机器移植也基本不用改。5.4 打包发布ARM64上没有现成的linuxdeployqt打包这一步在 ARM64 上比 x86 麻烦。原因是常见的linuxdeployqt官方只发布 x86_64 的二进制ARM64 上你得自己从源码编或者换别的思路。我的做法是手写脚本逻辑清楚而且可控。先看依赖ldd armdemo | grep /把 Qt 的库和平台插件拷进发布目录保持这样的结构dist/ usr/bin/armdemo usr/lib/libQt5Core.so.5 usr/lib/libQt5Gui.so.5 usr/lib/libQt5Widgets.so.5 usr/plugins/platforms/libqxcb.so usr/bin/qt.confqt.conf必须写否则程序找不到插件[Paths] Prefix.. Pluginsplugins Librarieslib最后给可执行文件设 rpath让它从相对路径找库patchelf --set-rpath $ORIGIN/../lib dist/usr/bin/armdemo打包最容易漏的是平台插件。程序在你开发机上跑得好好的拷到另一台机器就报找不到 xcb 插件十有八九是plugins/platforms/libqxcb.so没带上或者qt.conf没写对。发布前在一台干净的 ARM64 机器上跑一遍是唯一可靠的验证方式。6. 常见报错与排查实录这份速查表建议收藏6.1 模块缺失类报错Unknown module(s) in QT这是出现频率最高的一类。报错原文一般是Project ERROR: Unknown module(s) in QT: serialport或者webenginewidgets。它的含义很单一qmake 在 Qt 安装目录里找不到对应模块的.pri文件。排查顺序是固定的三步。第一步确认模块名字和目录名对不对Qt 的模块名大小写敏感serialport不能写成SerialPort。第二步去安装目录里找ls /opt/Qt/5.15.2-arm64/lib/cmake/ | grep -i 模块名没找到就是真没装。第三步如果没装就补装发行版包装的话apt install libqt5serialport5-dev源码方式就按 3.4 节那套单独编一遍模块。补完装之后一定要重启 QtCreator因为它启动时扫过一次模块列表不重启还是会报同样的错。这个细节坑过我一次白排查了半小时。6.2 运行时平台插件失败xcb加载不了报错原文是qt.qpa.plugin: Could not load the Qt platform plugin xcb in even though it was found.。注意后半句even though it was found说明插件文件本身是找到了但加载过程中依赖的库缺了。这时候打开调试开关让 Qt 把细节吐出来export QT_DEBUG_PLUGINS1 ./armdemo 21 | head -60输出里会明确告诉你哪个.so加载失败。更直接的办法是单独检查这个插件ldd /opt/Qt/5.15.2-arm64/plugins/platforms/libqxcb.so | grep not found缺什么就补什么通常是libxcb-icccm、libxcb-image、libxcb-keysyms这几个。如果是在另一台机器上跑打包结果出问题那基本就是 5.4 节说的插件路径和qt.conf的问题。还有一种情况是在没有独立显卡的 ARM64 板子上跑 QML 程序界面一片黑或者动画卡成幻灯片。这时候先别研究渲染优化把软件渲染打开看看能不能跑export QT_QUICK_BACKENDsoftware能跑通说明是 GPU 驱动或者 OpenGL ES 上下文的问题接下来再去处理驱动。用软件渲染先把功能验证完这个顺序比一上来就啃驱动省时间得多。6.3 Kit上的红叉和红色感叹号Kit 页面变红按这个顺序查基本三步能定位。先看Qt Versions页里那个 qmake 有没有红字提示如果有说明 qmake 本身就跑不起来命令行验证qmake -v和ldd能查到缺哪个库。再看编译器页里那个 GCC 的 ABI 是不是arm-linux-generic-elf-64bit如果是 x86 的 ABI手动改掉。最后回到 Kit 汇总页看它是报ABI 不匹配还是Qt 版本无效这两种提示指向的修复动作完全不同。红叉信息本身写得挺清楚的比乱改参数有效得多。6.4 链接期报错入口函数相关undefined reference to main这个报错新手容易误判成编译器坏了。实际上入口函数的问题只有几种可能main.cpp没写进SOURCESmain的签名写错了比如写成了int main(int)或者一个漏掉的大括号导致main被套进了别的函数里。还有一种隐蔽情况是.pro里同时指定了TARGET和一个同名的OBJECTS_DIR导致目标文件被覆盖。验证方法是用 nm 直接看目标文件里有没有 main 符号nm -C main.o | grep -i T main输出里能看到T main就说明符号在问题出在链接参数上看不到就是源码层面的事回去检查源文件列表。6.5 内存不足类报错看着像编译器故障这一类报错最容易被误判因为文字看起来很像编译器崩溃internal compiler error: Killed (program cc1plus)、c: fatal error: Killed、collect2: fatal error: ld terminated with signal 9 [Killed]。它们的共同原因是系统内存不够内核把进程杀了。诊断动作只有一个dmesg | tail -20 | grep -i out of memory有输出就确认是 OOM。解决就是把-j降下来或者临时加大 swap或者把出问题的大模块单独拎出来编。我在一台 8G 的机器上编 qtdeclarative 时就撞过这个-j8必然被杀改成-j2之后虽然慢但一次过了。下面这张表是我整理的高频报错速查遇到问题先对号入座。报错关键字真实原因处理动作Unknown module(s) in QT: xxx模块没装或名字大小写不对补装模块后重启 QtCreatorCould not load the Qt platform plugin xcb插件依赖库缺失或路径没配QT_DEBUG_PLUGINS1 定位补库或写 qt.confExec format error二进制架构不对多为 x86_64file 确认架构改用 arm64 版本undefined reference to main源文件没进工程或签名错误检查 SOURCES 和 main 签名internal compiler error: Killed内存不足被内核杀降低 -j加 swapld terminated with signal 9链接阶段 OOM同上有单独编译大模块ABI 不匹配Kit 红叉编译器 ABI 识别成 x86手动改成 arm-linux-generic-elf-64bit报错找不到 -lGL 或 -lEGL缺 GL 开发包装 mesa-libGL-devel / libgl1-mesa-dev6.6 两个跨平台的混淆点别把MCU工具链算进来最后提醒一个容易混淆的地方。搜索结果里经常混进一堆 MCU 相关的编译器问题比如arm 编译器 v5.06 未安装要求编译器包含 main 类型compiler heap space。这些是 Keil MDK、ARMCC 那套单片机工具链的问题跟 ARM64 上的 Linux Qt 开发完全是两个世界。ARM64 是 64 位应用处理器架构用的是 GCC 或 Clang 加 glibcARMCC 面向的是 Cortex-M 系列单片机用 C 库是精简版的。同样叫arm 编译器参数、报错、内存模型全不一样。在同一个项目里同时做这两件事的人建议把两个目录、两套工具链彻底分开连终端窗口都分开用能少掉很多莫名其妙的问题。7. 几个省时间的实操心得与扩展方向7.1 本机编译还是交叉编译先想清楚再动手这个选择决定了后面所有工作的形态。如果开发机本身就是 ARM64那没什么好纠结的本机原生编译一切按本文的流程走。如果开发机是 x86 而目标板是 ARM64那就得交叉编译事情复杂一个量级要准备aarch64-linux-gnu-前缀的工具链、要准备目标板的 sysroot目标板上/usr/include和/usr/lib的拷贝、要自己维护一份 mkspec 里的qmake.conf改QMAKE_CC、QMAKE_CXX的路径前缀和QMAKE_SYSROOT。任何一个环节写错症状都是编译能过但链接找不到库。我的建议很明确第一次上手不要交叉编译 Qt 本体。先在目标板上用发行版仓库的包装一套跑通一个 Hello World把目标板能不能跑 Qt 程序这个前提确认掉。然后在 x86 开发机上配交叉工具链用-sysroot指向目标板文件系统先从编一个小程序开始逐步过渡到编 Qt 应用。整个 Qt 库的交叉编译放到最后再做因为那是最耗时也最容易失败的一步。另外交叉编译有个非常隐蔽的坑宿主机上的pkg-config默认会去查宿主机 x86 的库路径给出的-I和-L全是 x86 的。处理方式是给交叉编译环境单独设PKG_CONFIG_SYSROOT_DIR和PKG_CONFIG_LIBDIR让 pkg-config 只在 sysroot 里找。这一步不设置症状就是明明装了 aarch64 的库链接器却说找不到。7.2 版本锁定与目录备份能省下一整天ARM64 上编译一次的代价太大所以我养成了一个习惯编译成功之后立刻把整个/opt/Qt/5.15.2-arm64打个 tar 包存起来。tar czf qt-5.15.2-arm64-$(date %Y%m%d).tar.gz -C /opt/Qt 5.15.2-arm64新机器上直接解包到同样的路径省掉一整天的编译。这里有一个前提必须注意Qt 的安装路径是写进二进制里的qmake 记录的qt_prfxpath就是你 configure 时的-prefix值。所以解包的时候路径必须保持一致不能从/opt/Qt解到/home/user/Qt那样 qmake 会找不到自己。真要换路径得用qt.conf覆盖或者重新 configure 一遍。顺带说一句qmake -query会把所有这些内置路径列出来包括QT_INSTALL_PREFIX、QT_INSTALL_LIBS、QT_INSTALL_PLUGINS。查库到底装哪儿了这种问题这一条命令比翻目录快得多。7.3 用容器把环境固定下来如果有多个 ARM64 项目要用不同 Qt 版本建议用容器把环境隔离。基础镜像选一个带完整构建工具的 ARM64 镜像把依赖装好把 Qt 编译进镜像然后每个项目挂载自己的代码目录进去编。这样做的好处是环境可复现同事拿到 Dockerfile 就能起一套一样的不会出现我这能编你那不能编的情况。容器里跑 GUI 程序需要挂载 X11 的 socket命令行大概是这样docker run --rm -it \ -e DISPLAY$DISPLAY \ -v /tmp/.X11-unix:/tmp/.X11-unix \ -v $(pwd):/work \ arm64-qt-env:5.15.2 bash进去之后qmake make照常跑界面还能弹出来。远程开发的时候记得xhost local:放行一下。这个方案在 ARM64 上有额外好处宿主机的依赖变化不会影响容器里的编译环境换发行版也不影响已经编好的镜像。我个人最真实的体会是ARM64 上装 Qt 这件事麻烦的从来不是某一条命令而是信息不对称——你手上那份教程是 x86 的你下的那个包是 x64 的你抄的那行-L路径是 amd64 目录。所以每次开新机器我会先花五分钟把uname -m、getconf PAGESIZE、command -v apt、nproc、df -h /opt这五个输出记在便签上后面所有的选择和参数都从这五个数字推出来比照着教程硬抄靠谱得多。
返回列表