Skip to content

Source · fairmq/

PluginManager.hpublic header

Defines class fair::mq::PluginManager, struct fair::mq::PluginManager::BadSearchPath, struct fair::mq::PluginManager::PluginInstantiationError, struct fair::mq::PluginManager::PluginLoadError, struct fair::mq::PluginManager::PluginNotFound, struct fair::mq::PluginManager::ProgramOptionsParseError.

Described in Plugins and control, custom-controller: control from code, dds: run with DDS, Control a device from code, Write a plugin, Command-line options.

1/********************************************************************************2 * Copyright (C) 2017-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH  *3 *                                                                              *4 *              This software is distributed under the terms of the             *5 *              GNU Lesser General Public Licence (LGPL) version 3,             *6 *                  copied verbatim in the file "LICENSE"                       *7 ********************************************************************************/8 9#ifndef FAIR_MQ_PLUGINMANAGER_H10#define FAIR_MQ_PLUGINMANAGER_H11 12#include <fairmq/Plugin.h>13#include <fairmq/PluginServices.h>14#include <fairmq/tools/Strings.h>15 16#if FAIRMQ_HAS_STD_FILESYSTEM17#include <filesystem>18namespace fs = std::filesystem;19#else20#define BOOST_FILESYSTEM_VERSION 321#define BOOST_FILESYSTEM_NO_DEPRECATED22#include <boost/filesystem.hpp>23namespace fs = ::boost::filesystem;24#endif25 26#include <boost/optional.hpp>27#include <boost/program_options.hpp>28#include <boost/dll/import.hpp>29#include <boost/dll/shared_library.hpp>30#include <boost/dll/runtime_symbol_info.hpp>31 32#include <functional>33#include <map>34#include <memory>35#include <stdexcept>36#include <string>37#include <vector>38#include <utility> // forward39 40namespace fair::mq41{42 43/**44 * @class PluginManager PluginManager.h <fairmq/PluginManager.h>45 * @brief manages and owns plugin instances46 *47 * The plugin manager is responsible for the whole plugin lifecycle. It48 * facilitates two plugin mechanisms:49 * A prelinked dynamic plugins (shared libraries)50 * B dynamic plugins (shared libraries)51 * C static plugins (builtin)52 */53class PluginManager54{55  public:56    using PluginFactory = std::unique_ptr<fair::mq::Plugin>(PluginServices&);57 58    PluginManager();59    PluginManager(const PluginManager&) = delete;60    PluginManager(PluginManager&&) = delete;61    PluginManager& operator=(const PluginManager&) = delete;62    PluginManager& operator=(PluginManager&&) = delete;63    PluginManager(const std::vector<std::string>& args);64 65    ~PluginManager()66    {67        LOG(debug) << "Shutting down Plugin Manager";68    }69 70    auto SetSearchPaths(const std::vector<fs::path>&) -> void;71    auto AppendSearchPath(const fs::path&) -> void;72    auto PrependSearchPath(const fs::path&) -> void;73    auto SearchPaths() const -> const std::vector<fs::path>& { return fSearchPaths; }74    struct BadSearchPath : std::invalid_argument { using std::invalid_argument::invalid_argument; };75 76    auto SearchPluginFile(const std::string&) const -> fs::path;77    struct PluginNotFound : std::runtime_error { using std::runtime_error::runtime_error; };78    auto LoadPlugin(const std::string& pluginName) -> void;79    auto LoadPlugins(const std::vector<std::string>& pluginNames) -> void { for(const auto& pluginName : pluginNames) { LoadPlugin(pluginName); } }80    struct PluginLoadError : std::runtime_error { using std::runtime_error::runtime_error; };81    auto InstantiatePlugins() -> void;82    struct PluginInstantiationError : std::runtime_error { using std::runtime_error::runtime_error; };83 84    static auto ProgramOptions() -> boost::program_options::options_description;85    struct ProgramOptionsParseError : std::runtime_error { using std::runtime_error::runtime_error; };86 87    static auto LibPrefix() -> const std::string& { return fgkLibPrefix; }88 89    auto ForEachPlugin(std::function<void (Plugin&)> func) -> void { for(const auto& p : fPluginOrder) { func(*fPlugins[p]); } }90    auto ForEachPluginProgOptions(std::function<void (boost::program_options::options_description)> func) const -> void { for(const auto& pair : fPluginProgOptions) { func(pair.second); } }91 92    template<typename... Args>93    auto EmplacePluginServices(Args&&... args) -> void { fPluginServices = std::make_unique<PluginServices>(std::forward<Args>(args)...); }94 95    auto WaitForPluginsToReleaseDeviceControl() -> void { fPluginServices->WaitForReleaseDeviceControl(); }96 97  private:98    static auto ValidateSearchPath(const fs::path&) -> void;99 100    auto LoadPluginPrelinkedDynamic(const std::string& pluginName) -> void;101    auto LoadPluginDynamic(const std::string& pluginName) -> void;102    auto LoadPluginStatic(const std::string& pluginName) -> void;103#if FAIRMQ_HAS_STD_FILESYSTEM104    template<typename T>105    static auto AdaptPathType(T&& path)106    {107        if constexpr(std::is_same_v<T, std::filesystem::path>) {108            return boost::filesystem::path(std::forward<T>(path));109        } else {110            return std::forward<T>(path);111        }112    }113#endif114    template<typename FirstArg, typename... Args>115    auto LoadSymbols(const std::string& pluginName, FirstArg&& farg, Args&&... args) -> void116    {117        using namespace boost::dll;118        using fair::mq::tools::ToString;119 120#if FAIRMQ_HAS_STD_FILESYSTEM121        auto lib = shared_library{AdaptPathType(std::forward<FirstArg>(farg)), std::forward<Args>(args)...};122#else123        auto lib = shared_library{std::forward<FirstArg>(farg), std::forward<Args>(args)...};124#endif125        fgDLLKeepAlive.push_back(lib);126 127        fPluginFactories[pluginName] = import_alias<PluginFactory>(128            shared_library{lib},129            ToString("make_", pluginName, "_plugin")130        );131 132        try133        {134            fPluginProgOptions.insert({135                pluginName,136                lib.get_alias<Plugin::ProgOptions()>(ToString("get_", pluginName, "_plugin_progoptions"))().value()137            });138        }139        catch (const boost::bad_optional_access& e) { /* just ignore, if no prog options are declared */ }140    }141 142    auto InstantiatePlugin(const std::string& pluginName) -> void;143 144    static const std::string fgkLibPrefix;145    static const std::string fgkLibPrefixAlt;146    std::vector<fs::path> fSearchPaths;147    static std::vector<boost::dll::shared_library> fgDLLKeepAlive; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)148    std::map<std::string, std::function<PluginFactory>> fPluginFactories;149    std::unique_ptr<PluginServices> fPluginServices;150    std::map<std::string, std::unique_ptr<Plugin>> fPlugins;151    std::vector<std::string> fPluginOrder;152    std::map<std::string, boost::program_options::options_description> fPluginProgOptions;153}; /* class PluginManager */154 155} // namespace fair::mq156 157#endif /* FAIR_MQ_PLUGINMANAGER_H */