1. 项目概述
作为一名嵌入式开发工程师,最近在泰山派RK3566开发板上进行QT6.5的交叉编译实践。这个项目的主要目标是在x86架构的Ubuntu22.04主机上,为ARM架构的RK3566开发板编译QT6.5框架,最终实现在开发板上运行QT应用程序。
交叉编译是嵌入式开发中的常见需求,特别是在资源有限的嵌入式设备上直接编译大型框架如QT会非常耗时。通过交叉编译,我们可以利用性能更强的开发主机完成编译工作,然后将编译好的二进制文件部署到目标设备上运行。
2. 环境准备
2.1 主机环境配置
主机环境采用Ubuntu22.04 LTS,这是目前LTS版本中较新的一个,对QT6.5有良好的支持。在开始之前,建议执行以下基础准备:
code复制sudo apt update
sudo apt upgrade
这确保了系统包是最新的,避免后续安装依赖时出现版本冲突。
2.2 交叉编译工具链选择与安装
对于RK3566这类ARM Cortex-A55/A72架构的处理器,我们选择gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu工具链。这个版本的工具链有几个优势:
- GCC 10.2版本对C++17有完整支持,与QT6.5的要求匹配
- 2020.11发布的版本经过充分测试,稳定性较好
- 专门针对aarch64架构优化
下载并安装工具链的步骤如下:
code复制wget https://developer.arm.com/-/media/Files/downloads/gnu-a/10.2-2020.11/binrel/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu.tar.xz
tar xf gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu.tar.xz -C ~/
注意:下载链接可能会更新,建议从Arm官网获取最新稳定版本的工具链。
2.3 环境变量配置
为了让系统识别交叉编译工具链,需要将工具链路径添加到环境变量中。编辑~/.bashrc文件,在末尾添加:
code复制export ARCH=arm64
export CROSS_COMPILE=aarch64-none-linux-gnu-
export PATH=$PATH:/home/$USER/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin
然后执行source ~/.bashrc使配置生效。验证工具链是否安装成功:
code复制aarch64-none-linux-gnu-gcc -v
如果能看到版本信息输出,说明工具链配置正确。
3. QT6.5源码获取与准备
3.1 下载QT6.5源码
QT官方提供了完整的源代码包,我们可以直接下载:
code复制mkdir ~/qt6 && cd ~/qt6
wget https://download.qt.io/archive/qt/6.5/6.5.0/single/qt-everywhere-src-6.5.0.tar.xz
tar xf qt-everywhere-src-6.5.0.tar.xz
QT6.5源码包大约1.2GB,解压后约5GB,请确保有足够的磁盘空间。
3.2 创建交叉编译配置文件
在qt-everywhere-src-6.5.0目录下创建aarch64-toolchain.cmake文件,内容如下:
cmake复制set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_CROSSCOMPILING TRUE)
set(CMAKE_C_COMPILER aarch64-none-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-none-linux-gnu-g++)
set(CMAKE_ASM_COMPILER aarch64-none-linux-gnu-gcc)
set(CMAKE_SYSROOT /opt/rk3566-sysroot)
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
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)
set(ENV{PKG_CONFIG_PATH} "${CMAKE_SYSROOT}/usr/lib/aarch64-linux-gnu/pkgconfig")
set(GSTREAMER_INCLUDE_DIRS ${CMAKE_SYSROOT}/usr/include/gstreamer-1.0)
set(GSTREAMER_LIBRARY_DIRS ${CMAKE_SYSROOT}/usr/lib/aarch64-linux-gnu)
这个文件定义了交叉编译的关键参数,包括:
- 目标系统类型(Linux)
- 处理器架构(aarch64)
- 编译器路径
- sysroot路径
- 库和头文件的查找规则
3.3 线程支持补丁文件
由于交叉编译环境下线程库的特殊性,我们需要创建一个aarch64-threads-fix.cmake文件:
cmake复制if(NOT TARGET Threads::Threads)
find_package(Threads QUIET)
if(NOT TARGET Threads::Threads)
add_library(Threads::Threads INTERFACE IMPORTED)
set_target_properties(Threads::Threads PROPERTIES
INTERFACE_LINK_LIBRARIES "pthread"
)
message(STATUS "Created Threads::Threads target manually for cross-compilation")
endif()
endif()
这个文件确保在交叉编译环境下能够正确链接到pthread库。
4. 目标板系统准备
4.1 开发板环境配置
在RK3566开发板上执行以下命令安装必要的开发包:
code复制sudo apt update
sudo apt install libgstreamer1.0-dev gstreamer1.0-plugins-* \
gstreamer1.0-libav libhunspell-dev
sudo apt install -y build-essential libc6-dev libegl1-mesa-dev \
libgles2-mesa-dev libpthread-stubs0-dev
这些包提供了QT运行所需的基础库支持,包括:
- GStreamer多媒体框架
- OpenGL ES图形库
- 基础开发工具链
4.2 创建sysroot
sysroot是交叉编译的关键,它包含了目标板的系统文件和库。我们通过rsync从开发板同步:
code复制sudo mkdir -p /opt/rk3566-sysroot
sudo rsync -avz --progress --delete \
--include='/' \
--include='/usr/include/***' \
--include='/usr/lib/aarch64-linux-gnu/***' \
--include='/lib/aarch64-linux-gnu/***' \
--exclude='*' \
开发板用户@开发板IP:/ /opt/rk3566-sysroot/
注意:需要将"开发板用户@开发板IP"替换为实际的开发板登录信息。
4.3 sysroot调整
同步完成后,需要对sysroot做一些调整:
- 将关键库文件移动到正确位置:
code复制sudo mv /opt/rk3566-sysroot/usr/lib/aarch64-linux-gnu/crt1.o /opt/rk3566-sysroot/lib/
sudo mv /opt/rk3566-sysroot/usr/lib/aarch64-linux-gnu/crti.o /opt/rk3566-sysroot/lib/
sudo mv /opt/rk3566-sysroot/usr/lib/aarch64-linux-gnu/libc.so.6 /opt/rk3566-sysroot/lib/
- 创建必要的符号链接:
code复制cd /opt/rk3566-sysroot/lib
sudo ln -sfn libc.so.6 libc.so
- 创建EGL和GLESv2的CMake配置文件:
在/opt/rk3566-sysroot/usr/lib/aarch64-linux-gnu/cmake/目录下创建EGLConfig.cmake和GLESv2Config.cmake文件,内容参考开发板上对应的文件。
5. 配置与编译QT6.5
5.1 创建构建目录
在QT源码目录下创建build目录并进入:
code复制cd ~/qt6/qt-everywhere-src-6.5.0
mkdir build && cd build
5.2 配置QT构建
执行以下命令进行配置:
bash复制cmake -G Ninja \
-DCMAKE_TOOLCHAIN_FILE=../aarch64-toolchain.cmake \
-DCMAKE_INSTALL_PREFIX=/opt/qt6-rk3566 \
-DQT_HOST_PATH=/opt/qt6-host \
-DQT_QPA_DEFAULT_PLATFORM=linuxfb \
-DCMAKE_SYSROOT=/opt/rk3566-sysroot \
-DQT_BUILD_EXAMPLES=OFF \
-DQT_BUILD_TESTS=OFF \
-DQT_BUILD_TOOLS_WHEN_CROSSCOMPILING=ON \
..
关键参数说明:
-G Ninja: 使用Ninja作为构建系统,比make更快-DCMAKE_TOOLCHAIN_FILE: 指定交叉编译工具链文件-DCMAKE_INSTALL_PREFIX: QT安装路径-DQT_QPA_DEFAULT_PLATFORM: 默认使用linuxfb显示后端-DQT_BUILD_EXAMPLES=OFF: 不编译示例程序,节省时间
5.3 解决依赖问题
配置过程中可能会报告缺少某些库,这是正常现象。解决方法:
- 在开发板上安装缺失的库
- 重新同步sysroot
- 如果某些库确实无法安装,可以在CMake配置中禁用相关模块
常见的缺失库可以通过以下命令安装:
code复制sudo apt install libxcb-xinerama0-dev libxcb-xinput-dev libxcb-xkb-dev
5.4 编译与安装
配置成功后,开始编译:
code复制cmake --build . --parallel $(nproc)
使用$(nproc)可以自动检测CPU核心数进行并行编译,大幅提高编译速度。编译完成后安装:
code复制sudo cmake --install .
编译过程可能需要几个小时,取决于主机性能。
6. 验证交叉编译结果
6.1 检查生成的文件
安装完成后,检查生成的qml解释器架构:
code复制file /opt/qt6-rk3566/bin/qml
输出应显示为aarch64架构的ELF文件。
6.2 打包与部署
将编译好的QT打包并传输到开发板:
code复制tar czf qt6-rk3566.tar.gz /opt/qt6-rk3566
scp qt6-rk3566.tar.gz 开发板用户@开发板IP:/opt/
在开发板上解压:
code复制sudo tar xzf /opt/qt6-rk3566.tar.gz -C /opt/
7. 开发板环境配置
7.1 设置环境变量
在开发板上创建/etc/profile.d/qt.sh文件,内容如下:
bash复制export QT_QPA_PLATFORM=linuxfb
export LD_LIBRARY_PATH=/opt/qt6-rk3566/lib:$LD_LIBRARY_PATH
export PATH=/opt/qt6-rk3566/bin:$PATH
sudo chmod 666 /dev/fb0
sudo chmod 666 /dev/input/event*
执行source /etc/profile使配置生效。
7.2 权限设置
将当前用户加入必要的组:
code复制sudo usermod -aG video,input 用户名
需要重新登录使组变更生效。
8. 测试QT应用程序
8.1 创建测试QML文件
创建一个简单的测试程序test.qml:
qml复制import QtQuick
import QtQuick.Window
Window {
width: 800
height: 480
visible: true
title: "Qt6 HDMI Test"
color: "#3498db"
Text {
anchors.centerIn: parent
text: "Hello RK3566 HDMI!"
font.pixelSize: 48
color: "white"
}
Text {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
text: "Qt Version: " + Qt.application.version
font.pixelSize: 16
color: "white"
}
}
8.2 运行测试程序
根据显示后端选择运行方式:
- 使用linuxfb后端:
code复制export QT_QPA_PLATFORM=linuxfb
qml test.qml
- 使用eglfs后端(需要GPU支持):
code复制export QT_QPA_PLATFORM=eglfs
qml test.qml
8.3 显示后端比较
两种显示后端的主要区别:
| 特性 | linuxfb | eglfs |
|---|---|---|
| 工作原理 | 直接写framebuffer | 通过DRM/KMS与显示控制器交互 |
| 性能 | 较低 | 较高,支持硬件加速 |
| 退出行为 | 不清屏,最后一帧保留 | 释放资源,屏幕变黑 |
| 多窗口 | 不支持 | 支持 |
| 输入设备 | 需要额外配置 | 自动处理 |
对于RK3566这类有GPU的设备,推荐使用eglfs后端以获得更好的性能。
9. 常见问题与解决方案
9.1 编译过程中的错误处理
-
找不到库文件:
- 确保sysroot同步完整
- 检查库文件路径是否正确
- 在开发板上安装缺失的库后重新同步
-
线程支持问题:
- 确保使用了aarch64-threads-fix.cmake文件
- 检查pthread库是否存在于sysroot中
-
EGL/GLES配置问题:
- 确认开发板上安装了libegl1-mesa-dev和libgles2-mesa-dev
- 检查sysroot中是否有正确的EGLConfig.cmake和GLESv2Config.cmake
9.2 运行时的常见问题
-
无法打开显示设备:
- 检查/dev/fb0权限
- 确认用户加入了video组
- 尝试使用sudo运行(仅用于测试,生产环境应正确配置权限)
-
缺少QT插件:
- 检查QT_QPA_PLATFORM_PLUGIN_PATH环境变量
- 确认所有插件都部署到了开发板
-
字体显示问题:
- 确保开发板上有字体文件
- 设置QT_QPA_FONTDIR环境变量指向字体目录
10. 性能优化建议
10.1 编译选项优化
在CMake配置时可以添加以下选项提高运行时性能:
code复制-DCMAKE_BUILD_TYPE=Release \
-DQT_FEATURE_opengles2=ON \
-DQT_FEATURE_opengles3=ON \
-DQT_FEATURE_opengles31=ON \
-DQT_FEATURE_opengles32=ON \
10.2 减少QT模块
只编译需要的模块可以显著减少编译时间和最终安装大小:
code复制-DQT_FEATURE_qt3d=OFF \
-DQT_FEATURE_qtcharts=OFF \
-DQT_FEATURE_qtdatavis3d=OFF \
10.3 使用静态链接
对于嵌入式设备,可以考虑静态链接QT库以减少运行时依赖:
code复制-DQT_BUILD_SHARED_LIBS=OFF
但需要注意静态链接会增加单个可执行文件的大小,且可能需要处理许可证问题。
11. 进阶应用
11.1 自定义QT插件
针对RK3566的硬件特性,可以开发自定义QT插件来优化性能。例如,可以实现一个专门针对Mali GPU的QPA插件。
11.2 多媒体应用开发
利用RK3566的硬件编解码能力,可以开发高性能多媒体应用。QT的Multimedia模块与GStreamer后端结合,可以实现高效的视频播放和处理。
11.3 3D图形应用
RK3566的Mali-G52 GPU支持OpenGL ES 3.2,可以开发3D图形应用。QT Quick 3D模块提供了高级别的3D图形API,简化了开发流程。
12. 项目总结
这次在泰山派RK3566开发板上交叉编译QT6.5的过程,让我对嵌入式QT开发有了更深入的理解。关键的收获包括:
- 交叉编译环境的搭建需要特别注意工具链、sysroot和环境变量的配置
- QT的模块化设计允许我们只编译需要的组件,节省时间和空间
- 显示后端的选择对应用程序的性能和表现有重大影响
- 嵌入式环境下的权限管理比桌面环境更加严格
在实际操作中,最耗时的部分是解决各种依赖关系和库路径问题。通过创建完整的sysroot和仔细配置工具链文件,可以大大减少这类问题。
