☰
Qt MySQL驱动编译与加载全指南:解决QMYSQL driver not loaded
2026/10/3 1:02:48 网站建设 项目流程

简介:本资源是一份面向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经moc(Meta-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 'QSqlResult',debug 半天才发现是 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.so
  • make -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 += c++11 # 第二行:MySQL 驱动源码使用 C++11 特性(如 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 += sql,qmake 可能漏掉libQt5Core.so链接,导致undefined reference to 'QObject::QObject(QObject*)'。显式加上core是防御性写法。
  • CONFIG += c++11是隐藏雷区:
    Qt 5.12+ 的 MySQL 驱动源码中大量使用auto推导和范围 for 循环。若.pro中未声明c++11,gcc 默认用 C++98 编译,报error: 'auto' changes meaning in C++11。此错误常被误判为驱动源码问题,实则是项目配置缺失。
  • 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); // ... 其余代码 }
  • addLibraryPathvsaddPluginPath:
    Qt 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 libmysqlclient18(Ubuntu 18.04)或libmysqlclient21(22.04),确保系统有对应版本的libmysqlclient_r.so。
    • 方案 B:export 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 trace=openat -f -o strace.log ./myproject 2>&1 | 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,都强制走一遍ldd+objdump+qtdiag三连检,再运行程序。省下的 debug 时间,够我喝三杯咖啡。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询