库的基本概念
0 库链接
说明:在不同平台下,库的表现形式是不一样的。
linux平台 | windows平台 | |
---|---|---|
动态库 | .so | .dll |
静态库 | .a | .lib |
目标文件 | .o | .obj |
其中 .a 是linux下经过一堆.o文件链接的集合,.lib是windows下一堆.obj经过链接的集合
动态链接:共享dll(.so)的数据和代码。操作系统可以提供一种方式让进程可以调用不属于自身的代码和访问数据,动态库包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。
静态链接:链接器从库复制所需的代码编译好的二进制数据,和代码的obj(linux下是.o文件)一起链接,生成exe(a.out)可执行文件。缺点是多次引用静态库,则会多次拷贝链接到exe/a.out内。
1 .dll .lib .obj
在windows操作系统下,经过vs编译为静态库和动态库都含有.lib文件,它们的区别是:
静态库中的lib:该LIB包含函数代码本身(即包括函数的索引,也包括实现),在编译时直接将代码加入程序当中
动态库中的lib:该LIB包含了函数所在的DLL文件和文件中函数位置的信息(索引),函数实现代码由运行时加载在进程空间中的DLL提供
总之,lib是编译时用到的,dll是运行时用到的。如果要完成源代码的编译,只需要lib;如果要使动态链接的程序运行起来,只需要dll。在开发和调试阶段,当然最好都有。
2 .so .a .o
linux下文件的类型是不依赖于其后缀名的,但一般来讲:
.o,是目标文件,相当于windows中的.obj文件
.so 为共享库,是shared object,用于动态连接的,和dll差不多
.a为静态库,是好多个.o合在一起,用于静态连接
.la为libtool自动生成的一些共享库,vi编辑查看,主要记录了一些配置信息。可以用如下命令查看*.la文件的格式 $file *.la
*.la: ASCII English text
所以可以用vi来查看其内容。
qt插件的生成
1 在qt 下制作插件流程:
基类的实现:filterinterface.h
#include <cstdio>
#include <QDebug>
/*
插件基类,所有插件继承自这个类
*/
class PluginInterFace
{
public:
PluginInterFace()
{
printf("PluginInterFace构造了\n");
}
virtual ~PluginInterFace(){
printf("PluginInterFace析构了\n");
}
virtual void SayHello() {}// 纯虚函数
};
// 定义动态库 iid (唯一的识别标识)
#define pluginInterFace_iid "io.qt.dynamicplugin"
// 向qt的元对象系统声明了这个插件接口
// 类名,类名iid
Q_DECLARE_INTERFACE(PluginInterFace, pluginInterFace_iid)
插件的实现:
#ifndef PLUGIN_H
#define PLUGIN_H
#include <QObject>
#include "../test1/filterinterface.h"
#include "hello.h"
// 构建的是 plugin子项目,而不是运行整个项目,会生成 .dll文件
class Plugin : public QObject, public PluginInterFace
{
Q_OBJECT
// 插件基类的iid 及 包含插件元数据的json文件【我们必须新建一个json文件,名称与这相同 json文件内容是{} 】
// 也可以不需要 json文件
Q_PLUGIN_METADATA(IID pluginInterFace_iid FILE "plugin.json")
// 基类名称
Q_INTERFACES(PluginInterFace)
public:
explicit Plugin(QObject *parent = nullptr);
~Plugin();
void SayHello();
Hello he;
signals:
public slots:
};
#endif // PLUGIN_H
配置插件项目的pro文件:(必须)
HEADERS += \
plugin.h \
hello.h
SOURCES += \
plugin.cpp \
hello.cpp
# 窗口模块
QT += core widgets
# 必须配置好,才是动态插件
# TEMPLATE 表示生成的目标是 app 还是 lib 等
TEMPLATE = lib
CONFIG += Plugin
DISTFILES += \
plugin.json
最后是使用dll:
固定加载:
PluginInterFace * interface = nullptr;
QPluginLoader pluginLoader("plugin.dll");
QObject *plugin = pluginLoader.instance();
if(plugin)
{
interface = qobject_cast<PluginInterFace*>(plugin);
if(interface)
{
interface->SayHello();
}
}
动态加载刷新dll:(案例)
// 通过获取 plugins/phones 目录下的所有dll,筛选需要加载的dll
ScreenTool *GetPhoneObject::phoneObject(const QString &iMenufest, const QString &iSerial)
{
if(iSerial.isEmpty())
{
qDebug() << "iSerial is null";
return NULL;
}
if(!pluginPath.isEmpty())
pluginPath.clear();
pluginPath.append(qApp->applicationDirPath());
PhoneCreateManage *manage = NULL;
QDir pluginDir(pluginPath);
// pluginDir.cdUp();
pluginDir.cd("plugins");
pluginDir.cd("phones");
const auto pluginList = pluginDir.entryList(QDir::Files);
foreach (const QString &fileName , pluginList) {
QPluginLoader loader(pluginDir.absoluteFilePath(fileName));//这里必须使用 pluginDir.absoluteFilePath(fileName)来转换fileName,否则会加载失败
QObject *phone = loader.instance();
qDebug() << "loader phone:" << loader.errorString() << " " <<fileName;
myLog->writeLog("GetPhoneObject.cpp", 69, 4, 0, QString("loader phone: %1").arg(loader.errorString()).toStdString().c_str());
if(phone)
{
manage = qobject_cast<PhoneCreateManage*>(phone);
if(manage)
{
qDebug() << manage->serialId();
if(manage->serialId() == iSerial.trimmed())
{
ScreenTool * tool = manage->createPhone(manage->returnMenufest(), iSerial);
tool->setPhoneProduct(manage->returnProduct());
tool->setPhoneSize(manage->returnPhoneSize());
tool->setPhoneVersion(manage->returnPhoneVersion());
return tool;
}
}
}
}
return NULL;
}
总结
在使用库的过程中遇到很多的坑,原因是我对库的概念不清晰。
qt使用插件:把插件编译成为realse | debug版本根据项目是什么版本编译的,版本不一样会出错
某些vs编译的lib静态库,只能在vs下使用,这是我遇到的坑之一