2015-10-08 7 views
0

Я смотрел вокруг SO и в другом месте, но не смог найти удовлетворительного ответа на этот довольно стандартный вопрос. Меня особенно интересует Linux и стандартное соответствие. Я наткнулся на следующий подходКак реализовать плагин C++ стандартным образом?

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)); 
} 

Является ли этот путь делать что-то правильно и стоять ard совместимый? В частности, могу ли я вернуть std::unique_ptr<> из функции с привязкой extern "C"? и может ли такая функция принимать аргумент const? Должен ли я объявлять create_ptr как extern "C" (в файле plugin.cc)? Могу ли я избежать extern "C" и напрямую получать символы C++ (this article обсуждает это для Windows, а не linux и является специфичным для компилятора)?

+0

Это наконец-то, чтобы получить компилятор/среда выполнения конкретных, потому что стандарты C++ не полагаются на такие понятия, как статическая или динамическая связь. –

+0

Насколько мне известно, стандартов для плагинов нет. Также нет совместимости с плагинами. Это вся платформа и ОС. –

ответ

2
  1. Связь не имеет ничего общего с типами. Это исключительно свойство имен.

  2. Динамическая загрузка того, как вы это делаете, не указана стандартом C++; в частности, реинтерпрет, переданный из указателя void на указатель функции, не указан. Существуют и другие тонкие проблемы относительно статических инициализаторов и обмена статическими объектами, которые не указаны должным образом и могут вас удивить.

  3. Однако, стандартные документы Posix <dlfcn.h>, а также требует, чтобы листинг делал то, что вы думаете, поэтому ваш код совместим с Posix и должен работать с любой совместимой с Posix операционной системой.

  4. Нет универсального рецепта для поиска имен символов. Если вы используете C-ссылку, вам необходимо проконсультироваться с C ABI вашей платформы; если вы хотите использовать ссылку на C++, вам нужно проконсультироваться с вашим C++ ABI. Также не является универсальным или фиксированным, хотя существует гораздо больше межплатформенного соглашения о том, что выглядит C ABI, чем для C++. (В частности, должно быть возможно испускать символы в C ABI таким образом, что исковерканные имена функций совпадают с их именами в исходном коде.)