1. 交叉编译配置
在嵌入式 Linux 开发中,交叉编译工具链是连接宿主机与目标板的关键桥梁。arm-2014.05-29 是 CodeSourcery 推出的基于 ARM 架构的交叉编译工具链版本,广泛用于早期 ARM 平台(如 ARM926EJ-S、Cortex-A8 等)的内核与驱动开发。本章详细介绍该工具链的下载、配置、安装与环境变量设置,帮助读者快速搭建可用的交叉编译环境。
1.1 工具链简介
arm-2014.05-29 全称为 Sourcery CodeBench Lite for ARM EABI,采用 GCC 4.8.3 编译器,支持 ARM EABI 与 GNU/Linux 两种目标格式。该版本于 2014 年发布,适合配合较老的内核源码(如 Linux 3.x 系列)进行编译。
其主要特点包括:
- 支持 ARMv4T 至 ARMv7-A 架构。
- 内置 GDB 调试器,便于远程调试。
- 提供 glibc 与 uclibc 两种 C 库支持。
- 安装包为自解压格式,无需复杂依赖。
1.2 下载与解压
首先从官方或镜像站点获取安装包,文件名为 arm-2014.05-29-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2。下载完成后,将其放置到 /opt 目录下并执行解压:
bash
cd /opt
sudo tar -xjf arm-2014.05-29-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2
解压完成后,会在 /opt 下生成目录 arm-2014.05,该目录即为工具链的根目录。
1.3 环境变量配置
为了让系统能够识别交叉编译工具,需要将工具链的 bin 目录添加到 PATH 环境变量中。编辑当前用户的环境配置文件:
bash
vim ~/.bashrc
在文件末尾追加以下内容:
bash
export PATH=/opt/arm-2014.05/bin:$PATH
保存退出后,执行以下命令使配置立即生效:
bash
source ~/.bashrc
1.4 验证安装
配置完成后,通过以下命令验证工具链是否正常工作:
bash
arm-none-linux-gnueabi-gcc --version
若输出 GCC 版本信息(如 gcc version 4.8.3),则说明安装成功。此外,还可以查看编译器路径确认环境变量生效:
bash
which arm-none-linux-gnueabi-gcc
1.5 常见问题
在安装和使用过程中,可能会遇到以下问题:
- 32 位库缺失:该工具链为 32 位程序,在 64 位系统上运行需要安装 32 位兼容库,可通过 apt 安装 lib32z1、lib32ncurses5 等。
- 权限问题:解压和编译时建议使用普通用户操作,避免因权限导致文件属性异常。
- 路径冲突:若系统中已存在其他 ARM 工具链,注意 PATH 顺序,确保优先使用本工具链。
2. Qt 5.9.1 源码交叉编译
在完成交叉编译工具链的配置后,接下来需要将 Qt 源码交叉编译为可在 ARM 目标板上运行的库。本章以 qt-everywhere-opensource-src-5.9.1 为例,详细介绍源码获取、解压、qmake.conf 配置修改、编译选项设置、编译安装以及打包移植的完整流程。
2.1 获取Qt源码
Qt 5.9.1 是 Qt 5.9 LTS 系列的一个重要补丁版本,修复了大量稳定性问题,适合嵌入式项目长期使用。获取源码有以下几种途径:
- 官网下载:访问 Qt 官方下载页面,选择 qt-everywhere-opensource-src-5.9.1.tar.xz 进行下载。
- 镜像服务器:国内用户可优先使用清华、中科大等开源镜像站,下载速度更快且稳定。
- 云盘分享:部分嵌入式社区或论坛会提供该版本的云盘备份,下载后注意校验文件完整性。
无论通过哪种方式获取,建议下载后先校验文件校验和,确保源码包完整无损。
2.2 解压源码
将下载好的源码包放置到工作目录,例如 /home/user/qt 下,然后执行解压:
bash
cd /home/user/qt
tar -xvf qt-everywhere-opensource-src-5.9.1.tar.xz
解压完成后,进入源码根目录:
bash
cd qt-everywhere-opensource-src-5.9.1
后续所有配置和编译操作都在该目录下进行。
2.3 修改配置文件
Qt 的交叉编译依赖于 mkspecs 目录下的平台配置文件。针对 ARM 平台,需要修改 qtbase/mkspecs/linux-arm-gnueabi-g++/qmake.conf 文件,使其适配我们使用的 arm-2014.05-29 工具链。
首先打开配置文件:
bash
vi qtbase/mkspecs/linux-arm-gnueabi-g++/qmake.conf
文件中默认定义了编译器名称,需要将其修改为实际使用的交叉编译器。原文件中涉及编译器名称的配置项共有 8 处,全部由 arm-linux-gnueabi-gcc 改为 arm-none-linux-gnueabi-gcc,具体包括:
bash
# 修改前
QMAKE_CC = arm-linux-gnueabi-gcc
QMAKE_CXX = arm-linux-gnueabi-g++
QMAKE_LINK = arm-linux-gnueabi-g++
QMAKE_LINK_SHLIB = arm-linux-gnueabi-g++
QMAKE_AR = arm-linux-gnueabi-ar
QMAKE_OBJCOPY = arm-linux-gnueabi-objcopy
QMAKE_STRIP = arm-linux-gnueabi-strip
QMAKE_RANLIB = arm-linux-gnueabi-ranlib
修改后
QMAKE_CC = arm-none-linux-gnueabi-gcc
QMAKE_CXX = arm-none-linux-gnueabi-g++
QMAKE_LINK = arm-none-linux-gnueabi-g++
QMAKE_LINK_SHLIB = arm-none-linux-gnueabi-g++
QMAKE_AR = arm-none-linux-gnueabi-ar
QMAKE_OBJCOPY = arm-none-linux-gnueabi-objcopy
QMAKE_STRIP = arm-none-linux-gnueabi-strip
QMAKE_RANLIB = arm-none-linux-gnueabi-ranlib
修改完成后保存退出。注意,如果工具链的 bin 目录已正确加入 PATH,则无需填写编译器绝对路径;否则建议填写完整路径以确保能找到编译器。
2.4 ARM指令集支持
为了让编译出的 Qt 库充分发挥 ARM 处理器的性能,需要在 qmake.conf 中追加针对 ARMv7-A 架构的编译优化选项。在配置文件的合适位置添加以下两行:
bash
QMAKE_CFLAGS_RELEASE += -O2 -march=armv7-a
QMAKE_CXXFLAGS_RELEASE += -O2 -march=armv7-a
其中 -O2 表示二级优化,-march=armv7-a 指定目标处理器架构为 ARMv7-A,适用于 Cortex-A8、Cortex-A9 等主流处理器。如果目标板是 Cortex-A7 或 Cortex-A15,同样属于 ARMv7-A 架构,该配置同样适用。
2.5 配置编译选项
在源码根目录下执行 configure 脚本,生成 Makefile 并配置编译选项。以下是一个常用的嵌入式配置示例:
bash
./configure \
-prefix /usr/local/qt5.9.1-arm \
-opensource \
-confirm-license \
-release \
-shared \
-xplatform linux-arm-gnueabi-g++ \
-no-opengl \
-no-cups \
-no-xcb \
-no-gtk \
-no-nis \
-no-accessibility \
-no-sql-sqlite \
-no-sql-mysql \
-no-sql-psql \
-no-sql-odbc \
-no-sql-ibase \
-no-sql-sqlite2 \
-no-sql-tds \
-no-sql-db2 \
-no-sql-oci
下面对上述配置中涉及的主要编译选项逐一进行解释,帮助读者理解每个参数的作用,以便根据实际项目需求灵活调整。
-prefix /usr/local/qt5.9.1-arm:指定 Qt 的安装路径。编译完成后,所有头文件、库文件、可执行程序以及 mkspecs 等都会安装到该目录下。建议使用独立目录,便于后续打包移植和版本管理。
-opensource:选择开源版本许可。Qt 提供开源版(LGPL/GPL)和商业版两种许可,使用开源版时需配合 -confirm-license 确认接受许可协议。
-confirm-license:自动确认并接受许可协议,避免 configure 过程中出现交互式询问,适合脚本化自动化编译场景。
-release:以 Release 模式编译,即启用编译优化并去除调试信息,生成的库体积更小、运行效率更高,适合最终发布到目标板使用。与之对应的是 -debug 模式,用于开发调试阶段。
-shared:编译生成动态链接库(.so 文件),而非静态库(.a 文件)。动态库可显著减小应用程序体积,并支持多个程序共享同一份库,便于后续单独升级 Qt 库。
-xplatform linux-arm-gnueabi-g++:指定交叉编译的目标平台。该参数告诉 configure 使用 qtbase/mkspecs/linux-arm-gnueabi-g++ 目录下的 qmake.conf 配置,从而调用我们前面修改好的 arm-linux-gcc 交叉编译器进行编译。这是整个交叉编译流程中最关键的参数。
-no-opengl:禁用 OpenGL 支持。嵌入式目标板通常没有 GPU 或缺少 OpenGL 驱动,禁用后可以避免编译 OpenGL 相关模块带来的依赖问题,同时减小库体积。
-no-cups:禁用 CUPS 打印系统支持。嵌入式设备一般不需要打印功能,禁用后可以减少不必要的依赖。
-no-xcb:禁用 XCB 平台插件。XCB 是 X11 窗口系统在 Linux 下的接口库,嵌入式设备通常直接运行在 framebuffer 上而不使用 X11,因此需要禁用。
-no-gtk:禁用 GTK 主题集成。Qt 默认可以集成 GTK 主题风格,但在嵌入式环境中没有 GTK 运行环境,禁用后避免编译错误。
-no-nis:禁用 NIS(网络信息服务)支持。NIS 主要用于大型网络环境下的用户认证,嵌入式单机设备不需要该功能。
-no-accessibility:禁用无障碍辅助功能支持。该功能主要用于屏幕阅读器等辅助工具,嵌入式设备通常不需要,禁用后可以减小体积。
-no-sql-sqlite、-no-sql-mysql、-no-sql-psql、-no-sql-odbc、-no-sql-ibase、-no-sql-sqlite2、-no-sql-tds、-no-sql-db2、-no-sql-oci:这一组参数用于禁用各类数据库驱动插件,包括 SQLite、MySQL、PostgreSQL、ODBC、InterBase、SQLite2、TDS、DB2 和 Oracle。嵌入式项目如果不需要数据库功能,全部禁用可以显著减少编译时间和库体积。如果目标应用确实需要某种数据库,则去掉对应的 -no-sql-xxx 参数即可。
配置完成后,执行 make 命令开始编译,编译过程耗时较长,建议使用 make -j4 或 make -j8 利用多核加速。编译完成后执行 make install 将产物安装到 -prefix 指定的目录。
2.6 编译
configure 配置完成后,会在源码根目录下生成 Makefile。接下来执行 make 命令开始编译 Qt 源码,编译过程耗时较长,建议使用多核并行编译以加快速度:
bash
make -j4
如果宿主机 CPU 核心数较多,可以使用 make -j8 或更高并行度。编译过程中会输出大量日志,如果出现错误,可先查看错误信息定位问题,常见错误包括编译器路径未找到、依赖库缺失等,可参考第一章的常见问题部分排查。
编译完成后,可以继续编译 Qt 自带的示例程序,用于后续在目标板上验证 Qt 环境是否正常:
bash
make examples
2.7 安装
编译成功后,执行 make install 将编译产物安装到 configure 时通过 -prefix 指定的目录,即 /usr/local/qt5.9.1-arm:
bash
sudo make install
安装完成后,检查安装目录是否生成了完整的 Qt 运行环境,主要包括以下子目录:
- bin:包含 qmake、moc、uic 等 Qt 开发工具。
- lib:包含 Qt 核心库、插件以及 cmake 配置文件。
- include:包含 Qt 头文件,供交叉编译应用程序时引用。
- mkspecs:包含平台配置文件,即我们前面修改过的 qmake.conf 所在目录。
- plugins:包含平台插件、图像格式插件等运行时组件。
可以通过以下命令确认安装是否成功:
bash
ls /usr/local/qt5.9.1-arm
/usr/local/qt5.9.1-arm/bin/qmake -v
若 qmake 能正常输出版本信息,则说明 Qt 已成功安装到宿主机。
2.8 打包移植
Qt 交叉编译完成后,需要将编译产物移植到 ARM 目标板上运行。由于目标板通常存储空间有限,建议只拷贝运行所需的库和插件,而不是整个安装目录。下面介绍两种常用的移植方式。
方式一:整体拷贝
如果目标板存储空间充足,可以直接将整个安装目录拷贝到目标板。将 /usr/local/qt5.9.1-arm 目录打包后传输到目标板,再解压到相同路径:
bash
# 在宿主机上打包
cd /usr/local
tar -czf qt5.9.1-arm.tar.gz qt5.9.1-arm
将压缩包拷贝到目标板后,在目标板上解压
tar -xzf qt5.9.1-arm.tar.gz -C /usr/local
方式二:精简拷贝
如果目标板存储空间有限,可以只拷贝运行所需的库和插件。首先在宿主机上查看 Qt 库的依赖关系,确定需要哪些动态库:
bash
# 查看 Qt 库依赖的共享库
arm-none-linux-gnueabi-readelf -d /usr/local/qt5.9.1-arm/lib/libQt5Core.so.5 | grep NEEDED
然后根据目标应用实际使用的模块,将对应的 lib 目录下的 .so 文件、plugins 目录下的平台插件(如 libqlinuxfb.so)以及目标板系统所需的依赖库一并拷贝到目标板。拷贝完成后,在目标板上设置环境变量,使 Qt 能找到库和插件:
| 环境变量 | 作用 | 示例值 |
|---|---|---|
| LD_LIBRARY_PATH | 指定 Qt 动态库的搜索路径,使目标板运行时能找到 Qt 的 .so 库文件 | /usr/local/qt5.9.1-arm/lib |
| QT_QPA_PLATFORM | 指定 Qt 使用的平台插件,嵌入式设备通常使用 Linux framebuffer 平台 | linuxfb |
| QT_QPA_FONTDIR | 指定 Qt 的字体目录,避免中文等文字显示为方块 | /usr/share/fonts |
bash
export LD_LIBRARY_PATH=/usr/local/qt5.9.1-arm/lib:$LD_LIBRARY_PATH
export QT_QPA_PLATFORM=linuxfb
export QT_QPA_FONTDIR=/usr/share/fonts
其中 QT_QPA_PLATFORM=linuxfb 指定 Qt 使用 Linux framebuffer 平台插件,适用于无显示服务器的嵌入式设备;QT_QPA_FONTDIR 指定字体目录,避免中文等文字显示为方块。
最后,将交叉编译好的应用程序及其依赖的 Qt 库一起拷贝到目标板,即可运行验证。建议先在目标板上运行 Qt 自带的示例程序(如 ./examples/widgets/analogclock)确认环境正常,再运行自己的应用程序。
3. 编译常见错误与排查
在 Qt 5.9.1 交叉编译过程中,由于工具链、系统环境或配置参数等原因,经常会遇到各类编译错误。本节汇总了几种典型错误,给出错误现象、原因分析及解决步骤,帮助读者快速定位并解决问题。
3.1 qmake.conf 路径错误
错误现象:执行 configure 时提示找不到平台配置文件,例如:
bash
ERROR: Cannot find mkspecs/linux-arm-gnueabi-g++/qmake.conf
Project ERROR: Unknown module(s) in QT: core
原因分析:-xplatform 参数指定的平台名称与 mkspecs 目录下的实际目录名不一致,或者源码解压不完整导致 mkspecs 目录缺失。
解决步骤:
- 确认源码根目录下存在 qtbase/mkspecs/linux-arm-gnueabi-g++ 目录:
bash
ls qtbase/mkspecs/ | grep linux-arm
- 检查 configure 命令中的 -xplatform 参数是否与目录名完全一致,注意大小写和连字符:
bash
./configure -xplatform linux-arm-gnueabi-g++ ...
- 若目录确实缺失,重新解压源码包并校验完整性:
bash
tar -xvf qt-everywhere-opensource-src-5.9.1.tar.xz
3.2 缺少32位库
错误现象:运行 arm-none-linux-gnueabi-gcc 或执行 configure 时提示无法加载共享库,例如:
bash
arm-none-linux-gnueabi-gcc: error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory
原因分析:arm-2014.05-29 工具链是 32 位程序,在 64 位 Linux 系统上运行需要 32 位兼容库支持。
解决步骤:
- 在 Ubuntu/Debian 系统上安装 32 位兼容库:
bash
sudo apt-get update
sudo apt-get install lib32z1 lib32ncurses5 lib32stdc++6
- 安装完成后重新验证工具链是否可运行:
bash
arm-none-linux-gnueabi-gcc --version
- 若仍提示缺少其他库,可使用 ldd 查看具体依赖:
bash
ldd /opt/arm-2014.05/bin/arm-none-linux-gnueabi-gcc
3.3 编译器版本不匹配
错误现象:编译过程中出现大量语法错误或头文件找不到,例如:
bash
error: 'nullptr' was not declared in this scope
error: 'std::unique_ptr' has not been declared
原因分析:Qt 5.9.1 要求编译器支持 C++11 标准,而工具链版本过旧或 qmake.conf 中未正确启用 C++11 支持。
解决步骤:
- 确认工具链版本支持 C++11,arm-2014.05-29 自带的 GCC 4.8.3 已支持:
bash
arm-none-linux-gnueabi-g++ --version
- 在 qmake.conf 中显式添加 C++11 支持标志:
bash
QMAKE_CXXFLAGS += -std=c++11
- 若使用其他版本工具链,建议升级到 GCC 4.8 及以上版本,或改用与 Qt 5.9.1 匹配的交叉编译工具链。
3.4 configure失败
错误现象:执行 configure 时中途退出,提示缺少依赖或配置项错误,例如:
bash
ERROR: Feature 'opengl' was enabled, but the pre-condition 'libs.opengl' failed.
ERROR: The test for linking against libxcb failed.
原因分析:configure 会检测宿主机上的各类开发库,若缺少某些依赖库或配置参数冲突,会导致检测失败。
解决步骤:
- 根据错误提示,在 configure 命令中禁用对应模块,例如:
bash
./configure \
-no-opengl \
-no-xcb \
-no-gtk \
-no-cups \
-no-nis \
-no-accessibility \
-no-sql-sqlite \
-no-sql-mysql \
-no-sql-psql \
-no-sql-odbc \
-no-sql-ibase \
-no-sql-sqlite2 \
-no-sql-tds \
-no-sql-db2 \
-no-sql-oci
- 若提示缺少宿主机开发库,可通过 apt 安装后重新 configure:
bash
sudo apt-get install libx11-dev libxext-dev libxrender-dev libxcb1-dev libxcb-glx0-dev libxcb-util0-dev
- 查看 configure 日志定位具体失败原因:
bash
./configure ... 2>&1 | tee configure.log
grep -i error configure.log
3.5 编译过程中找不到头文件
错误现象:make 编译时提示找不到 Qt 头文件,例如:
bash
fatal error: QWidget: No such file or directory
fatal error: qglobal.h: No such file or directory
原因分析:编译应用程序时未正确设置 Qt 的头文件搜索路径,或 Qt 库尚未安装完成。
解决步骤:
- 确认 Qt 已安装到指定目录,且 include 目录存在:
bash
ls /usr/local/qt5.9.1-arm/include
- 编译应用程序时,使用 qmake 生成 Makefile 并指定正确的交叉编译环境:
bash
/usr/local/qt5.9.1-arm/bin/qmake your_app.pro
make
- 若仍找不到头文件,检查 qmake.conf 中的 QMAKE_INCDIR 是否指向正确的 include 目录。
3.6 链接错误:找不到 Qt 库
错误现象:链接阶段提示找不到 Qt 库文件,例如:
bash
/opt/arm-2014.05/bin/../lib/gcc/arm-none-linux-gnueabi/4.8.3/../../../../arm-none-linux-gnueabi/bin/ld: cannot find -lQt5Core
collect2: error: ld returned 1 exit status
原因分析:链接器未找到 Qt 库文件,可能是库路径未正确设置,或 Qt 库尚未编译安装完成。
解决步骤:
- 确认 Qt 库文件已生成:
bash
ls /usr/local/qt5.9.1-arm/lib/libQt5Core.so*
- 在 qmake 生成的 Makefile 中检查 LIBS 变量是否包含正确的库路径:
bash
grep LIBS Makefile
- 若路径缺失,可在 .pro 文件中手动指定:
bash
LIBS += -L/usr/local/qt5.9.1-arm/lib -lQt5Core -lQt5Gui -lQt5Widgets
3.7 编译速度过慢或内存不足
错误现象:make 编译过程中系统卡顿严重,或提示内存不足:
bash
g++: internal compiler error: Killed (program cc1plus)
make: *** [Makefile:123: xxx.o] Error 1
原因分析:并行编译任务过多导致内存耗尽,或编译单元过大。
解决步骤:
- 降低并行编译的核数,例如从 -j8 改为 -j2:
bash
make -j2
- 关闭其他占用内存较大的程序,释放系统资源。
- 若宿主机内存确实不足,可增加 swap 空间:
bash
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
3.8 常见错误速查表
| 错误现象 | 可能原因 | 解决方向 |
|---|---|---|
| Cannot find mkspecs/linux-arm-gnueabi-g++/qmake.conf | -xplatform 参数与目录名不匹配 | 核对平台名称,重新解压源码 |
| error while loading shared libraries | 缺少 32 位兼容库 | 安装 lib32z1、lib32ncurses5 等 |
| 'nullptr' was not declared in this scope | 编译器不支持 C++11 | 添加 -std=c++11,升级工具链 |
| Feature 'opengl' was enabled, but pre-condition failed | 依赖库缺失或配置冲突 | 禁用对应模块或安装依赖库 |
| fatal error: QWidget: No such file or directory | 头文件搜索路径未设置 | 使用 qmake 生成 Makefile,检查 QMAKE_INCDIR |
| cannot find -lQt5Core | 库路径未设置或库未安装 | 检查 LIBS 变量,确认库文件存在 |
| internal compiler error: Killed | 内存不足 | 降低并行度,增加 swap |
4. 总结
本文围绕 ARM 嵌入式开发中的交叉编译环境搭建与 Qt 5.9.1 源码交叉编译,系统梳理了从工具链配置到应用移植的完整流程。下面从整体流程、关键要点和后续建议三个角度进行总结。
4.1 整体流程回顾
整个交叉编译过程可以划分为三个阶段:
- 工具链准备:下载并解压 arm-2014.05-29 交叉编译工具链,配置 PATH 环境变量并验证安装,为后续编译提供基础。
- Qt 源码编译:获取 qt-everywhere-opensource-src-5.9.1 源码,修改 qmake.conf 中的编译器名称并添加 ARMv7-A 指令集支持,通过 configure 配置编译选项,再执行 make 与 make install 完成编译安装。
- 打包移植:根据目标板存储空间选择整体拷贝或精简拷贝,设置 LD_LIBRARY_PATH、QT_QPA_PLATFORM、QT_QPA_FONTDIR 等环境变量,最后将应用程序与依赖库一并部署到目标板运行验证。
4.2 关键要点
在实际操作中,以下几个要点对成败影响较大:
- 工具链与平台匹配:qmake.conf 中 8 处编译器名称必须全部由 arm-linux-gnueabi-gcc 改为 arm-linux-gcc,且 -xplatform 参数要与 mkspecs 目录名完全一致。
- 架构优化:在 qmake.conf 中追加 -O2 -march=armv7-a 编译选项,可让生成的 Qt 库充分发挥 ARMv7-A 处理器性能。
- 裁剪编译选项:嵌入式场景下通过 -no-opengl、-no-xcb、-no-sql-xxx 等参数禁用不需要的模块,可显著缩短编译时间并减小库体积。
- 环境变量配置:目标板运行时需正确设置动态库搜索路径、平台插件和字体目录,否则程序无法启动或中文显示异常。
4.3 后续建议
完成本文流程后,建议读者从以下方向继续深入:
- 在目标板上运行 Qt 自带示例程序(如 analogclock)验证环境,再逐步移植自己的业务应用。
- 结合具体项目需求,按需调整 configure 参数,例如启用需要的数据库驱动或图形模块。
- 若遇到编译问题,可对照第三章的常见错误速查表快速定位,并结合 configure.log 日志深入排查。
通过以上步骤,即可在 ARM 嵌入式平台上搭建起完整的 Qt 运行环境,为后续应用开发与部署打下坚实基础。