如何以符合标准的方式实现C ++插件?

时间:2015-10-08 22:48:11

标签: c++ linux plugins extern unique-ptr

我确实在SO和其他地方环顾四周,但找不到这个相当标准问题的满意答案。我对linux和标准合规性特别感兴趣。我来自以下方法

file plugin.h图书馆的一部分

#include <memory>
#include <string>
/// defines an interface to be implemented by a plugin
struct PluginBase
{
  virtual~PluginBase() {}
  virtual double calc(double) const = 0;
};
/// loads a plugin
/// \param[in] file  shared object file to load and find plugin in
/// \param[in] strg  data for initialising the plugin
std::unique_ptr<PluginBase> load_plugin(std::string const&file, std::string const&strg);
extern "C" {
  /// to be implemented with plugin
  /// \param[in] strg  data for initialising the plugin
  std::unique_ptr<PluginBase> create_plugin(std::string const&strg);
}

file plugin.cc图书馆的一部分

#include "plugin.h"
#include <cassert>
extern "C" {
#include <dlfcn.h> // dlopen() dlsym()
  std::unique_ptr<PluginBase>(*create_ptr)(std::string const&);
}
std::unique_ptr<PluginBase> load_plugin(std::string const&file,
                                        std::string const&strg)
{
  auto handle = dlopen(file.c_str(),RTLD_LAZY|RTLD_GLOBAL);
  assert(handle);                                  // in lieu of proper error handling
  auto func_ptr = dlsym(handle,"create_plugin");
  assert(func_ptr);                                // ditto
  return reinterpret_cast<create_ptr>(func_ptr)(strg);
}

file some_plugin.cc不属于图书馆

#include "plugin.h"
struct PluginImpl : PluginBase
{
  PluginImpl(std::string const&);
  double calc(double) const override;
};
/// has extern "C" linkage
std::unique_ptr<PluginBase> create_plugin(std::string const&strg)
{
  return std::unique_ptr<PluginBase>(new PluginImpl(strg));
}

这种做事方式是否正确且符合标准?特别是,我可以从具有std::unique_ptr<>链接的函数返回extern "C"吗?并且这样的函数可以采用const引用参数吗?我是否必须将create_ptr声明为extern "C"(在文件plugin.cc中)?我可以避免extern "C"并直接获取C ++符号(this article讨论这个用于Windows,而不是linux,并且是编译器特定的)?

1 个答案:

答案 0 :(得分:2)

  1. Linkage与类型无关。它只是 names 的属性。

  2. C ++标准未指定动态加载方式;具体而言,未指定从void指针到函数指针的重新解释。还有其他一些关于静态初始化器和共享静态对象的细微问题,这些问题没有被正确指定并且会让您大吃一惊。

  3. 但是,Posix标准文档<dlfcn.h>并且还要求强制转换符合您的想法,因此您的代码符合Posix标准,并且应该适用于任何符合Posix的操作系统。

    < / LI>
  4. 找不到符号名称没有通用的方法。如果您使用C链接,则需要咨询您的平台的C ABI;如果你想使用C ++链接,你需要咨询你的C ++ ABI。既不是通用的也不是固定的,尽管对于C ABI看起来比C ++有更多的跨平台协议。 (具体来说,应该可以在C ABI中以符合源代码名称相同的方式发出符号。)