基于imx6ull的qt开发——mqtt交叉编译与部署实战
1. 环境准备与工具链配置
在开始MQTT库的交叉编译之前,我们需要先搭建好开发环境。我使用的是Ubuntu 18.04系统,这个版本比较稳定,与imx6ull的开发工具链兼容性也很好。如果你用的是其他版本的Ubuntu,可能需要注意一些依赖库的版本差异。
首先安装一些基础开发工具:
sudo apt update
sudo apt install build-essential git make cmake
接下来配置交叉编译工具链。imx6ull使用的是ARM Cortex-A7架构,我们需要安装对应的交叉编译器。正点原子提供的工具链是基于poky的,可以直接从官方获取:
# 创建工具链目录
sudo mkdir -p /opt/fsl-imx-x11
cd /opt/fsl-imx-x11
# 下载工具链(具体版本号请根据实际情况调整)
wget https://www.nxp.com/lgfiles/sdk/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
设置环境变量很重要,每次打开新的终端都需要执行:
source /opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
验证工具链是否配置成功:
arm-poky-linux-gnueabi-gcc --version
如果看到正确的版本信息,说明工具链已经就绪。我在第一次配置时遇到过环境变量没生效的问题,后来发现是因为source命令只在当前终端有效,所以每次开新终端都要重新执行。
2. Qt MQTT库源码获取与准备
Qt从5.10版本开始将MQTT模块移到了官方扩展库中,我们需要从GitHub获取源码。这里有个坑要注意:必须选择与你的Qt版本匹配的MQTT库版本。我用的Qt5.12.9,所以就选择对应的5.12.9版本的MQTT库。
# 创建工作目录
mkdir -p ~/imx6ull_qt_mqtt
cd ~/imx6ull_qt_mqtt
# 下载Qt MQTT源码
wget https://github.com/qt/qtmqtt/archive/refs/tags/v5.12.9.tar.gz
tar -xzf v5.12.9.tar.gz
cd qtmqtt-5.12.9
解压后的目录结构是这样的:
qtmqtt-5.12.9/
├── src/
│ └── mqtt/
│ ├── *.h 头文件
│ └── *.cpp 源文件
├── examples/ 示例代码
└── tests/ 测试代码
在开始编译前,还需要检查一下依赖。MQTT模块需要QtNetwork的支持,确保你的Qt版本包含了这个模块。可以用以下命令检查:
qmake -query | grep QT_INSTALL_LIBS
这会显示Qt库的安装路径,进去看看有没有libQt5Network.so文件。如果没有,可能需要重新安装Qt并包含Network模块。
3. 交叉编译Qt MQTT库
现在开始实际的交叉编译过程。首先需要设置交叉编译的环境变量,这是最关键的一步:
source /opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
验证qmake版本是否正确:
qmake -v
应该看到使用的是arm-poky-linux-gnueabi版本的qmake,而不是x86_64版本。
创建编译目录并配置:
mkdir build-arm
cd build-arm
../configure -prefix /opt/qtmqtt-5.12.9-arm \
-opensource \
-confirm-license \
-nomake examples \
-nomake tests
这里有几个重要参数:
-prefix指定安装目录,我习惯放在/opt下方便管理-nomake examples和-nomake tests可以跳过示例和测试编译,加快速度
开始编译:
make -j4
sudo make install
编译过程大概需要10-20分钟,取决于你的电脑性能。我在第一次编译时遇到了一个常见错误:找不到-lts库。这是因为tslib没正确配置,解决方法是指定tslib的路径:
export TS_LIBRARY=/usr/local/tslib/lib
export TS_INCLUDE=/usr/local/tslib/include
编译完成后,检查生成的库文件:
file /opt/qtmqtt-5.12.9-arm/lib/libQt5Mqtt.so.5.12.9
应该显示为ARM架构的共享库。如果显示x86_64,说明环境变量没设置对,需要重新检查。
4. 开发板环境部署与测试
编译好的库需要部署到开发板上。我通常用nfs共享的方式,这样调试起来比较方便。首先在开发板上配置nfs挂载:
# 在开发板上执行
mkdir /mnt/nfs
mount -t nfs 192.168.1.100:/home/share /mnt/nfs -o nolock
将编译好的库文件拷贝到nfs共享目录:
sudo cp -r /opt/qtmqtt-5.12.9-arm /home/share/
在开发板上设置库路径:
export LD_LIBRARY_PATH=/mnt/nfs/qtmqtt-5.12.9-arm/lib:$LD_LIBRARY_PATH
创建一个简单的测试程序验证MQTT库是否能正常工作:
// mqtt_test.cpp
#include <QtMqtt/QMqttClient>
#include <QCoreApplication>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMqttClient client;
client.setHostname("test.mosquitto.org");
client.setPort(1883);
QObject::connect(&client, &QMqttClient::connected, []() {
qDebug() << "Connected to MQTT broker!";
});
client.connectToHost();
return a.exec();
}
交叉编译测试程序:
arm-poky-linux-gnueabi-g++ -o mqtt_test mqtt_test.cpp \
-I/opt/qtmqtt-5.12.9-arm/include \
-L/opt/qtmqtt-5.12.9-arm/lib \
-lQt5Mqtt -lQt5Network -lQt5Core
将生成的可执行文件拷贝到开发板运行:
./mqtt_test
如果看到"Connected to MQTT broker!"的输出,说明库移植成功了。
5. Qt Creator项目配置
现在我们来配置Qt Creator,让它可以交叉编译使用MQTT的项目。首先打开Qt Creator,进入Tools -> Options -> Kits。
添加新的Qt版本:
- Name: Qt 5.12.9 ARM
- Path: /opt/qtmqtt-5.12.9-arm/bin/qmake
添加新的编译器:
- Name: ARM Poky GCC
- Path: /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-gcc
创建新的Kit:
- Name: imx6ull Kit
- Device: Generic Linux Device
- Sysroot: /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/cortexa7hf-neon-poky-linux-gnueabi
- Compiler: ARM Poky GCC
- Qt version: Qt 5.12.9 ARM
在项目配置文件(.pro)中添加MQTT支持:
QT += mqtt network
INCLUDEPATH += /opt/qtmqtt-5.12.9-arm/include
LIBS += -L/opt/qtmqtt-5.12.9-arm/lib -lQt5Mqtt
# 交叉编译设置
contains(QT_ARCH, arm) {
target.path = /home/root
INSTALLS += target
}
配置完成后,在Qt Creator中选择imx6ull Kit,点击编译。如果一切正常,应该能成功生成ARM版本的可执行文件。
6. 常见问题与解决方案
在移植过程中我遇到过不少问题,这里分享几个典型的:
问题1:编译时报错找不到mqtt头文件
fatal error: QtMqtt/QMqttClient: No such file or directory
解决方案:确保在.pro文件中正确设置了INCLUDEPATH,并且安装了对应版本的Qt MQTT库。
问题2:运行时提示找不到libQt5Mqtt.so
error while loading shared libraries: libQt5Mqtt.so.5: cannot open shared object file
解决方案:将编译好的库文件拷贝到开发板的/usr/lib目录下,或者设置LD_LIBRARY_PATH环境变量。
问题3:MQTT连接失败
QMqttConnection::SocketError: Connection refused
解决方案:检查网络连接,确认MQTT broker地址和端口正确,开发板防火墙设置允许出站连接。
问题4:性能问题 如果发现MQTT通信速度慢,可以调整QoS等级和keepalive时间:
client.setQualityOfService(1);
client.setKeepAlive(60);
调试技巧:可以在Qt Creator中启用远程调试,这样可以在开发板上直接调试程序。需要在开发板上安装gdbserver:
gdbserver :1234 ./your_program
然后在Qt Creator中配置远程调试,连接开发板IP和端口1234。
7. 实际项目应用示例
现在我们来做一个完整的温度监控示例,这个例子综合使用了MQTT的发布和订阅功能。
首先创建发布者程序,定时发布温度数据:
// publisher.cpp
#include <QtMqtt/QMqttClient>
#include <QCoreApplication>
#include <QTimer>
#include <QRandomGenerator>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMqttClient publisher;
publisher.setHostname("broker.hivemq.com");
publisher.setPort(1883);
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, [&publisher]() {
double temperature = 20 + QRandomGenerator::global()->generateDouble() * 10;
QString message = QString("Temperature: %1 C").arg(temperature, 0, 'f', 1);
publisher.publish(QMqttTopicName("imx6ull/temperature"), message.toUtf8());
qDebug() << "Published:" << message;
});
QObject::connect(&publisher, &QMqttClient::connected, [&timer]() {
qDebug() << "Publisher connected";
timer.start(5000); // 每5秒发布一次
});
publisher.connectToHost();
return a.exec();
}
再创建订阅者程序,接收温度数据:
// subscriber.cpp
#include <QtMqtt/QMqttClient>
#include <QtMqtt/QMqttSubscription>
#include <QCoreApplication>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMqttClient subscriber;
subscriber.setHostname("broker.hivemq.com");
subscriber.setPort(1883);
QObject::connect(&subscriber, &QMqttClient::connected, [&subscriber]() {
qDebug() << "Subscriber connected";
auto subscription = subscriber.subscribe(QMqttTopicFilter("imx6ull/temperature"));
QObject::connect(subscription, &QMqttSubscription::messageReceived, [](QMqttMessage msg) {
qDebug() << "Received:" << msg.payload();
});
});
subscriber.connectToHost();
return a.exec();
}
编译这两个程序并部署到开发板上运行。你可以看到发布者每5秒发送一次温度数据,订阅者实时接收并显示。这个例子展示了MQTT在物联网设备中的典型应用场景。
在实际项目中,你可能还需要处理网络断开重连、消息持久化、安全认证等问题。Qt MQTT模块提供了相应的接口,可以根据具体需求进行配置。
记得在实际部署时使用安全的MQTT连接(MQTT over SSL/TLS),特别是在生产环境中。Qt同样支持SSL/TLS,只需要在代码中启用即可:
client.setTransportType(QMqttClient::SecureTransport);
QSslConfiguration sslConfig;
// 配置SSL证书等
client.setSslConfiguration(sslConfig);
更多推荐


所有评论(0)