基于Qt 6.9 为 ARM 设备交叉编译应用程序

交叉编译器

如果接触过Linux驱动或应用开发,那么你一定有一个交叉编译器,用于在x64的机器上将c文件编译成可供arm架构设备执行的二进制版本。Qt也是这样,不过不同的是Qt基于C运行,因此交叉编译器不再是xxx-gcc,而是xxx-g++xxx-gnu。以我的交叉编译器为例,编译C语言时我使用的是7.5.0版本的Linaro公司的arm-linux-gnueabihf-gcc。同理,编译C的就是arm-linux-gnueabihf-g++

有一个办法可以用来快速确认编译器是否可用。在开发板的根目录下(或者别的随便什么位置)新建一个测试文件test.cpp,输入:

1
2
3
4
5
6
7
8
#include <iostream>
using namespace std;

int main()
{
cout << "Hello World!" << endl;
return 0;
}

然后在Ubuntu虚拟机中将其交叉编译为arm:

1
arm-linux-gnueabihf-g++ test.cpp -o test

然后在开发板中执行:

1
./test

如果你看到终端打印出了"Hello World!",说明你的交叉编译器工作正常。

Qt环境配置

我们常说的“Qt"其实由很多个东西组成,包括但不限于:

  • Qt源码(source code),比如 QtCore、QtWidgets、QtNetwork 等模块
  • Qt Creator:Qt 官方的 IDE(集成开发环境),用来写代码、调试、构建 Qt 应用
  • Qt UI designer:用于设计UI

现在官方主推的安装Qt的方式是通过在线安装器安装,安装时一般会让你选择需要安装哪些组件。需要注意的是,安装器默认是不会安装Qt源码的,而交叉编译Qt给arm设备又必须需要Qt源码,因为Qt默认没有提供arm的二进制文件。因此我们需要从官网下载Qt源码,这里我选择6.9版本。

在Qt5时代,可以只进行一次交叉编译。而Qt6则必须先用宿主机(Qt Host)编译一次以生成Host Build的Qt工具链用于后续的Qt tools构建,也就是必须基于x86_64先编译一次Qt的源码,生成一些Qt需要的宿主工具,比如moc和rcc。然后在这基础上,才能继续进行交叉编译。交叉编译时也需要向Cmake指定宿主工具的目录,否则交叉编译会失败。Qt5的编译步骤和Qt6差异较大,而关于Qt5的编译教程又有很多,这里就不展开了,主要讲Qt6.

在浏览器中下载源码并拷贝至虚拟机:https://download.qt.io/official_releases/qt/6.9/6.9.0/single/qt-everywhere-src-6.9.0.tar.xz

或者直接在虚拟机中wget https://download.qt.io/official_releases/qt/6.9/6.9.0/single/qt-everywhere-src-6.9.0.tar.xz

下载完成后,解压(耗时较长),进入源码目录。

基于x86_64编译获得Qt Host

首先要构建Host。在Qt源码目录下新建一个build-qt-host文件夹,用于存放编译结果:

1
2
cd ~/Qt_source_code/qt-everywhere-src-6.9.0
mkdir build-qt-host && cd build-qt-host

然后在终端中配置cmake:

1
2
3
4
5
cmake .. \
-GNinja \
-DCMAKE_BUILD_TYPE=Release \
-DQT_BUILD_EXAMPLES=OFF \
-DQT_BUILD_TESTS=OFF

执行编译:

1
ninja

默认会编译所有模块,共计需要编译一万多个文件,时间会很长(我用了将近三个小时)。此构建必须成功,否则得不到Qt需要的宿主工具。

这里当然也可以只编译自己需要的模块,比如我只需要Core、Gui、Widgets、Network这些比较基础的模块,可以指定:

1
2
3
4
-DFEATURE_network=ON \
-DFEATURE_gui=ON \

......

现在大语言模型这么发达,完全可以让gpt或者deepseek写一个shell脚本,告诉他想要的模块,然后一键编译。这样编译的文件数量和时长会大大减少。

比如这是我的shell文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#!/bin/bash

# ======================
# Qt Host Build Script
# Author: ChatGPT
# ======================

set -e

# 设置变量
QT_SRC_DIR=~/Qt_source_code/qt-everywhere-src-6.9.0
QT_INSTALL_PREFIX=/usr/local/qt6-host
BUILD_DIR=$QT_SRC_DIR/build-qt-host

# 创建安装路径(如未存在)
sudo mkdir -p "$QT_INSTALL_PREFIX"
sudo chown $(whoami):$(whoami) "$QT_INSTALL_PREFIX"

# 清理旧构建目录
rm -rf "$BUILD_DIR"
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"

# ========== Step 1: 构建 qtbase ==========
echo "=== Configuring qtbase ==="
cmake "$QT_SRC_DIR/qtbase" \
-GNinja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="$QT_INSTALL_PREFIX" \
-DFEATURE_sql=ON \
-DFEATURE_network=ON \
-DFEATURE_gui=ON \
-DFEATURE_widgets=ON \
-DFEATURE_opengl=OFF \
-DFEATURE_dbus=OFF \
-DFEATURE_printsupport=OFF \
-DQT_BUILD_EXAMPLES=OFF \
-DQT_BUILD_TESTS=OFF

echo "=== Building qtbase ==="
ninja
echo "=== Installing qtbase ==="
ninja install

# ========== Step 2: 构建 qtcharts ==========
echo "=== Configuring qtcharts ==="
mkdir -p "$QT_SRC_DIR/build-qtcharts-host"
cd "$QT_SRC_DIR/build-qtcharts-host"

cmake "$QT_SRC_DIR/qtcharts" \
-GNinja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH="$QT_INSTALL_PREFIX" \
-DCMAKE_INSTALL_PREFIX="$QT_INSTALL_PREFIX" \
-DQT_BUILD_EXAMPLES=OFF \
-DQT_BUILD_TESTS=OFF

echo "=== Building qtcharts ==="
ninja
echo "=== Installing qtcharts ==="
ninja install

echo "✅ Qt Host Build Completed and Installed to $QT_INSTALL_PREFIX"

交叉编译Qt

Qt6默认且推荐使用Cmake构建,和makefile相似,Cmake需要一个配置文件来向编译器告知交叉编译工具链。在源码目录下新建一个arm-gnueabihf-toolchain.cmake

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# arm-gnueabihf-toolchain.cmake
SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_SYSTEM_PROCESSOR arm)

SET(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
SET(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)

# ARM根文件系统路径
SET(CMAKE_SYSROOT /home/aki/linux/nfs/NXP_rootfs/)

# ARM根文件系统路径
SET(CMAKE_FIND_ROOT_PATH /home/aki/linux/nfs/NXP_rootfs/)

SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

按照注释,将arm的根文件路径替换成自己开发板的路径。


基于Qt 6.9 为 ARM 设备交叉编译应用程序
http://akichen891.github.io/2025/04/24/Qt交叉编译/
作者
Aki
发布于
2025年4月24日
更新于
2025年4月24日
许可协议