c++插件管理--pluma<实践>

最近研究了一下pluma的使用。发现官网上的简单示例对于刚入门的人来说还是麻烦了些(而且还有语法错误)。
下面重新整理了一个例子,作为备注。

其中,device为一个虚基类,作为接口类存在。keyboardscreen作为实现了device的子类存在,实现具体的操作。在pluma上注册后,在main中调用接口,实现keyboardscreen的调用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// device.hpp
#ifndef _DEVICE_HPP_
#define _DEVICE_HPP_
#include "Pluma/Pluma.hpp"

class Device{
public:
    virtual std::string getDescription() const=0;
};
// create DevicedProvider class
PLUMA_PROVIDER_HEADER(Device);

#endif
1
2
3
// device.cpp
#include "device.hpp"
PLUMA_PROVIDER_SOURCE(Device, 6, 3);

如上所示,是device的定义。其中PLUMA_PROVIDER_HEADERPLUMA_PROVIDER_SOURCEpluma提供的宏。功能暂且不论。我们继续往下看。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// screen.hpp
#include "Pluma/Pluma.hpp"
#include "device.hpp"

class Screen: public Device{
public:
    std:: string getDescription() const{
        return "screen";
    }
};

PLUMA_INHERIT_PROVIDER(Screen, Device);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// keyboard.hpp
#include "Pluma/Pluma.hpp"
#include "device.hpp"

class Keyboard: public Device{
public:
    std:: string getDescription() const{
        return "keyboard";
    }
};

PLUMA_INHERIT_PROVIDER(Keyboard, Device);

上面实现了screenkeyboard的逻辑。实现了之后,需要进行注册:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// connect.cpp
 #include <Pluma/Connector.hpp>
 #include "keyboard.hpp"
 #include "screen.hpp"

 PLUMA_CONNECTOR
 bool connect(pluma::Host& host){
     // add a keyboard provider to host
     host.add( new KeyboardProvider() );
     host.add( new ScreenProvider() );
     return true;
 }

这里在connect中进行了两个子类的注册。之所以使用connect是因为后面的pluma使用的时候,官网给出的示例代码中,会从connect入口开始调用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// main.cpp
#include "Pluma/Pluma.hpp"

#include "device.hpp"
#include <iostream>
#include <vector>

int main()
{
    pluma:: Pluma plugins;
    plugins.acceptProviderType<DeviceProvider>();
    plugins.load("./plugin/connect.so");
    //plugins.load("./plugin/keyboard.so");

    std::vector<DeviceProvider*> providers;
    plugins.getProviders(providers);

    std::cout<<"size for providers are:" << providers.size()<< std:: endl;
    if (!providers.empty()){
        for (std::vector<DeviceProvider*>::iterator device=providers.begin();
            device != providers.end(); ++ device){
            Device* myDevice = (*device)->create();
            std::cout << myDevice->getDescription() << std::endl;
            delete myDevice;
        }
    }
    return 0;
}

这里就是主要的调用逻辑了。官网中myDevice附近的拼写有主意,这是个坑了。
这里回顾下目录结构:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.
├── connect.cpp
├── device.hpp
├── device.cpp
├── keyboard.hpp
├── main.cpp
├── plugin                          # 用来存储插件结果的目录
├── Pluma                           # 为了方便,这里将Pluma的include及src文件均拷贝到这里
│   ├── Config.hpp
│   ├── Connector.hpp
│   ├── Dir.cpp
│   ├── Dir.hpp
│   ├── DLibrary.cpp
│   ├── DLibrary.hpp
│   ├── Host.cpp
│   ├── Host.hpp
│   ├── PluginManager.cpp
│   ├── PluginManager.hpp
│   ├── Pluma.hpp
│   ├── Pluma.inl
│   ├── Provider.cpp
│   ├── Provider.hpp
│   └── uce-dirent.h
└── screen.hpp

看下编译过程:

1
2
3
4
5
# 生成device.so
g++ connect.cpp device.cpp Pluma/*.cpp -shared -fPIC -o plugin/connect.so -I./

# 生成main
g++ main.cpp device.hpp device.cpp Pluma/*.cpp -o main -I./ -ldl

执行:

1
2
3
4
./main
size for providers are:2
keyboard
screen

以上就是实践的内容了。

Licensed under CC BY-NC-SA 4.0
Hello, World!
使用 Hugo 构建
主题 StackJimmy 设计