QT调用动态库,在编译时和运行时的方式不同,编译时可在pro文件加载或使用QLibrary类加载;运行时依赖环境变量,windows下直接把动态库拷贝到可执行文件目录即可,linux需要配置固定路径或相对路径搜索动态库(ps:windows程序默认在可执行文件所在路径搜索动态库,linux则不会)。

<>编译时加载:pro工程文件加载动态库so

INCLUDEPATH += 库的头文件路径
LIBS += -L PATH
-lLIB,PATH是so库所在路径,LIB是库的名字(-L是库路径,-l是库名字,例如库文件是libReceiptPrint.so,后面应添加-lReceiptPrint)
collect2:ld returned 1 exit
status解决方案:没有正确加载库,检测库路径,32位还是64位,库是debug版还是release版,定义了槽函数没有实现,定义了构造函数和析构函数没有实现。
INCLUDEPATH += /home/chw/HSCompany/HardWareTest/source/HardWareTest/
HardWareTest/sores CONFIG(debug,debug|release){ LIBS += -L /home/chw/HSCompany/
HardWareTest/source/HardWareTest/build-HardWareTest-Desktop_Qt_5_10_1_GCC_64bit-
Debug/bin/ -lReceiptPrint LIBS += -L /home/chw/HSCompany/HardWareTest/source/
HardWareTest/build-HardWareTest-Desktop_Qt_5_10_1_GCC_64bit-Debug/bin/ -
lInfrared} else{ LIBS += -L /home/chw/HSCompany/HardWareTest/source/HardWareTest
/build-HardWareTest-Desktop_Qt_5_10_1_GCC_64bit-Release/bin -lReceiptPrint LIBS
+= -L /home/chw/HSCompany/HardWareTest/source/HardWareTest/build-HardWareTest-
Desktop_Qt_5_10_1_GCC_64bit-Release/bin -lInfrared }
cannot open shared object file: No such file or directory解决方案:
运行报错原因分析,LIBS += -LPATH
-l中添加的库路径是编译链接中使用,用于生成makefile,运行时的库路径是在环境变量中搜索,linux不会搜索当前路径,库路径加入到LD_LIBRARY_PATH变量中即可(使用
LD_DEBUG=libs xxx 可查看程序查找路径);

加载库后编译正常,但是运行报错,尝试添加环境变量,QT-左侧项目-Bulid-构建环境,点击添加,变量LD_LIBRARY_PATH,值$(LD_LIBRARY_PATH):库文件路径;

上述是在qt中添加环境变量,软件发布以后还要在linux系统中设置环境变量,否则还会报上面的错误。

<>编译时加载:QLibrary加载动态库so

契机:在工程文件加载so动态库方便快捷,但遇到过一种情况,当加载多个so文件,且多个so文件有同名函数时,linux系统会以先加载的为准,后加载的被忽略,导致调用混乱,解决方法很多,大多数需要重新编译库,这里介绍使用QLibrary类加载so,不用重新编译so;
QLibrary简介:

使用QLibrary可以在程序运行时加载动态链接库,一个QLibrary的实例作用于一个单一的共享库上,QLibrary库的典型用法是去解析一个库中的导出符号,并调用该符号表示的C函数,如果该库是由C++编译器编译的,那么该函数必须被包在extern
"C"块中。并且在Windows平台上,还需要使用dllexport宏来修饰该函数。
代码示例:
//例如动态库接口函数为:extern "C" int OpenPort(char* pcInPort, int iInBaud); typedef int
(*Cs_OpenPort)(char* , int );//根据动态库接口函数原型,定义一个函数指针类型 Cs_OpenPort OpenPort;
//用新的类型定义一个变量 QLibrary m_ReceiptPrint;//实例化一个QLibrary对象 //加载动态库 m_ReceiptPrint.
setFileName("ReceiptPrint");//关联动态库名称 bool isok = m_ReceiptPrint.load();
//加载动态库,成功返回true,失败返回false OpenPort = (Cs_OpenPort)m_ReceiptPrint.resolve(
"OpenPort");//解析并调用动态库的函数 int ret = OpenPort((char*)"port",38400);
//到这里就可以调用动态库接口
ps:QLibrary方式代码量大容易出错,不建议大量使用,多个so库有同名函数问题在封装阶段就要想办法避免。

<>运行时搜索库路径:固定路径

linux系统不会默认搜索应用程序所在目录的库文件,使用指定的路径搜索动态库;
固定路径有三种方式,生成临时环境变量、写入当前用户配置文件、写入系统配置文件。
1、可在终端执行:
把=号后面替换为库的路径,验证是不是环境变量路径问题,该方法在重启系统后失效;
export LD_LIBRARY_PATH=/usr/local/lib
2、把下面语句加到 ~/.bashrc中,重启后对当前用户还有效:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
3、还有一种方法对所有用户有效,修改共享库配置文件/etc/ld.so.conf,把库路径复制到该文件,执行下面命令立即生效:
sudo ldconfig
4、另一种对所有用户有效的方法:
vim /etc/profile #文档最后添加 export PATH=环境目录:$PATH #生效 source /etc/profile
<>运行时搜索库路径:相对路径

固定路径使用中有很多问题,比如部署时需要修改配置文件;当有别的程序依赖相同名称库,但库的版本不一样时,会导致程序起不来,现场遇到过teamviewer依赖的QT库和我们用QT开发时使用的库名字一样,但版本不一样,导致程序起不来。

因此建议使用相对路径,在QT开发阶段,在pro文件指定库的搜索路径,使用-rpath指定路径为库搜索路径:
QMAKE_LFLAGS += -Wl,--rpath=./lib #指定应用程序所在路径的相对路径为库搜索路径 QMAKE_LFLAGS += -Wl,--
rpath=. #指定应用程序所在路径为库搜索路径
<>补充1

qt环境加载库报错: undefined reference to symbol dlclose
在QT工程的.pro文件中添加如下内容:
LIBS += -ldl #显式加载动态库的动态函数库
<>补充2:QT加载静态库.a文件

只能在pro文件加载,不能通过QLibrary加载,在pro文件加载方式和动态库类似,比如静态库名是libTool_Fun.a,加载方式如下:
INCLUDEPATH += /home/chw/HSCompany/QSRM/Pdjserver/dbTest/dbTest//头文件所在路径 LIBS
+= -L /home/chw/HSCompany/QSRM/Pdjserver/dbTest/build-dbTest-
Desktop_Qt_5_10_1_GCC_64bit-Debug/bin -lTool_Fun//LIBS += -L 库路径 -l库名称
包含头文件后即可使用,注意静态库是直接编译进可执行文件,因此发布以后不需再依赖库。
ps1:生成静态库时命名规则是lib***.a,qt生成的静态库默认是这种命名规则,gcc
编译-o指定静态库文件名也要用这种命名规则,否则在qt中加载时可能失败。
ps2:QT在调用c语言编译的静态库时,发现pro加载库成功,但调用接口时报错,可能是C++和C兼容问题,把头文件中的静态库接口用extern "C"包裹:
extern "C" { //c静态库接口 }
extern "C"的作用:指示编译器这部分代码按C语言方式进行编译,而不是C++方式。

技术
下载桌面版
GitHub
百度网盘(提取码:draw)
Gitee
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:766591547
关注微信