[QT]qt plugin插件

plugin是作为dll的一种特殊的应用而存在的. 也就
是说,在linux下面,他是so的一种应用而已. 动态链接装入器例程 dlopen 需要在文件系统
中查找共享目标文件以打开文件并创建句柄. 有 4 种方式用以指定文件的位置:
  1.dlopen call 中的绝对文件路径
  2.在 LD_LIBRARY_PATH 环境变量中指定的目录中
  3.在 /etc/ld.so.cache 中指定的库列表之中,可以用命令更新ld.so.cache:
    ldconfig -C ld.so.cache -n ../lib -v
  4.先在 /usr/lib 之中,然后在 /lib 之中

 

今天主要是看了qt相关的plugin的东西. 并且尝试了一个plugin的程序,对于我们来说,
plugin是一个非常非常有用的东西,以后要多用.
对于qt而言,plugin是做成动态链接库的形式存在的,但是qt的plugin有一些特殊的地方. 事
实上,qt的plugin有两种,高层次和低层次的. qt的高层(high level)plugin是有qt的
meta-object system自动管理的. 也就是说你必须把你的plugin放在特定的子目录下面不能
修改,qt会自动寻找这些plugin. 当然我们可以用QLibrary重新设定qt lib的path,但是我觉
得这样是非常不礼貌的做法. 当然了,高层plugin也会自动搜寻系统的当前执行目录下的子
目录来寻找plugin. 高层的plugin包括了许多有用的东西,包括了image,textcode,style等
等.
而对于我们更加有用的低层次的plugin,这种plugin可以用QPluginLoader来加载,我们可以
利用qApp::applicationDirPath()来得到我们当前的程序运行path,然后利用
QDir::cd("plugins")这样的操作进入我们的plugins子目录,然后load之. 对于这类的
plugin我们需要遵循下列的step
  ap:
    1.定义一个Interface,并且用Q_DECLARE_INTERFACE宏告知qt meta-object system有这
   样一个interface;
 2.用QPluginLoader加载这个plugin,用qobject_cast<>测试这个interface是否可用;
  plugin:
    1.定义一个plugin的类,必须从interface继承,并在.h用Q_INTERFACE告诉meta-object
   system我们的类支持这样的interface;
 2.实现这个类并用Q_EXPORT_PLUGIN2(pluginName,class)导出这个plugin,建立合适的
   .pro文件来编译这个plugin
要注意的是默认的plugin是编译在debug模式下的,如果ap是release模式的话不能load
debug模式的plugin的. 我们可以在.pro中加入"config += release"这样的语句来改变
build模式.
结构上,我们的interfaces.h(包含Q_DECLARE_INTERFACE)可以为ap和plugin公共include没
有问题. 我们要注意的有:
  1.interfaces.h(包含Q_DECLARE_INTERFACE);
  2.Q_INTERFACE(interface1 interface2 interface3)放在plugin.h中;
  3.Q_EXPORT_PLUGIN2(pluginName,class)放在plugin.cpp中;
  4.plugin.pro文件中一定要定义TARGET的内容,并且这个内容必须和Q_EXPORT_PLUGIN2中
    的pluginName一致;
  5.ap除了写代码load plugin之外不需要特殊的的宏;
这样我们就可以把我们的代码写成plugin了,如果你觉得子目录也要做成可以定义的话当然
也可以,做成QSetting就好了.
下面是我们的试验程序,注意这个程序中用了下面语句来列举plugins目录下的所有
plugin.so:
 pluginsDir = QDir(qApp->applicationDirPath());
 pluginsDir.cd("plugins");
 foreach (QString fileName,pluginsDir.entryList(QDir::Files))
 {
        QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
  ...
 }
 // 注意这段程序中用到了applicationDirPath来得到app的地址. 要用到这种功能的话
 // 要#include 才行,qApp不需要自己定义,系统会自动定义的.
 // 还有就是用到了foreach宏来列举dir下面的所有文件名. 显然比较可爱
我们的试验程序plugin叫做kitty(猫咪),而ap叫做hunny,显然,我是想不到合适的名字罢了.
  kitty:
    .pro:
  ######################################################################
  # Automatically generated by qmake (2.00a) 四 11月 9 10:37:28 2006
  ######################################################################

  TEMPLATE = lib
  CONFIG  += plugin
  INCLUDEPATH += ..  # "指定特殊的include path"
  TARGET  += kitty # "特别注意这里"
  DEPENDPATH += .
  INCLUDEPATH += .

  # Input
  HEADERS += kitty.h
  SOURCES += kitty.cpp
 .h:
  #ifndef KITTY_H
  #define KITTY_H

  #include
  #include

  class Kitty : public QObject,
       public KittyInterface
  {

  Q_OBJECT
  Q_INTERFACES(KittyInterface)

  public:
   // for KittyInterface
   void go();
  };
  #endif
 .cpp:
  #include
  #include "kitty.h"

  void
  Kitty :: go()
  {
   printf("Kitty :: go() called/n");
   printf("Kitty :: goto() /n");
  }

  Q_EXPORT_PLUGIN2(kitty,Kitty)
  hunny: // 我们把kitty作为plugin放在plugins目录下
    .pro: // 其实不需要做什么特殊的修改
  ######################################################################
  # Automatically generated by qmake (2.00a) 四 11月 9 10:58:12 2006
  ######################################################################

  TEMPLATE = app
  TARGET +=
  DEPENDPATH += .
  INCLUDEPATH += .

  # Input
  HEADERS += hunny.h interfaces.h
  SOURCES += hunny.cpp main.cpp

  CONFIG  += debug
 .h:  // 也不需要特殊的动作
  #ifndef HUNNY_H
  #define HUNNY_H

  #include
  #include
  #include
  #include
  #include "interfaces.h"

  class Hunny : public QObject
  {
  Q_OBJECT


  public: 
   void loadPlugins();
   
  private:
   QDir pluginsDir;

  };
  #endif
 .cpp: // load kitty而已
  #include "hunny.h"

  void
  Hunny :: loadPlugins()
  {
   printf("Hunny :: loadPlugins/n");
   pluginsDir = QDir(qApp->applicationDirPath());
   pluginsDir.cd("plugins");
   
   foreach (QString fileName,pluginsDir.entryList(QDir::Files))
   {
    QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
    printf("loadPlugins : /
      fileName(%s)/n",fileName.toAscii().data());
    QObject *plugin = loader.instance();
    printf("loadPlugins : plugin = %#x/n",plugin);
    if (plugin)
    {
     KittyInterface *iKitty =
         qobject_cast(plugin);
     printf("loadPlugins : load KittyInterface,/
        iKitty = %#x/n",iKitty);
     if (iKitty)
     {
      iKitty->go();
     }
    }
   }
  }
  main.cpp:
  #include
  #include "hunny.h"

  int main(int argc,char *argv[])
  {
   QApplication app(argc,argv);
   Hunny h;
   h.loadPlugins();
   return app.exec();
  }
  interfaces.h:  // 公用的interfaces
  #ifndef INTERFACES_H
  #define INTERFACES_H

  class KittyInterface
  {
  public:
   virtual void go() = 0;
   
  };

  Q_DECLARE_INTERFACE(KittyInterface,
       "com.S1.Linxb.hunny.KittyInterface/1.0")
  // 这里的标识字符其实没有什么关系的
  #endif

你可能感兴趣的:([QT]qt plugin插件)