1. 动手前先讲清楚:交叉编译到底在折腾什么
如果你手里有一台龙芯 3A5000 或者 LoongArch 架构的开发板,接到任务时第一反应多半是“直接在板子上装 Qt、写代码、编译不就行了”。但真把机器跑起来就发现,龙芯设备往往配的是精简桌面、内存和 CPU 都偏保守,在板子上跑 Qt Creator、再开几个工程文件,卡顿肉眼可见。等代码量大一点,一次全量构建等上十分钟很正常。这时候最现实的开发方式,就是回到性能和硬盘都充裕的 x86 工作站上,用交叉编译工具链编译出目标机可运行的 Qt 程序,再部署到龙芯设备上跑。
我用到的核心方案就是这么一条:x86 宿主机(Ubuntu / Deepin 都可以)安装 LoongArch 交叉编译工具链,准备一份和目标机一致的 sysroot(系统头文件和库),再准备一份同样面向 LoongArch 的 Qt 库,最后在 Qt Creator 里把这些组件串成一个自定义 Kit(套件)。写完代码一键编译、一键部署、甚至远程调试,而龙芯设备那边完全不用动开发环境,只负责充当运行和生产环境。这套流程听着不复杂,但实际配置过程中,工具链版本、sysroot 路径、qmake 缓存这些地方到处是坑,这篇文章就是专门把这些流程和坑点完整过一遍的。
这篇文章适合正在或准备在龙芯 LoongArch 设备上做 Qt 界面开发的工程师,也适合所有需要把 x86 工作站变成“给国产平台做交叉编译”开发机的开发者。下面所有操作我都按真实可复现的原则写,命令可以直接抄,但你自己设备的具体路径建议先列个清单再动手。
2. 交叉编译的基本逻辑:为什么不能直接拷贝一个 Qt 过来用
2.1 交叉编译和本地编译的差别
本地编译很好理解,就是我在 x86 机器上用 x86 的 gcc 编译 x86 可执行文件。交叉编译则是“我有 x86 的开发环境,但要编译出在 LoongArch 上运行的程序”,编译生成的文件架构是目标机的架构,不是宿主机自己的架构。比如宿主机的普通gcc编译产物是x86_64的,放到龙芯机器上直接报Exec format error,原因不是文件坏了,而是 CPU 指令集对不上。
所以交叉编译需要三样东西:第一是有目标架构生成能力的交叉编译器,第二是目标机系统环境的头文件和系统库(这里的库不是编译器自带的,而是目标机/usr/lib、/usr/include等目录里真实的系统库和开发头文件),第三是目标机的 Qt 库。这三样缺一个,编译阶段或运行阶段就会出问题。整个环境搭建工作,说到底就是把这三样组织好,再让 Qt Creator 能识别和调用它们。
2.2 LoongArch 架构的基本特点
龙芯在指令集上走的是自主研发的 LoongArch,默认是 64 位,向下兼容旧 32 位应用的办法也有,但开发新应用基本都按 64 位来。交叉编译工具链的前缀通常是loongarch64-linux-gnu-,这一点很重要,因为它决定了你在Qt Creator里配置编译器时要选择哪种 ABI,也决定了你会拿到什么版本的 Qt 库。
LoongArch 在生态上比 x86/ARM 起步晚,对应的问题是很多通用软件包没有现成的 LoongArch 版本,或者需要自己动手编译。Qt 官方直到近期版本才把 LoongArch 列入正式支持设备列表。这就是为什么很多人在配置时发现,直接下载通用 Qt 安装包安装不了,必须使用龙芯社区编译好的 Qt,或者自己从源码交叉编译。
2.3 两条路线怎么选:官方 SDK 还是全源码自编译
我实际接触下来,环境搭建大致有两条路线,各有侧重:
- 路线 A(推荐给赶进度的人):直接使用龙芯开源社区发布的 Qt for LoongArch 交叉编译 SDK,解压后已经包含 qmake、Qt 库、相关插件和一部分 mkspecs,不用自己纠结 configure 参数。这种方式重点在把 Qt Creator 的套件配置对,项目配置好就能编译。
- 路线 B(适合深入定制的人):从
qt-everywhere-src-5.15.10或更新源码包自行交叉编译,好处是模块、编译参数完全可控,坏处是 configure 和 mkspec 定制过程比较折磨,编译一次耗时也很长。
我这次的主体配置用的是路线 A,但会把路线 B 的关键步骤也写出来。因为很多时候你想在项目里追加一个 Qt 模块(比如qtcharts或qtnetworkauth),官方 SDK 里不一定有对应模块的交叉编译版本,最终还是要回到源码编译这条路。两条路都走通,后面遇到问题才不会慌。
3. 基础环境准备:宿主机、工具链、sysroot
3.1 宿主机准备工作
先看你手头用什么系统。我是在 Ubuntu 20.04 x86_64 上配的,Deepin x86 版本也可以用,注意只要是 64 位系统即可,不要拿 32 位宿主机去搞,很多工具链和 Qt 库都只考虑 64 位 host。
在开始之前,建议把需要的基本构建工具装齐,避免编译第三方模块时缺东西:
sudo apt update sudo apt install build-essential rsync ssh cmake ninja-build \ libgl1-mesa-dev libfontconfig1-dev libdbus-1-dev \ libxkbcommon-dev libx11-dev libxft-dev libxext-dev这几类包不全装也没关系,build-essential和rsync是刚需,因为后面要同步 sysroot,还要编译程序。其他图形相关的库按你项目的实际依赖来,我先列出来省得后面发现缺了再回头装。
同时你需要知道目标机的 IP 地址和 SSH 登录方式,交叉编译部署和 sysroot 同步都依赖它能被宿主机网络访问。
3.2 交叉编译工具链的获取与验证
我是从龙芯开源社区的软件仓库和开发者镜像里获取工具链的,文件名类似loongson-gnu-toolchain-8.3-x86_64-loongarch64-linux-gnu-release.tar.xz,下载后解压到/opt下,然后配置环境变量:
export PATH=/opt/loongarch64-toolchain/bin:$PATH工具链解压后大致像这样:
/opt/loongarch64-toolchain/ ├── bin/ │ ├── loongarch64-linux-gnu-gcc │ ├── loongarch64-linux-gnu-g++ │ ├── loongarch64-linux-gnu-ld │ └── ... ├── lib/ ├── libexec/ └── share/验证它能不能用,先看版本:
loongarch64-linux-gnu-gcc -v然后写一个 hello.c:
#include <stdio.h> int main(void) { printf("Hello LoongArch\n"); return 0; }交叉编译并查看文件架构:
loongarch64-linux-gnu-gcc hello.c -o hello_loongarch file hello_loongarch如果输出里带ELF 64-bit LSB executable, 64-bit LoongArch之类描述,说明交叉编译器已经能正常生成目标机器架构的程序。这个步骤最好先跑通,再往下走。
3.3 sysroot 的准备:从目标机同步系统环境
交叉编译时,编译器需要找到目标机的libc、头文件以及各种系统库,但这些肯定不能直接用宿主机的/usr/include和/usr/lib,因为它们是 x86 架构的。解决办法是把目标机上的系统目录完整同步一份到宿主机,称为 sysroot。
我用的同步命令(第一次同步可能耗时较长,之后增量更新就好):
mkdir -p ~/loongarch-sysroot rsync -avz --copy-links \ --exclude='/proc' --exclude='/sys' --exclude='/dev' \ --exclude='/tmp' --exclude='/run' --exclude='/mnt' \ root@<龙芯目标机IP>:/ \ ~/loongarch-sysroot/这一步会把整个根文件系统拷贝过来,实际比较需要的是/usr、/lib、/etc/alternatives这几个位置。--copy-links很重要,如果没有它,/usr/lib下的动态链接器软链接和.so文件软链会碎掉,后面链接阶段就等着报错吧。
同步完确认几个关键文件:
ls -l ~/loongarch-sysroot/lib/ld-linux-loongarch-lp64d.so.1 ls -l ~/loongarch-sysroot/usr/lib/loongarch64-linux-gnu/libc.so.6如果这两个存在,说明系统库同步基本正常。注意libc.so.6在交叉编译工具链里通常也带一份,但链接阶段应该优先读 sysroot 里的版本,顺序弄反会产生莫名奇妙的运行时问题。
实践心得:sysroot 最好做一次完整快照,不要今天拷/usr明天拷/lib,缺了一两个库在链接期会反复报cannot find -lxxx,排查起来很头疼。
4. Qt 环境构建:官方 SDK 和源码自编译两种路线全拆解
4.1 路线 A:直接使用官方 Qt for LoongArch 交叉编译 SDK
龙芯社区维护的 Qt SDK 主要基于 Qt 5.15 系列,下载后可能是 tar.gz 或自解压脚本。解压后通常是这样:
/opt/qt-loongarch/ ├── bin/ │ ├── qmake │ └── ... ├── lib/ │ ├── libQt5Core.so.5 │ ├── libQt5Widgets.so.5 │ └── ... ├── plugins/ └── mkspecs/拿到先跑一遍:
/opt/qt-loongarch/bin/qmake -v正常情况下会输出类似QMake version 3.1 Using Qt version 5.15.x的信息。这一步能确认 Qt 库文件是否完整。如果 qmake 能运行,说明这个 SDK 自带的是 host 工具,同时关联对应的 target 库,很省事。
在此基础上,Qt Creator 里只需要告诉它三件事:编译器用哪个、qmake 用哪个、sysroot 在哪。后面第 5 节会细讲。
4.2 路线 B:从 qt-everywhere-src 自行交叉编译
源码自编译这件事,我不建议一开始就搞,但对定制需求强烈的人来说绕不过去,所以把关键步骤写清楚。我以qt-everywhere-src-5.15.10为例。
首先下载解压:
wget https://download.qt.io/archive/qt/5.15/5.15.10/single/qt-everywhere-src-5.15.10.tar.xz tar -xJf qt-everywhere-src-5.15.10.tar.xz cd qt-everywhere-src-5.15.10然后需要为 LoongArch 创建 mkspec。Qt 默认支持很多平台,但 LoongArch 的 mkspec 不一定包含在 5.15 里面,所以需要基于linux-g++复制一份修改。
cp -r qtbase/mkspecs/linux-g++ qtbase/mkspecs/linux-loongarch64-g++编辑qtbase/mkspecs/linux-loongarch64-g++/qmake.conf,把编译器改成交叉工具链:
QMAKE_CC = loongarch64-linux-gnu-gcc QMAKE_CXX = loongarch64-linux-gnu-g++ QMAKE_LINK = loongarch64-linux-gnu-g++ QMAKE_LINK_SHLIB = loongarch64-linux-gnu-g++然后创建 configure 参数:
export PATH=/opt/loongarch64-toolchain/bin:$PATH ./configure -release -opensource -confirm-license \ -prefix /opt/qt-loongarch \ -xplatform linux-loongarch64-g++ \ -sysroot /home/<user>/loongarch-sysroot \ -extprefix /opt/qt-loongarch \ -hostprefix /opt/qt-loongarch-host \ -nomake examples -nomake tests \ -skip qtwebengine -skip qtwebchannel \ -no-opengl \ -linuxfb -eglfs \ -qt-libjpeg -qt-libpng -qt-zlib -qt-pcre这里解释几个重点参数的含义:
-sysroot:指向第 3 节同步的目标机根文件系统,编译器找头文件和系统库就从这个根开始。-extprefix:最终 target Qt 库的安装目录,也就是程序部署时要拷到目标机上的那套库文件。-hostprefix:编译过程中生成的 host 工具(qmake、moc 等)的安装目录,比如 qmake 必须能在宿主机上运行。-xplatform linux-loongarch64-g++:告知 Qt 使用我们新做的 LoongArch mkspec。-no-opengl:看目标机情况,很多龙芯设备图形能力有限,Linux 下用linuxfb或eglfs跑界面就够了。-skip:跳过部分不常用且容易编译失败的模块,还好我实际编译时跳过的就是 webengine 这类重型模块,省了大量时间。
配置完成后:
make -j$(nproc) sudo make install编译 Qt 的时间取决于机器性能,全量 5.15 编完在 i7/16GB 机器上大概半小时到一小时,如果遇到某个模块失败,先调整-skip参数,把不参与实际业务的模块跳过去,不要死磕。
4.3 两种路线间的补充说明
如果你的目标机跑的是 openEuler 或 deepin 的 LoongArch 版本,系统自带的 Qt 库版本可能和 SDK 的一致,也可能不一致,建议尽可能使用同一个 Qt 小版本,否则在运行时出现 ABI 不兼容会比较麻烦。
还有一个实际情况:官方 SDK 里不一定包含全部模块,比如qtcharts、qtserialport这类附加模块。它们的交叉编译原理和上面一样,先拿源码包解压,用同一套 mkspec 和 qmake 配置去构建,再把产出安装到同一个 Qt 前缀目录即可。
5. Qt Creator 套件配置:四步搭建完整开发环境
5.1 在 Qt Creator 添加 LoongArch 交叉编译器
打开 Qt Creator,进入“工具 -> 选项 -> Kits -> 编译器”,点击“添加 -> GCC -> C++”。
重点在于“编译器路径”要定位到交叉工具链的 g++:
/opt/loongarch64-toolchain/bin/loongarch64-linux-gnu-g++Qt Creator 会自动识别 ABI,如果没有自动识别,手动选择一种类似“Generic: Linux / 64-bit / unknown / 64-bit”的 ABi 也可以。但我不推荐乱选,识别不准会导致后面套件无效,最好在“编译 ABI”里能看到loongarch64相关前缀。C 编译器同理,路径选择loongarch64-linux-gnu-gcc。
这里有一个常见的细节:Qt Creator 有“C”和“C++”两个编译器配置页,很多人只配了 C++,结果项目里混用.c文件时编译器找不到,所以两个都要加。
5.2 注册 Qt 版本:把 qmake 交给 Qt Creator
进入“Kits -> Qt Versions”,点击“添加”,选择 qmake 的可执行文件路径。官方 SDK 就选:
/opt/qt-loongarch/bin/qmake如果是源码编译路线,同样用/opt/qt-loongarch/bin/qmake。添加成功后,版本信息会显示对应的 Qt 版本(如 Qt 5.15.10)、源码位置和 Qt 库位置。这一步能通过的前提是这个 qmake 可以在宿主机上运行,如果运行不了,说明 zlib、libstdc++ 等 host 侧依赖没满足,需要先解决。
对于 CMake 项目,Qt Creator 也会自动扫描 CMake 工具链,如果你用 CMake 作为构建系统,建议同时在“Kits -> CMake”里确认有可用的 CMake 生成器(Unix Makefiles 或 Ninja 都行)。
5.3 新建套件(Kit):把编译器、Qt、sysroot 串起来
在“Kits -> 套件”中点击“添加”。参考配置如下:
| 配置项 | 推荐值 |
|---|---|
| 名称 | 龙芯 LoongArch (Qt 5.15) |
| 设备类型 | 通用 Linux 设备(配置 SSH) |
| 编译器 C | loongarch64-linux-gnu-gcc |
| 编译器 C++ | loongarch64-linux-gnu-g++ |
| 调试器 | loongarch64-linux-gnu-gdb(如没有可留空) |
| Qt 版本 | 上面添加的 Qt 5.15.10 |
| CMake 工具 | 使用系统 CMake 即可 |
| Sysroot | /home/ /loongarch-sysroot |
如果你手头没有 LoongArch 版 gdb,调试器一项可以留空,只做编译和运行验证。但如果你打算在 Qt Creator 里直接点 Debug 远程调试,还是建议装一个 LoongArch gdb,很多工具链包里会一并带上。
Sysroot 路径一定要填,否则即使编译器选对了,找系统头文件时还会回到宿主机目录,链接出来一堆版本错乱的问题。
5.4 配置设备与部署路径
进入“工具 -> 选项 -> 设备”,点击“添加 -> 通用 Linux 设备”,填写龙芯机器的 IP、SSH 用户名和密码。Qt Creator 会测试连接,如果能读取到/etc/os-release这类系统信息,说明连接成功。
然后在“项目 -> 构建与运行 -> Run”里设置可执行文件部署路径,例如:
/opt/apps/myapp部署方式可以选择内置的“上传文件”或“rsync”步骤,也可以自己加一个“自定义处理步骤”脚本。我用的是内置 rsync 部署,编译完成后自动把二进制和必需库 push 到目标机的/opt/apps/myapp目录。如果项目依赖 Qt 的动态库,建议把libQt5Core.so.5这些按需拷贝到同一个目录,运行前在目标机上设置:
export LD_LIBRARY_PATH=/opt/apps/myapp:$LD_LIBRARY_PATHQt Creator 的“Run”配置里也能直接设置环境变量(点击“Run Environment”旁边的详情),把上面的LD_LIBRARY_PATH填进去,这样从开发环境直接点击运行,Qt Creator 会自动执行远程命令,省去手动敲命令的麻烦。
6. 高频坑点与排查实录
6.1 坑:交叉编译器版本和目标机系统 libc 版本不匹配
有一次项目在 qtbase configure 阶段过了,编译也过了,部署到龙芯机器后一运行就报:
Fatal error: QElfParser: failed to parse dynamic library ...或者干脆是Segmentation fault。排查下来是工具链里的 glibc 版本比目标机系统自带的要高,编译产物链接了较新 glibc 符号,目标机的动态库解析不了。
解决办法有两个:一是更换与目标机系统发行版配套的工具链版本(例如目标机是 openEuler,就找 openEuler 仓库里对应版本的工具链);二是同步 sysroot 时,把目标机系统的 glibc 相关文件完整同步,避免编译器自带 glibc 响应文件覆盖了 sysroot 里的版本。经验是先loongarch64-linux-gnu-gcc -v看工具链默认搜索路径,再用find确认 sysroot 下实际生效的libc.so.6是哪个版本。
6.2 坑:sysroot 路径不对,头文件或库找不到
Qt Creator 里填了 Sysroot 后,qmake 项目仍然找不到X11/Xlib.h或者链接时报cannot find -lGL,十有八九是 sysroot 不完整。最典型的是/usr/lib/loongarch64-linux-gnu这个多架构目录没同步到,或者同步时软链接断了。
排查方法很直接,在终端里手动加参数试编译一次:
echo 'int main() { return 0; }' > t.c loongarch64-linux-gnu-gcc --sysroot=/home/<user>/loongarch-sysroot t.c -o t找不到哪个头文件,就到 sysroot 对应目录里find搜索。比如:
find ~/loongarch-sysroot -name "libGL.so*"确认后重新用 rsync 拉取缺失目录。不要图省事只在宿主机的/usr/include里加搜素路径,那样会引入 x86 的头文件,编译能过但后续行为不可控。
6.3 坑:qmake 缓存导致配置残留
如果你先用了路线 A 的官方 SDK 配置 Qt,后来又切换到源码编译的 Qt,或者改了-prefix和-sysroot,一定要小心 qmake 的缓存文件。最典型的表现是:明明配置了新的 sysroot,编译时却还去找旧路径下的头文件,或者生成的 Makefile 里带着过时的编译器路径。
处理办法是:
cd /opt/qt-loongarch make distclean make clean ./configure ... make如果还不行,检查源码目录下的.qmake.cache和config.cache文件,建议直接删掉再重新 configure。还有,改 mkspec 后务必确认mkspecs/qconfig.pri里没有残留旧平台信息。
实践中我还遇到过一个更隐蔽的缓存:Qt Creator 的“构建目录”里残留了旧 Kit 的 CMakeCache,切了新 Kit 后依然用旧缓存。解决方法是清理项目构建目录,让 Qt Creator 重新运行 CMake 或 qmake,不要只点“重新构建”。
6.4 坑:程序部署后提示找不到 Qt 平台插件
这是交叉编译部署里最典型的运行时报错:
This application failed to start because no Qt platform plugin could be initialized.原因很直白:Qt 程序需要platforms插件来完成和显示环境的对接。你编译时链接的是 Qt 库,但插件是运行时动态加载的,目录不对就会找不到。
解决办法是找到 Qt 库目录下的plugins/platforms目录(/opt/qt-loongarch/plugins/platforms),把整个platforms目录复制到程序部署目录,保持相对结构:
/opt/apps/myapp/ ├── myapp └── plugins/ └── platforms/ ├── libqlibinput.so ├── libqlinuxfb.so └── libqminimal.so然后运行时指定平台插件搜索路径:
export QT_PLUGIN_PATH=/opt/apps/myapp/plugins如果在龙芯设备上没有显示环境,就加上:
export QT_QPA_PLATFORM=linuxfblinuxfb适合简单的 Linux 直接帧缓冲场景,不需要 X11。如果目标机有桌面环境,可以不用设,或者换成xcb。
6.5 坑:Qt Creator 代码对齐快捷方式不好用
这个话题是很多人实际用 Qt Creator 时都会吐槽的。默认情况下,QCreator 对齐代码的快捷方式是Ctrl+I(自动缩进),选中一段代码后按Ctrl+I会执行自动缩进,但很多人发现它对“格式化对齐”的需求(比如等号对齐、花括号对齐)并不生效,代码粘过来还是一团乱。
我的处理方法是启用 Qt Creator 自带的 Beautifier 插件。路径是“工具 -> 选项 -> Beautifier”。在 Beautifier 的 General 页面里选择“Artistic Style”或“clang-format”,设置好对应可执行文件,然后在“Clang Format”或“Artistic Style”页面里把项目和工具链对应起来。配置完成后,编辑代码时选中需要格式化的段落,按快捷键触发格式化(默认可能是Ctrl+Shift+F之类,具体可以在“环境 -> 键盘”里搜索“Beautifier”并改成你想要快捷键)。如果你不满意的只是对齐缩进,也可以直接在“环境 -> 键盘”搜索“Auto-indent Selection”和“Format”相关命令,重新分配快捷键。这种方式比折腾默认快捷键省心很多,也是我建议你去自定义的原因。
6.6 坑:编译时 OpenGL 相关模块失败
Qt 源码编译阶段,qtbase和qtdeclarative都对 OpenGL 有编译期依赖。很多龙芯设备的显卡驱动和 OpenGL ES 支持不完整,configure 时直接-no-opengl可以绕开,但这样编译出来的 Qt 不支持某些依赖 OpenGL 的模块,比如qt3d、qtquick3d。
如果你的界面主要基于 QWidget,这完全不影响。如果必须用 Qt Quick 3D,那对目标机的显卡驱动要求很高,建议先在目标机上跑一个 Qt 自带的qtdiag或glxinfo看看 OpenGL 支持级别,再决定要不要带 OpenGL 编译。这个坑点属于“不匹配导致编译失败”而非“不会配置”,大家一定先弄清目标机硬件,再动 configure 参数。
7. 一套我能稳定复用的检查清单
配置过几次后,我把这套流程里的关键检查项整理成清单,每次配新机器都照着过一遍,基本不会出大错:
- 交叉编译工具链版本号和目标机发行版匹配,
loongarch64-linux-gnu-gcc -v和/etc/os-release对照检查。 sysroot里/lib/ld-linux-loongarch-lp64d.so.1存在且软链接完整。- qmake 能运行,用
qmake -v确认版本和 SDK 一致。 - Qt Creator 里 C 和 C++ 编译器都配置,ABI 识别正确。
- Kit 指向 qmake、sysroot、编译器的路径均正确。
- 程序部署时
LD_LIBRARY_PATH和QT_PLUGIN_PATH都设置好。 - 远程设备 IP、SSH 密钥、部署目录配置在 Qt Creator 里能连通。
- 第一次部署后在目标机上用
ldd myapp检查动态库依赖,缺什么补什么。
这套清单尤其适合半路接手别人环境的人——很多情况下程序跑不起来,不是代码的问题,而是环境检查漏掉了某一项。
8. 最后再分享一点我的实际体会
我在实际配置中还有一个非常推荐的做法:把交叉编译工具链和 Qt SDK 统一放在/opt下的固定目录,并把这些目录路径写成环境变量配置脚本,比如/opt/loongarch-env.sh,内容就是export PATH、export LD_LIBRARY_PATH这些。换机器或者换同事交接时,把整个目录打包带走,配置文件名一改就能继续用,比在每台机器上重新下载工具链、重新编译 Qt 省太多时间。
另外,如果你发现第一次在 Qt Creator 里配置完 Kit 后,构建时 qmake 一直报错,可以先在终端里手动跑一次qmake && make,确认命令行环境没问题,再回去检查 Qt Creator 的环境变量配置。很多时候问题出在 Qt Creator 没有加载宿主机的预设环境变量,导致交叉编译器不在 PATH 里。这是个小细节,但特别容易让人忽略。
环境搭建这一类工作,最忌讳的就是只配到一个“看起来能编译”的程度,真正决定开发效率的还是部署和调试链路是否顺畅。把本文中部署到龙芯设备、远程运行、LD_LIBRARY_PATH 这些步骤一次配好后,你的 x86 工作站基本就变成一台“龙芯项目快速开发机”了,后面写业务代码、调界面会顺畅很多。