ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Qt MySQL驱动编译与加载全指南:解决QMYSQL driver not loaded

Qt MySQL驱动编译与加载全指南:解决QMYSQL driver not loaded 简介本资源是一份面向Linux平台Qt开发者的MySQL数据库连接实践指南适用于具备C和Qt基础、正开展数据库集成项目的中初级开发者。文档详细梳理了在Ubuntu等Linux发行版中编译Qt MySQL驱动libqsqlmysql.so的完整流程涵盖依赖安装、源码编译、插件部署及项目配置并提供可直接复用的Qt SQL连接代码与.pro文件配置示例覆盖主机设置、认证、查询执行与结果输出等核心环节。资源为单个Word文档.doc格式大小142KB内容结构清晰含环境说明如Ubuntu 10.10 Qt Creator、权限处理提示、驱动路径配置要点及控制台调试输出实录便于快速定位常见编译失败与连接异常问题。目前已有635人学习下载是Linux下Qt数据库开发入门与排错的实用参考材料。1. Linux 下 QT 连接 MySQL不是加个QT sql就能跑通的黑匣子你刚在 Qt Creator 里敲完QSqlDatabase::addDatabase(QMYSQL)编译通过、运行一闪而过——然后控制台只吐出一句QSqlDatabase: QMYSQL driver not loaded。别急着重装 Qt 或怀疑 MySQL 没装好这根本不是“连不上数据库”的问题而是Qt 根本没加载到 MySQL 驱动模块。这篇文档讲的就是 Ubuntu 系统下尤其老版本如 10.10但原理完全适用于 18.04/20.04/22.04如何从零手编libqsqlmysql.so并让它稳稳躺在 Qt 插件路径里被识别。它不依赖qt5-default的模糊包管理不靠apt install qt5sql5-mysql这种可能和你的 Qt 安装目录错位的“捷径”而是直击 Qt 插件机制底层驱动源码在哪、头文件和库路径怎么硬指定、.so文件生成后放哪、权限怎么设、.pro里哪些行是救命稻草、哪些是画蛇添足。适合正在调试嵌入式 Qt 项目X11/X86/ARM 多环境共存、或用自编译 Qt非系统包管理安装的 C 工程师——你不是在学 SQL 语法是在打通 Qt 应用层和数据库中间件之间的最后一道 ABI 壁垒。2. 驱动编译全流程从源码目录到libqsqlmysql.so的七步实操Qt 的 SQL 驱动不是开箱即用的二进制而是需要你用当前 Qt 构建环境qmake make重新编译的插件模块。关键在于驱动必须和你最终运行程序所用的 Qt 版本、ABI、架构32/64bit、甚至编译器gcc 版本严格一致。否则就会出现fatal: cannot mix incompatible qt library这类玄学报错。下面每一步都对应一个真实翻车点代码块后附参数逻辑说明。2.1 定位 Qt 源码中的 MySQL 驱动目录提示此步骤必须用你实际用于构建项目的 Qt 安装目录不是系统默认/usr/include/qt5。如果你用的是 Qt Online Installer 安装的 5.15.2路径类似/opt/Qt5.15.2/5.15.2/gcc_64/src/plugins/sqldrivers/mysql如果是源码编译安装路径为$QTDIR/src/plugins/sqldrivers/mysql。cdQTDIR在原文中是占位符必须替换成你的真实路径。# 假设你的 Qt 安装在 /opt/Qt5.15.2/5.15.2/gcc_64 cd /opt/Qt5.15.2/5.15.2/gcc_64/src/plugins/sqldrivers/mysql ls -l # 正常应看到 main.cpp, moc_qsql_mysql.cpp, qsql_mysql.cpp, qsql_mysql.h 等为什么必须进这个目录Qt 的qmake工具链会根据当前目录下的.cpp/.h文件自动生成Makefile并调用moc处理元对象。若你在别处新建空目录再复制文件qmake-project无法正确识别 Qt SQL 模块依赖导致#include QSqlDriver找不到。moc_qsql_mysql.cpp是什么它是qsql_mysql.h经mocMeta-Object Compiler预处理生成的封装了 Qt 的信号槽、属性系统与 MySQL C API 的胶水代码。没有它驱动无法注册到QSqlDatabase::drivers()列表中。2.2 生成mysql.pro工程文件并修正路径参数# 在 mysql 目录下执行 qmake -project # 若提示 Permission denied先赋权常见于源码解压后 chmod x ./qmake # 生成后编辑 mysql.pro确保包含以下三行原文中 qmake 命令参数已过时必须用现代写法# mysql.pro —— 必须手动编辑不能只靠 qmake -project 自动生成 TEMPLATE lib TARGET qsqlmysql INCLUDEPATH /usr/include/mysql LIBS -L/usr/lib/x86_64-linux-gnu -lmysqlclient_r # 注意Ubuntu 18.04 默认库路径是 /usr/lib/x86_64-linux-gnu不是 /usr/lib/mysql # 若你的 MySQL 是 apt 安装用 dpkg -L libmysqlclient-dev 查真实路径 DESTDIR $$[QT_INSTALL_PLUGINS]/sqldrivers # 此行决定 make install 后 .so 放哪必须和你的 Qt 安装路径匹配INCLUDEPATH /usr/include/mysql解析告诉编译器去哪找mysql.h,mysqld_error.h等头文件。libmysqlclient-dev包安装后这些文件固定在/usr/include/mysql无需修改。LIBS -L/usr/lib/x86_64-linux-gnu -lmysqlclient_r解析-L指定链接器搜索库的目录-lmysqlclient_r表示链接libmysqlclient_r.so线程安全版。注意r后缀Qt 官方驱动要求线程安全客户端库libmysqlclient.so无_r会导致运行时undefined symbol: mysql_init错误。DESTDIR $$[QT_INSTALL_PLUGINS]/sqldrivers解析$$[QT_INSTALL_PLUGINS]是 qmake 内置变量值为qmake -query QT_INSTALL_PLUGINS输出路径如/opt/Qt5.15.2/5.15.2/gcc_64/plugins。这是 Qt 运行时查找驱动的唯一标准路径硬编码成/usr/lib/qt5/plugins/sqldrivers是典型错误。2.3 执行 qmake 并检查生成的 Makefile# 使用你项目所用的 qmake不是系统 /usr/bin/qmake /opt/Qt5.15.2/5.15.2/gcc_64/bin/qmake mysql.pro # 检查生成的 Makefile 是否包含正确路径 grep INCLUDEPATH Makefile | head -n 3 grep LIBS Makefile | head -n 2 # 应看到类似INCPATH -I. -I/usr/include/mysql -I/opt/Qt5.15.2/5.15.2/gcc_64/include/... # 和LIBS $(SUBLIBS) -L/usr/lib/x86_64-linux-gnu -lmysqlclient_r ...为什么必须用目标 Qt 的 qmake不同 Qt 版本的qmake生成的 Makefile 规则不同如 Qt 5.9 用$(CC)Qt 5.15 用$(CXX)且内置变量$$[QT_INSTALL_PLUGINS]值由该 qmake 所属 Qt 决定。混用会导致make install把.so装到错误目录。grep检查是血泪经验曾有同事因qmake路径写错Makefile 中INCPATH仍指向旧 Qt 的 include编译时qsql_mysql.h里的QSqlResult定义与当前 Qt 不兼容报incomplete type QSqlResultdebug 半天才发现是 qmake 版本错。2.4 编译与安装驱动模块# 编译静默模式避免刷屏 make -s # 检查是否生成 libqsqlmysql.so注意前缀是 lib不是 qsqlmysql ls -lh libqsqlmysql.so # 安装到 Qt 插件目录需 sudo因 plugins 目录通常属 root sudo make install # 验证安装位置 ls -lh /opt/Qt5.15.2/5.15.2/gcc_64/plugins/sqldrivers/libqsqlmysql.somake -s的意义驱动编译输出极长含大量 moc 生成代码-s只显示错误加快定位。若失败去掉-s看完整日志。sudo make install的必要性DESTDIR指向的目录权限通常是drwxr-xr-x root root普通用户无法写入。跳过sudo会导致make install报Permission denied但make本身成功容易误以为编译完成。验证.so文件存在是最后防线很多人make install后不检查结果运行时 Qt 仍报driver not loaded因为.so根本没落盘。2.5 验证驱动是否被 Qt 识别命令行级# 在任意目录执行不依赖你的项目 /opt/Qt5.15.2/5.15.2/gcc_64/bin/qtdiag | grep -A 5 SQL Drivers # 或更直接 /opt/Qt5.15.2/5.15.2/gcc_64/bin/qtdiag | grep QMYSQL # 正常输出应含QMYSQL: libqsqlmysql.so (default) # 若无输出说明驱动未被识别重点检查上一步的安装路径和文件权限qtdiag是 Qt 自带诊断工具它读取QT_PLUGIN_PATH环境变量和$$[QT_INSTALL_PLUGINS]路径列出所有已加载插件。比写测试程序更快定位驱动层问题。为什么不用QSqlDatabase::drivers()测试因为QSqlDatabase::drivers()是运行时 API需先#include QtSql并链接libQt5Sql.so而qtdiag是 Qt 自身二进制绕过所有项目配置直击 Qt 插件加载引擎。3. 项目工程配置.pro文件的四行生死线与运行时路径陷阱驱动编译成功只是第一步。你的 Qt 项目.pro文件若配置不当即使libqsqlmysql.so已在插件目录程序启动时仍会找不到驱动。核心矛盾在于编译期链接linking和运行时加载loading是两套独立机制。下面四行.pro配置缺一不可且顺序和写法有严格要求。3.1.pro文件必须包含的四行配置# myproject.pro —— 这是能跑通的最小可行配置 QT core sql # 第一行声明依赖 sql 模块core 是隐式依赖显式写出更安全 CONFIG c11 # 第二行MySQL 驱动源码使用 C11 特性如 auto, lambda必须开启 LIBS -L/usr/lib/x86_64-linux-gnu -lmysqlclient_r # 第三行链接 MySQL 客户端库编译期 INCLUDEPATH /usr/include/mysql # 第四行包含 MySQL 头文件编译期 # 注意不要写 QTPLUGIN qsqlmysql —— 这是 Qt 4 语法Qt 5 已废弃QT core sql的深层含义core是sql的依赖模块QSqlDatabase继承自QObject若只写QT sqlqmake 可能漏掉libQt5Core.so链接导致undefined reference to QObject::QObject(QObject*)。显式加上core是防御性写法。CONFIG c11是隐藏雷区Qt 5.12 的 MySQL 驱动源码中大量使用auto推导和范围 for 循环。若.pro中未声明c11gcc 默认用 C98 编译报error: auto changes meaning in C11。此错误常被误判为驱动源码问题实则是项目配置缺失。LIBS和INCLUDEPATH的作用域它们只影响你的项目源码编译如main.cpp中调用QSqlDatabase::addDatabase不影响libqsqlmysql.so的编译。驱动模块是独立编译的其LIBS在mysql.pro中定义。3.2 运行时插件路径的三种设置方式按优先级排序Qt 查找插件的顺序是QT_PLUGIN_PATH环境变量 QApplication构造时传入的pluginPath$$[QT_INSTALL_PLUGINS]。你的程序若仍报QMYSQL driver not loaded大概率是运行时路径没对上。方式一环境变量开发调试首选# 启动程序前设置Bash export QT_PLUGIN_PATH/opt/Qt5.15.2/5.15.2/gcc_64/plugins ./myproject # 验证是否生效 echo $QT_PLUGIN_PATH为什么开发时首选环境变量无需修改代码可快速切换不同 Qt 版本的插件路径。qmake生成的 Makefile 中QT_PLUGIN_PATH不会被硬编码所以make run无效必须手动export。方式二代码中硬编码发布部署用// main.cpp 开头QApplication 构造前 #include QApplication #include QDir int main(int argc, char *argv[]) { // 强制指定插件路径绝对路径 QApplication::addLibraryPath(/opt/Qt5.15.2/5.15.2/gcc_64/plugins); QApplication a(argc, argv); // ... 其余代码 }addLibraryPathvsaddPluginPathQt 5.14 推荐用addLibraryPath它同时搜索plugins/子目录。addPluginPath是旧 API部分 Qt 版本已弃用。必须用绝对路径相对路径如./plugins会以可执行文件所在目录为基准而发布时可执行文件可能被移到/usr/bin路径失效。方式三打包时复制插件最稳妥的发布方案# 构建完成后将插件复制到可执行文件同级的 plugins/sqldrivers 目录 mkdir -p ./deploy/plugins/sqldrivers cp /opt/Qt5.15.2/5.15.2/gcc_64/plugins/sqldrivers/libqsqlmysql.so ./deploy/plugins/sqldrivers/ # 运行时 Qt 会自动搜索 ./deploy/plugins ./deploy/myproject此方案为何最稳妥它不依赖系统环境变量或用户 Qt 安装所有依赖打包进一个目录。linuxdeployqt工具正是基于此原理自动复制插件。3.3 数据库连接代码的健壮写法防崩溃、带日志原文中的main.cpp示例过于简陋缺少错误上下文和资源释放。以下是生产环境推荐写法#include QtSql #include QMessageBox #include QTextStream #include QDebug int main(int argc, char *argv[]) { QTextStream out(stdout); QApplication a(argc, argv); // 1. 检查驱动是否可用运行时验证 QStringList drivers QSqlDatabase::drivers(); out Available SQL drivers: drivers endl; if (!drivers.contains(QMYSQL)) { qCritical() QMYSQL driver is NOT loaded! Check plugin path and libqsqlmysql.so.; return -1; } // 2. 创建并配置数据库连接 QSqlDatabase db QSqlDatabase::addDatabase(QMYSQL); db.setHostName(localhost); // 若 MySQL 在 Docker 中改用容器 IP db.setDatabaseName(test); db.setUserName(root); db.setPassword(your_password); // 生产环境务必用配置文件或环境变量 db.setPort(3306); // 显式指定端口避免默认 0 导致连接失败 // 3. 尝试连接并捕获详细错误 if (!db.open()) { QString error QString(Cannot connect to database:\n%1\nError code: %2) .arg(db.lastError().text()) .arg(db.lastError().number()); qCritical() error; QMessageBox::critical(nullptr, Database Error, error); return -1; } qDebug() Connected to MySQL successfully!; // 4. 执行查询带异常防护 QSqlQuery query(db); // 关联到 db 实例避免全局连接冲突 if (!query.exec(SELECT * FROM t_homedata)) { qWarning() Query failed: query.lastError().text(); } else { while (query.next()) { QString id query.value(0).toString(); QString type query.value(1).toString(); QString data query.value(2).toString(); out id , type , data endl; } } // 5. 显式关闭连接虽 Qt 会自动清理但显式调用更清晰 db.close(); return a.exec(); }QSqlQuery query(db)的意义将QSqlQuery绑定到特定QSqlDatabase实例避免多连接时查询错乱。若只写QSqlQuery query;它会使用默认连接QSqlDatabase::database()在复杂项目中易出错。db.setPort(3306)的必要性QSqlDatabase默认端口为0表示“让 MySQL 客户端库自己决定”。但某些 MySQL 配置如skip-networking下0会被解释为 Unix socket而非 TCP导致连接 localhost 失败。显式设3306强制走 TCP。4. 避坑指南五个高频翻车现场与秒级排查法这些坑我全踩过有些 debug 了三天最后发现是chmod权限或路径少了个/。以下按现象 → 原因 → 解决的结构整理每条都能直接复现、直接验证。4.1 现象QSqlDatabase: QMYSQL driver not loaded但qtdiag显示QMYSQL: libqsqlmysql.so原因libqsqlmysql.so文件权限为600仅属主可读Qt 运行时以普通用户身份加载无读取权限。排查ls -l /opt/Qt5.15.2/5.15.2/gcc_64/plugins/sqldrivers/libqsqlmysql.so若显示-rw-------即中招。解决sudo chmod 644 /opt/Qt5.15.2/5.15.2/gcc_64/plugins/sqldrivers/libqsqlmysql.so。注意不是755.so文件无需执行权限。4.2 现象编译mysql.pro时报mysql.h: No such file or directory原因libmysqlclient-dev未安装或安装了但头文件不在/usr/include/mysql。Ubuntu 22.04 的libmysqlclient-dev包头文件路径为/usr/include/mysql但某些 MariaDB 替代包路径不同。排查dpkg -L libmysqlclient-dev | grep mysql.h确认头文件真实路径。解决修改mysql.pro中INCLUDEPATH为真实路径如INCLUDEPATH /usr/include/mariadb。4.3 现象make时报undefined reference to mysql_init或mysql_real_connect原因链接的 MySQL 库是libmysqlclient.so非线程安全版但 Qt 驱动源码强制调用_r后缀函数。排查ldd libqsqlmysql.so | grep mysql若显示libmysqlclient.so /usr/lib/x86_64-linux-gnu/libmysqlclient.so无_r即错误。解决确认libmysqlclient-dev包安装后/usr/lib/x86_64-linux-gnu/下存在libmysqlclient_r.so。若不存在安装libmysqlclient-dev的线程安全版本Ubuntu 通常自带或在mysql.pro中改用LIBS -lmysqlclient不推荐有线程安全风险。4.4 现象程序运行时报QSqlDatabase: QMYSQL driver not loaded且qtdiag也不显示QMYSQL原因libqsqlmysql.so依赖的libmysqlclient_r.so在运行时找不到ldd检查显示not found。排查ldd /opt/Qt5.15.2/5.15.2/gcc_64/plugins/sqldrivers/libqsqlmysql.so | grep mysql若第二列为not found即动态链接失败。解决方案 A推荐sudo apt install libmysqlclient18Ubuntu 18.04或libmysqlclient2122.04确保系统有对应版本的libmysqlclient_r.so。方案 Bexport LD_LIBRARY_PATH/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH临时添加路径。4.5 现象Qt Creator 中编译通过但终端运行./myproject报QMYSQL driver not loaded原因Qt Creator 的构建环境Kit设置了QT_PLUGIN_PATH但终端 shell 未设置导致运行时路径丢失。排查在 Qt Creator 的 “Projects” → “Build Run” → “Run” 设置中查看 “Run Environment” 是否有QT_PLUGIN_PATH。再在终端执行echo $QT_PLUGIN_PATH对比是否一致。解决临时在终端运行前export QT_PLUGIN_PATH...。永久在~/.bashrc中添加export QT_PLUGIN_PATH/opt/Qt5.15.2/5.15.2/gcc_64/plugins然后source ~/.bashrc。5. 进阶技巧用ldd和objdump定位驱动加载失败的终极方法当所有常规方法失效qtdiag也沉默时你需要祭出 Linux 二进制分析神器。这不是炫技而是工程师在 deadline 前的后悔药。5.1 用ldd检查libqsqlmysql.so的完整依赖树# 检查驱动自身依赖关键 ldd /opt/Qt5.15.2/5.15.2/gcc_64/plugins/sqldrivers/libqsqlmysql.so # 输出示例 # linux-vdso.so.1 (0x00007fff...) # libmysqlclient_r.so.16 /usr/lib/x86_64-linux-gnu/libmysqlclient_r.so.16 (0x00007f...) # libQt5Sql.so.5 /opt/Qt5.15.2/5.15.2/gcc_64/lib/libQt5Sql.so.5 (0x00007f...) # libQt5Core.so.5 /opt/Qt5.15.2/5.15.2/gcc_64/lib/libQt5Core.so.5 (0x00007f...) # libc.so.6 /lib/x86_64-linux-gnu/libc.so.6 (0x00007f...)看什么每一行后的路径是否真实存在。若某行显示not found如libmysqlclient_r.so.16 not found说明该库缺失或版本不匹配。怎么办若libmysqlclient_r.so.x缺失sudo apt install libmysqlclient-dev并确认版本apt list --installed | grep mysql。若路径存在但 Qt 库libQt5Sql.so.5显示not found说明你的LD_LIBRARY_PATH未包含 Qt 的lib/目录export LD_LIBRARY_PATH/opt/Qt5.15.2/5.15.2/gcc_64/lib:$LD_LIBRARY_PATH。5.2 用objdump检查驱动是否导出了 Qt 插件必需符号Qt 插件必须导出qt_plugin_query_verification_data符号否则被判定为非法插件。objdump可直接查看# 检查符号表-T 显示动态符号-C 解析 C 名字 objdump -TC /opt/Qt5.15.2/5.15.2/gcc_64/plugins/sqldrivers/libqsqlmysql.so | grep qt_plugin # 正常应输出 # 00000000000012a0 g F .text 000000000000004a Qt_5.15.2::qt_plugin_query_verification_data # 00000000000012f0 g F .text 000000000000004a Qt_5.15.2::qt_static_plugin_qsqlmysql()若无输出驱动编译失败未生成 Qt 插件入口。检查mysql.pro中TEMPLATE lib是否写错如写成app或qmake是否用了错误版本导致qmake未识别插件模板。若输出符号名含Qt_5.9.9但你的 Qt 是5.15.2说明qmake版本错用的是旧 Qt 的qmake导致生成的符号与当前 Qt ABI 不兼容。qmake -v确认版本换用目标 Qt 的qmake。5.3 用strace追踪 Qt 运行时加载插件的完整路径当QT_PLUGIN_PATH设置正确libqsqlmysql.so权限正常ldd无not found但 Qt 仍不加载时strace是终极武器# 追踪 openat 系统调用Qt 加载插件时会尝试打开多个路径 strace -e traceopenat -f -o strace.log ./myproject 21 | grep sqldrivers # 查看 strace.log搜索 libqsqlmysql.so # 正常应看到类似 # [pid 12345] openat(AT_FDCWD, /opt/Qt5.15.2/5.15.2/gcc_64/plugins/sqldrivers/libqsqlmysql.so, O_RDONLY|O_CLOEXEC) 3 # 若看到 No such file or directory说明 Qt 尝试的路径和你认为的不一致。strace的价值它不依赖 Qt 日志直接展示内核层面的文件访问行为。曾用此法发现 Qt 5.15.2 在某些环境下会优先搜索QT_PLUGIN_PATH/plugins/sqldrivers多了一层plugins/而非常规的QT_PLUGIN_PATH/sqldrivers根源是qmake配置中DESTDIR的路径拼接逻辑。从那以后我每次编译完libqsqlmysql.so都强制走一遍lddobjdumpqtdiag三连检再运行程序。省下的 debug 时间够我喝三杯咖啡。希望帮到你。本文还有配套的精品资源点击获取
返回列表