CTK插件框架学习4-创建跨平台插件工程「建议收藏」

CTK插件框架学习4-创建跨平台插件工程「建议收藏」在上一篇博文中已经实现了一个简单的插件和测试程序的编写,但是插件跟应用是分开独立的工程。实际应用开发中需要把相关的库和头文件打包到一个工程中,如下图所示,这样比较方便调试开发,也为创建跨平台工程提供了便利。此节我们将创建一个初步完整的工程,工程文件中包含应用程序以及要使用的各个插件,同时将各个平台编译后的ctk插件库文件也整合到一起。目前支持如下三个平台:系统CPU编译器说明…

大家好,又见面了,我是你们的朋友全栈君。

在上一篇博客中已经实现了一个简单的插件和测试程序的编写,但是插件跟应用是分开独立的工程。实际应用开发中需要把相关的库和头文件打包到一个工程中,如下图所示,这样比较方便调试开发,也为创建跨平台工程提供了便利。
在这里插入图片描述
此节我们将创建一个示例工程,工程文件中包含应用程序以及要使用的各个插件,同时将各个平台编译后的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,欢迎进行下载编译验证。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/143780.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • stm32f103替换_能力复用

    stm32f103替换_能力复用文章来源:刚接触STM32F103,在尝试编写“按键中断”和“PWM呼吸灯”程序的时候,发现例程都用到了管脚复用AFIO://打开管脚复用AFIORCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);写到“232USART串口通信”程序时,当我非常自信的写下上面这句代码后,发现例程里面却没有这句话,很让人摸不着头脑……查了很多资料,加上

    2022年10月10日
  • scrapy爬虫出现Forbidden by robots.txt[通俗易懂]

    scrapy爬虫出现Forbidden by robots.txt[通俗易懂]先说结论,关闭scrapy自带的ROBOTSTXT_OBEY功能,在setting找到这个变量,设置为False即可解决。使用scrapy爬取淘宝页面的时候,在提交http请求时出现debug信息Forbiddenbyrobots.txt,看来是请求被拒绝了。开始因为是淘宝页面有什么保密机制,防止爬虫来抓取页面,于是在spider中填入各种header信息,伪装成浏览器,结果还是不行。。

  • Mysql事务隔离级别_数据库默认的事务隔离级别

    Mysql事务隔离级别_数据库默认的事务隔离级别前言提到事务,你肯定不会陌生,最经典的例子就是转账,甲转账给乙100块,当乙的账户中到账100块的时候,甲的账户就应该减去100块,事务可以有效的做到这一点。在MySQL中,事务支持实在引擎层实现的,MySQL是一个支持多引擎的系统,但并不是所有引擎都支持事务。比如MySQL原生的MyISAM引擎就不支持事务,这也是MyISAM被取代的原因之一。隔离性事务的四大特性AC…

    2022年10月14日
  • 几种常见mybatis分页实现[通俗易懂]

    几种常见mybatis分页实现[通俗易懂]mybatis框架分页实现,有几种方式,最简单的就是利用原生的sql关键字limit来实现,还有一种就是利用interceptor来拼接sql,实现和limit一样的功能,再一个就是利用PageHelper来实现。这里讲解这三种常见的实现方式:无论哪种实现方式,我们返回的结果,不能再使用List了,需要一个自定义对象Pager。packagecom.xxx.mybatis.bean;…

    2022年10月20日
  • ConcurrentHashMap实现原理及源码分析

    ConcurrentHashMap实现原理及源码分析一、ConcurrentHashMap跟HashMap,HashTable的对比HashMap不是线程安全:在并发环境下,可能会形成环状链表(扩容时可能造成,具体原因自行百度google或查看源码分析),导致get操作时,cpu空转,所以,在并发环境中使用HashMap是非常危险的HashTable是线程安全的:HashTable和HashMap的实现原理几乎一样,差别:1.Ha…

  • linux中如何给文件重命名_ppt重命名怎么恢复

    linux中如何给文件重命名_ppt重命名怎么恢复Linux下文件重命名、创建、删除、修改及保存文件一、重命名(更名)linux给文件改名的命令是mv命令mv命令来为文件或目录改名或将文件由一个目录移入另一个目录中。该命令等同于DOS系统下的ren和move命令的组合。它的使用权限是所有用户。格式mv[options]源文件或目录目标文件或目录。主要参数[options]-i:交互方式操作。如果mv操作将导致对已存在的目标文…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号