1. 程式人生 > >Qt5下通過CMake建立CTK外掛的步驟

Qt5下通過CMake建立CTK外掛的步驟

這兩天一直在看CTK外掛的用法,網上資料實在太少,只能通過已有的一些開源工程摸索,過程中遇到很多問題,都是些細節方面的東西,把過程記錄下來,方便以後查閱。網上有通過pro檔案建立外掛的教程,這裡只介紹通過CMakeList配置外掛的方法。

首先新建一個外掛類PluginLoader(名字可以隨意起)

#include <ctkPluginActivator.h> 
#include <ctkPluginContext.h>

class ServiceOne;

class LoadPlugin : public QObject, public ctkPluginActivator
{
    Q_OBJECT
    Q_INTERFACES(ctkPluginActivator)

#ifdef HAVE_QT5
        Q_PLUGIN_METADATA(IID "org_ctk_example")
#endif

public:
    LoadPlugin();
    void start(ctkPluginContext *Context);
    void stop(ctkPluginContext *Context);

private:
    ServiceOne   *m_service;
};

實現類

#include "LoadPlugin_p.h"

#include <QtPlugin> 
#include "ServiceOne.h"

LoadPlugin::LoadPlugin():m_service(0)
{

}


void LoadPlugin::start(ctkPluginContext *Context)
{
    m_service = new ServiceOne;
    Context->registerService(QStringList("Service"), m_service);
}

void LoadPlugin::stop(ctkPluginContext *Context)
{
    if (m_service)
    {
        delete m_service;
        m_service = 0;
    }
}

#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
Q_EXPORT_PLUGIN2(org_commontk_log, ctkLogPlugin)
#endif
因為Q_EXAPORT_PLUGIN2在Qt5中已經廢棄了,這裡加個巨集來判斷。其中ServieOne為服務的實現類,繼承自介面IService,介面供外部呼叫

IService.h:

#include <QObject>

class IService :public QObject
{
    Q_OBJECT
public:
    virtual void SetParameter(int x) = 0;
    virtual int GetParameter() = 0;
};

Q_DECLARE_INTERFACE(IService, "Service")
ServiceOne.h
#include "IService.h"

#include "QObject"

class ServiceOne : public IService
{
    Q_OBJECT
    Q_INTERFACES(IService)
public:
    ServiceOne() {}
    ~ServiceOne() {}

    void SetParameter(int x) { m_x = x; }
    int GetParameter() { return m_x; }

private:
    int m_x;
};

       下面是CMakeList.txt中的內容

project(org_ctk_example)

set(PLUGIN_export_directive "org_ctk_example_EXPORT")

find_package(CTK REQUIRED)

include_directories(
	${CTKCore_INCLUDE_DIRS}
	${CTKPluginFramework_INCLUDE_DIRS}
)

set(PLUGIN_SRCS
  LoadPlugin.cxx
)

# Files which should be processed by Qts moc
set(PLUGIN_MOC_SRCS
  LoadPlugin_p.h
  IService.h
  ServiceOne.h
)

# Qt Designer files which should be processed by Qts uic
set(PLUGIN_UI_FORMS
)

# QRC Files which should be compiled into the plugin
set(PLUGIN_resources
)

#Compute the plugin dependencies
ctkFunctionGetTargetLibraries(PLUGIN_target_libraries)

ctkMacroBuildPlugin(
  NAME ${PROJECT_NAME}
  EXPORT_DIRECTIVE ${PLUGIN_export_directive}
  Hdrs ${Headers}
  SRCS ${PLUGIN_SRCS}
  MOC_SRCS ${PLUGIN_MOC_SRCS}
  UI_FORMS ${PLUGIN_UI_FORMS}
  RESOURCES ${PLUGIN_resources}
  TARGET_LIBRARIES ${PLUGIN_target_libraries}
)


因為生成CTK外掛需要一個qrc檔案和MF檔案,ctk提供的ctkMacroBuildPlugin工具可以在建立外掛工程的同時自動建立這兩個檔案,不過需要我們在原始檔目錄下放置兩個cmake檔案manifest_headers.cmake和target_libraries.cmake,檔案內容分別為

manifest_headers.cmake

set(Plugin-Name "CTK Example")
set(Plugin-ActivationPolicy "eager")
Plugin-name為外掛名稱,可以自己設定。

arget_libraries.cmake

SET(target_libraries
  CTKPluginFramework
)

建立好這兩個檔案,通過cmake配置我們的工程,在生成目錄下就會生成MANIFEST.MF和org_ctk_example_manifest.qrc兩個檔案了。生成好的外掛通過Dependency Walker檢視,需要有兩個匯出函式qt_plugin_instance和qt_plugin_query_metadata,否則說明外掛配置有問題(剛開始因為一些細節外掛總是生成失敗T_T)。

生成成功後就可以載入外掛並呼叫服務了

ctkPluginFrameworkFactory* ctkFrameWorkFactory = new ctkPluginFrameworkFactory;
    QSharedPointer<ctkPluginFramework> framework = ctkFrameWorkFactory->getFramework();

    try
    {
        framework->init();

        framework->start();

        qDebug() << "[Info] ctkPluginFramework start ...";
    }
    catch (const ctkPluginException &Exception)
    {
        qDebug() << QObject::tr("Failed to initialize the plug-in framework: ") << Exception.what();
        return 1;
    }


    //install plugin
    ctkPluginContext* pluginContext = framework->getPluginContext();
    QSharedPointer<ctkPlugin> Plugin = pluginContext->installPlugin(QUrl::fromLocalFile("../liborg_ctk_example.dll"));
    Plugin->start(ctkPlugin::START_TRANSIENT);

    ctkServiceReference reference = pluginContext->getServiceReference("Service");
    IService *test = qobject_cast<IService *>(pluginContext->getService(reference));
    test->SetParameter(10);
    qDebug() << test->GetParameter();