CTK插件框架學習4-創建跨平臺插件工程

在上一篇博客中已經實現了一個簡單的插件和測試程序的編寫,但是插件跟應用是分開獨立的工程。實際應用開發中需要把相關的庫和頭文件打包到一個工程中,如下圖所示,這樣比較方便調試開發,也爲創建跨平臺工程提供了便利。
在這裏插入圖片描述
此節我們將創建一個示例工程,工程文件中包含應用程序以及要使用的各個插件,同時將各個平臺編譯後的ctk插件庫文件也整合到一起。目前支持如下三個平臺:

系統 CPU 編譯器 說明
windows x86_84 msvc 64位系統
linux x86_64 gcc 64位系統
linux arm64 gcc 64位系統

後續考慮增加windows-mingw以及linux-arm32兩個平臺的支持,接下來簡單介紹下工程的實現。

1.工程創建

打開Qt Cteator,選擇文件->新建文件或項目->其它項目->Empty qmake Project,新建一個空的qmake工程,這裏取名爲CtkpluginProj
在這裏插入圖片描述
通過文件瀏覽器進入到該工程目錄下,新建三個目錄,分別命名爲applicationplugin-*plugindepends。其中application目錄用來存放應用程序,plugin-*爲創建的一個插件示例,plugindepends用來存放ctk庫文件。目錄創建完如下圖所示,這裏插件取名爲appinfo,也就是一個用來獲取應用信息的插件。
在這裏插入圖片描述

1.1 plugindepends文件拷貝

plugindepends目錄下存放ctk庫的頭文件以及其編譯生成庫文件。首先將ctk源碼目錄中的Libs/Core與Libs/PluginFramework兩個目錄拷貝到plugindepends目錄下,core目錄與pluginframework目錄中存放着插件與應用程序編譯所依賴的頭文件,同時需要將編譯生成的兩個頭文件也拷貝過來,分別是ctkCoreExport.h與ctkPluginFrameworkExport.h,它們分別位於CTK-build/Libs/Core與CTK-build/Libs/PluginFramework目錄下。
上面步驟僅拷貝所需的頭文件即可,接下來開始拷貝編譯ctk後生成的庫文件,考慮到跨平臺,這裏爲每個平臺各創建一個目錄,並將相應的庫文件拷貝進去,目前在windows-x64、linux-x64、linux-arm64三個平臺下編譯了ctk庫,因此這裏就創建lib-linux-arm64-gcclib-linux-x64-gcclib-windows-x64-msvc三個目錄。創建完成如下圖所示。
在這裏插入圖片描述
linux平臺下與windows平臺下ctk要拷貝的庫文件列表如下圖所示。
在這裏插入圖片描述
最後創建一個Plugindepends.pri文件,用以添加qt工程中的頭文件與庫文件路徑描述,文件內容如下。

INCLUDEPATH +=  $$PWD/../plugindepends/core/ \
                $$PWD/../plugindepends/pluginframework/ \
                $$PWD/../plugindepends/

win32-msvc*{
# for windows visual studio 2015 x64 msvc compiler
equals(QT_ARCH, x86_64): LIBS += -L$$PWD/../plugindepends/lib-windows-x64-msvc/ -lCTKCore -lCTKPluginFramework
}

win32-g++{
# for mingw x64 compiler
equals(QT_ARCH, x86_64): LIBS += -L$$PWD/../plugindepends/lib-windows-x64-mingw/ -lCTKCore -lCTKPluginFramework
}

linux{
# for linux gcc x64 compiler
equals(QT_ARCH, x86_64): LIBS += -L$$PWD/../plugindepends/lib-linux-x64-gcc/ -lCTKCore -lCTKPluginFramework
# for linux gcc arm64 compiler
equals(QT_ARCH, arm64): LIBS += -L$$PWD/../plugindepends/lib-linux-arm64-gcc/ -lCTKCore -lCTKPluginFramework
}

1.2 創建第一個插件

第一個插件示例功能爲運行時打印下應用程序信息,其目錄爲plugin-appinfo,首先到該目錄下,創建一個plugin-appinfo.pro文件,在其中填寫內容如下。

QT += core
QT -= gui

TARGET = plugin-appinfo
TEMPLATE = lib
CONFIG += plugin

include($$PWD/../plugindepends/Plugindepends.pri)

這個時候就可以回到Qt Creator工具了,更改工程文件CtkpluginProj.pro,添加內容如下。

TEMPLATE = subdirs

SUBDIRS += \
    plugin-appinfo/plugin-appinfo.pro

CONFIG += ordered

保存CtkpluginProj.pro文件後,工程界面變成如下圖所示。
在這裏插入圖片描述
這時右鍵點擊plugin-appinfo,選擇Add new,添加一個C++ class,類名可以隨便取,這裏設置爲QPluginActivator,代碼如下。

/***************** qpluginactivator.h *******************/
#ifndef QPLUGINACTIVATOR_H
#define QPLUGINACTIVATOR_H

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

class QPluginActivator : public QObject, public ctkPluginActivator
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "appinfo")
    Q_INTERFACES(ctkPluginActivator)
public:
    QPluginActivator();
    void start(ctkPluginContext *context);
    void stop(ctkPluginContext *context);
};

#endif // QPLUGINACTIVATOR_H

/***************** qpluginactivator.cpp *******************/
#include "qpluginactivator.h"
#include <QDebug>
#include <QCoreApplication>

QPluginActivator::QPluginActivator()
{

}

void QPluginActivator::start(ctkPluginContext *)
{
    qDebug() << QString("I'm appinfo plugin, now start.");
    qDebug() << "app_name: " << qApp->applicationName();
    qDebug() << "app_path: " << qApp->applicationFilePath();
}

void QPluginActivator::stop(ctkPluginContext *)
{
    qDebug() << QString("I'm appinfo plugin, now stop.");
}

然後新建資源文件,添加前綴/plugin-appinfo/META-INF,並在資源文件中創建MANIFEST.MF插件清單文件。創建完成後,工程界面如下圖。
在這裏插入圖片描述

1.3 創建第二個插件

第二個插件創建就比較簡單了,直接拷貝第一個插件的目錄,進行下簡單修改即可。這裏第二個示例插件取名爲sysinfo,也就是加載插件時打印下系統信息。首先通過文件瀏覽器進入到工程目錄,拷貝plugin-appinfo插件目錄爲plugin-sysinfo,然後更改plugin-sysinfo目錄下的plugin-appinfo.pro文件爲plugin-sysinfo.pro,最後更改plugin-sysinfo.pro文件中的"TARGET = plugin-sysinfo"。
接下來再次回到Qt Creator,更改工程文件CtkpluginProj.pro,在其SUBDIRS項添加一行"plugin-sysinfo/plugin-sysinfo.pro",然後工程界面變成如下圖所示。
在這裏插入圖片描述
需要注意的是要修改下resource.qrc資源文件的前綴,改成/plugin-sysinfo/META-INF,另外qpluginactivator.cpp中插件功能根據需要進行下更改,MANIFEST.MF清單文件裏面插件名稱跟版本號也可以重新設置下。

1.4 創建應用程序

插件是爲應用程序服務的,這裏需要一個可執行程序,來加載插件,從而調用插件的功能。
首先到工程的application目錄下,創建一個Application.pro文件,裏面內容如下。

QT -= gui

CONFIG += console
CONFIG -= app_bundle

include($$PWD/../plugindepends/Plugindepends.pri)

然後再次回到Qt Creator,更改工程文件CtkpluginProj.pro,在其SUBDIRS項添加一行"application/Application.pro",然後工程界面變成如下圖所示。
在這裏插入圖片描述
右鍵點擊application,選擇Add new,添加一個C++ source file,取名爲main.cpp,其代碼如下。

#include <QCoreApplication>
#include <ctkPluginFrameworkFactory.h>
#include <ctkPluginFramework.h>
#include <ctkPluginException.h>
#include <ctkPluginContext.h>
#include <QtDebug>
#include <QUrl>

#if defined(WIN32)
    QString static appinfoPlugin_filePath = "../plugin-appinfo/debug/plugin-appinfo.dll";
    QString static sysinfoPlugin_filePath = "../plugin-sysinfo/debug/plugin-sysinfo.dll";
#else
  #ifdef __linux__
    QString static appinfoPlugin_filePath = "../plugin-appinfo/libplugin-appinfo.so";
    QString static sysinfoPlugin_filePath = "../plugin-sysinfo/libplugin-sysinfo.so";
  #endif
#endif

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    ctkPluginFrameworkFactory frameworkFactory;
    QSharedPointer<ctkPluginFramework> framework = frameworkFactory.getFramework();

    // 初始化並啓動插件框架
    try {
        framework->init();
        framework->start();
        qDebug() << "CTK plugin framework start...";
    } catch (const ctkPluginException &e) {
        qDebug() << "CTK plugin framework init err: " << e.what();
        return -1;
    }

    // 獲取插件服務的contex
    ctkPluginContext* pluginContext = framework->getPluginContext();
    // 安裝啓動插件appinfo
    try {
        // 安裝插件
        QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(appinfoPlugin_filePath));
        qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
        // 啓動插件
        plugin->start(ctkPlugin::START_TRANSIENT);
    } catch (const ctkPluginException &e) {
        qDebug() << QString("Failed install or run plugin: ") << e.what();
        return -2;
    }
    // 安裝啓動插件sysinfo
    try {
        // 安裝插件
        QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(sysinfoPlugin_filePath));
        qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
        // 啓動插件
        plugin->start(ctkPlugin::START_TRANSIENT);
    } catch (const ctkPluginException &e) {
        qDebug() << QString("Failed install or run plugin: ") << e.what();
        return -2;
    }

    return a.exec();
}

2. 運行應用

在Qt Creator軟件中,點擊綠色三角的運行鍵,開始編譯運行工程,它會自動的先編譯插件,最後編譯運行應用程序。
window-msvc環境下編譯運行結果如下圖所示。
在這裏插入圖片描述
linux-x86_64環境下編譯運行結果如下圖所示。
在這裏插入圖片描述
linux-arm64環境下編譯運行結果如下圖所示。
在這裏插入圖片描述
最後還一點,這樣編寫工程的好處在於,遷移工程到一個已支持的平臺上,不用再先下載並編譯配置CTK庫了,直接拷貝整個工程代碼到平臺上編譯運行即可,可以把精力放到開發插件及應用程序上。

整個工程代碼我上傳到csdn資源-12075076,歡迎進行下載編譯驗證。

發佈了30 篇原創文章 · 獲贊 63 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章