A Simple C++ Plugin System Summary

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010598445/article/details/52780345

Abstract

一个简单的C++插件系统介绍,主要介绍linux平台下的原理及代码

Keywords

plugin framework c++ plugin system plugin architecture linux

Introduction

Now, lets say that you are making a program, maybe a game, and you decide that you want to make it moddable without your intervention. Now, of course, you think of how that might be possible, and without forcing the users to inject code directly into your executable, or modifying the source code directly. How would you do this?

Well, of course, the answer is a plugin system. I’ll briefly explain how it works: A plugin system is simply where a specified folder is searched for DLLs (or the like), and if any are found, adds the contents to the program. Of course, because the program doesn’t actually know what is in the DLLs, the normal way is for the DLL’s to define a set entry point and calling functions defined by the program itself, which can then use the functionality exposed in those DLLs. The way this can be done is up to you, whether defining functions to implement or maybe getting the DLL to provide an instance of a base class, and then use the functionality from that. In this article, I am briefly going to demonstrate both of those options. First, though, lets look at how to actually load libraries at all.

对于C++这类非脚本语言,它的插件就是共享库,在windowns平台下即xxx.dll,在linux平台下即xxx.so,release/debug也会引入些许不同,不过一般自然是直接使用release版本,更小更快。
为了让避免添加新功能时反复地编译,采用插件系统是一个不错形式,设想已拥有一个主程序MainApp,然后用户从某些地方下载插件,或者说有些高级用户自己开发插件。然后主程序需要如何使用这些插件?需要考虑哪些问题?
1. 设置插件目录,一般就放在主程序根目录下的plugin文件夹下
2. 加载插件目录下的插件,linux下用dlopen
3. 调用插件中的函数,类
4. 插件修改访问主程序中的变量/类(本文没有介绍)
5. 插件配置(本文没有介绍)
6. 插件的运行时加载 vs 插件的重启时加载(本文没有介绍)
7. 插件的升级 (本文没有介绍)

Related work

  1. libSourcey and Pluga 我的编译以失败告终,依赖opencv3等等
  2. github plugin framework 没有找到一个想要的,简单的插件系统

Implementation

为了减小代码量,以知名的数学库为例,只求快速上手,但我不曾想这样的官方程序还有问题/usr/lib/x86_64-linux-gnu/libm.so: invalid ELF header。但可以 借此看看原理,毕竟,上面的错误在Ubuntu14.04上没有发生,但在本人的Ubuntu16.04上却发生了。

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

int main(int argc, char **argv)
{
    void *handle;
    double (*cosine)(double);
    char *error;

   handle = dlopen("libm.so", RTLD_LAZY);
    if (!handle) {
        fprintf(stderr, "%s\n", dlerror());
        exit(EXIT_FAILURE);
    }

   dlerror();    /* Clear any existing error */

   /* Writing: cosine = (double (*)(double)) dlsym(handle, "cos");
       would seem more natural, but the C99 standard leaves
       casting from "void *" to a function pointer undefined.
       The assignment used below is the POSIX.1-2003 (Technical
       Corrigendum 1) workaround; see the Rationale for the
       POSIX specification of dlsym(). */

   *(void **) (&cosine) = dlsym(handle, "cos");

   if ((error = dlerror()) != NULL)  {
        fprintf(stderr, "%s\n", error);
        exit(EXIT_FAILURE);
    }

   printf("%f\n", (*cosine)(2.0));
    dlclose(handle);
    exit(EXIT_SUCCESS);
}

更多的demo 参见csdn git,在上面居然还有服务器支持运行!!!所有demo来自 Article: How to use dlopen ,运行并测试成功。

# build dll
gcc -fPIC -shared -nostartfiles -o triangle.so test3_triangle.cpp
# build exe
g++ test3_main.cpp -ldl -o test3_main
# run test
./test3_main

Reference

Error

  • /usr/lib/x86_64-linux-gnu/libm.so: invalid ELF header
    将libm.so 更改为libm.so.6即可在ubuntu16.04上正确运行。错误的libm.so与/lib/x86_64-linugnu/libm.so.6估计不是同一种东西 。通过readelf xxx.so 可以看出来。

猜你喜欢

转载自blog.csdn.net/u010598445/article/details/52780345