构建一个插件来扩展Qt应用程序

Building a plugin to extend a Qt application

本文关键字:扩展 Qt 应用程序 插件 一个 构建      更新时间:2023-10-16

我决定将我的业余项目应用程序(字典查找程序)切换到插件架构,以便在未来为其他语言开发各种不同的字典。该应用程序是用Qt(5.0.2)在Visual C++中开发的。我在应用程序代码中添加了这个标题,以定义字典插件的接口:

// dict_plugin.h
#ifndef DICT_PLUGIN_H
#define DICT_PLUGIN_H
#include <QtPlugin>
class PluginInterface
{
public:
    virtual ~PluginInterface() {}
    virtual QString language() const = 0;
    virtual class QWidget* ui() const = 0;
};
Q_DECLARE_INTERFACE(PluginInterface, "pl.ksmvision.winona.PluginInterface")
#endif // DICT_PLUGIN_H

接下来,我从"Qt库"模板为插件本身创建了一个新项目(使用Qt Visual Studio插件),该插件用于制作dll。主头文件如下所示:

#ifndef JP_PLUGIN_H
#define JP_PLUGIN_H
// created by the template to define Q_DECL_EXPORT 
// and _IMPORT macros but the plugin engine takes 
// care of that (I think)
//#include "jp_plugin_global.h"
#include <QObject>
#include <QtPlugin>
#include <dict_plugin.h>
class JpPlugin : public QObject, public PluginInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "pl.ksmvision.winona.JpPlugin")
    Q_INTERFACES(PluginInterface)
public:
    JpPlugin();
    virtual ~JpPlugin();
    virtual QString language() const;
    virtual QWidget* ui() const;
};
#endif // JP_PLUGIN_H

当我试图构建它时,我在Q_INTERFACES行上从moc中得到一个错误,指定了我的插件应该实现的接口:

3> ------生成已启动:项目:jp_plugin,配置:调试Win32------
3> 莫青jp_plugin.h…
3> F:\moje\src\cpp\winona\build\jp_plugin\jp_plugin.h(15):错误:未定义接口
==========生成:2成功,1失败,2最新,0跳过==========

看起来moc‘ing发生在dict_plugin.h文件被包含之前,因为当我在包含文件名中输入一个拼写错误时,它不会抱怨该文件不存在,只是终止构建,并返回关于接口未定义的相同错误消息。

我做错了什么?谢谢

moc失败的原因是接口声明不可用。由于找不到文件,#include指令失败。显然,moc可以自己处理#include指令,但如果找不到要包含的文件,则不会(默认情况下?)打印错误消息或停止处理。

找不到带有接口声明的头文件的原因是,Qt VS外接程序生成的导致调用moc的自定义生成设置没有继承项目的include路径。我设法手动将所需的路径添加到moc的命令行,方法是输入插件头文件的属性页,浏览到Custom Build Tool->General->command line,并在末尾添加一个额外的"-I.."include选项。之后,moc处理了标头,构建成功。

对于那些像我一样沿着这条路冒险的人。我的问题略有不同,与名称空间有关。我得到了完全相同的";未定义接口";错误,但路径分辨率对我没有影响。

我有这样的东西:

namespace foo {
class Interface
{
    // ...
};
} // namespace foo
Q_DECLARE_INTERFACE(foo::Interface, "my.interface/1.0")

不正确

namespace foo {
class Derived : public QObject, public Interface
{
    Q_OBJECT
    Q_INTERFACES(Interface)
};
}

正确

namespace foo {
class Derived : public QObject, public Interface
{
    Q_OBJECT
    Q_INTERFACES(foo::Interface)  //!< Notice foo:: is still provided
};
}

原因

来自文件:

如果要将Q_DECLARE_INTERFACE与在命名空间中声明的接口类一起使用,则必须确保Q_DECLARE_INTERFACE不在命名空间内。

但他们没有提到的是,Q_INTERFACES(),即使按范围在该命名空间内部,仍然要求提供命名空间,就好像它是全局的一样。