交叉编译器
如果接触过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
|
然后在开发板中执行:
如果你看到终端打印出了"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
|
执行编译:
默认会编译所有模块,共计需要编译一万多个文件,时间会很长(我用了将近三个小时)。此构建必须成功,否则得不到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
|
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"
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
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 SET(CMAKE_SYSTEM_PROCESSOR
SET(CMAKE_C_COMPILER SET(CMAKE_CXX_COMPILER
# ARM根文件系统路径 SET(CMAKE_SYSROOT /home//linux//NXP_rootfs/
# ARM根文件系统路径 SET(CMAKE_FIND_ROOT_PATH /home//linux//NXP_rootfs/
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE SET(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
|
按照注释,将arm的根文件路径替换成自己开发板的路径。