Реализация диспетчера плагинов Dynami c - PullRequest
1 голос
/ 14 февраля 2020

Я пытаюсь создать менеджер плагинов для c ++, который проверяет каталог для разделяемых библиотек (dll, итак, dylib) и проверяет, есть ли доступный интерфейс плагина для хранения плагина и последующего его получения с помощью.

Я использую boost :: dll для импорта библиотеки DLL, но я не знаю, как лучше настроить шаблон.

Как использовать шаблоны или какой-либо другой метод для добавления интерфейсов плагинов в менеджер плагинов, чтобы он проверял в разделяемых библиотеках имя псевдонима экспорта и сохранял дескриптор разделяемой библиотеки?

PluginInterface.hpp

class PluginInterface {
public:
  virtual void testPlugin() = 0;
};

plugin.hpp source для "plugins_directory / plugin. dll "

#include <boost/config.hpp> // for BOOST_SYMBOL_EXPORT
#include "pluginInterface.hpp"

namespace PluginNamespace {
class PluginClass : public PluginInterface {
  void testPlugin(){
    printf("Hello World!");
  }
}

extern "C" BOOST_SYMBOL_EXPORT PluginClass pluginName;
PluginClass pluginName;
}

PluginManager.hpp

class InterfaceMethodsBase {
public:
  std::string pluginName;
  InterfaceMethodsBase(std::string s) { pluginName = s; }
  ~InterfaceMethodsBase() {}
  virtual void addPath(std::filesystem::path p) = 0;
};

template <class T> class InterfaceMethods : public InterfaceMethodsBase {
public:
  InterfaceMethods(std::string s) : InterfaceMethodsBase(s) {}
  ~InterfaceMethods() {}
  std::vector<boost::shared_ptr<T>> pluginPtrs;
  void addPath(std::filesystem::path p) {
    boost::filesystem::path lib_path(p.string().c_str());
    std::cout << "PLUGIN: Loading " << p << "\n";
    boost::shared_ptr<T> plugin;
    try {
      plugin = boost::dll::import<T>(lib_path, pluginName,
                                     boost::dll::load_mode::default_mode);
    } catch (...) {
      std::cout << "PLUGIN: Loading FAILED " << p << "\n";
    }
    if (plugin) {
      std::cout << "PLUGIN: Loading SUCCESS " << p << "\n";
      pluginPtrs.push_back(plugin);
    }
  }
};

class PluginManager {
private:
  std::unordered_map<std::string, InterfaceMethodsBase *> interfaceMap;

public:
  template <class T> void addPluginInterface(std::string pluginName) {
    InterfaceMethods<T> *interface = new InterfaceMethods<T>(pluginName);
    InterfaceMethodsBase *interfaceBase = (InterfaceMethodsBase *)interface;
    interfaceMap.insert({pluginName, interface});
  }

  void loadPlugins(std::string directoryPathStr) {
    for (auto &p :
         std::filesystem::recursive_directory_iterator(directoryPathStr)) {
      std::cout << "PLUGIN: File Found " << p.path() << "\n";
      if (p.is_regular_file() &&
          (p.path().extension() == ".dll" || p.path().extension() == ".dylib" ||
           p.path().extension() == ".so")) {
        for (auto pairs : interfaceMap) {
          pairs.second->addPath(p.path());
        }
      }
    }
  }

  template <class T> boost::shared_ptr<T> getPlugin(std::string pluginName) {
    InterfaceMethods<T> *interface =
        dynamic_cast<InterfaceMethods<T> *>(interfaceMap.at(pluginName));
    if (interface->pluginPtrs.empty()) {
      return nullptr;
    }
    return interface->pluginPtrs.front();
  }
};

main. cpp

#include "PluginManager.hpp"
#include "PluginInterface.hpp"

int main(){
  PluginManager pluginManagerObj;
  pluginManagerObj.addPluginInterface<PluginInterface>("pluginName");
  pluginManagerObj.loadPlugins("plugins_directory");
  boost::shared_ptr<PluginInterface> plugin = pluginManagerObj.getPlugin<PluginInterface>("pluginName");
  plugin->testPlugin();
}

РЕДАКТИРОВАТЬ: я использую компилятор MinGW на windows

1 Ответ

1 голос
/ 14 февраля 2020

Мое первоначальное намерение состояло в том, чтобы найти способ для loadPlugins() интеллектуально найти и загрузить все плагины в каталоге и сохранить их дескрипторы для последующего использования.

После того, как задали начальный вопрос и возились с Из возможных решений я узнал, что могу использовать шаблоны для создания класса InterfaceMethods, который наследует InterfaceMethodsBase, который будет обрабатывать распознавание одного типа интерфейса и хранить все экземпляры класса в таблице типа ha sh типа InterfaceMethodsBase. После вызова loadPlugins() я смог извлечь обнаруженные плагины из таблицы ha sh.

Я отредактировал рабочий код обратно в исходное сообщение. Я надеюсь, что кто-то может извлечь выгоду из этого решения в будущем.

...