From 16dc7bcf8cba9729ffc787e4d676defee8a7c39a Mon Sep 17 00:00:00 2001 From: Stephane Del Pino <stephane.delpino44@gmail.com> Date: Sun, 29 Dec 2024 22:00:11 +0100 Subject: [PATCH] Add plugin loading mechanism Plugins are loaded through environment variables. Two environment variables are read: PUGS_PLUGIN and PUGS_PLUGIN_DIR - PUGS_PLUGIN is a string literal that contains the filename of the dynamic library that contains plugins. One can provide multiple filename using semicolumn separators. ex. PUGS_PLUGIN="/path/to/my/libplugin1.so;/anotherpath/to/another/libplugin2.so" - PUGS_PLUGIN_DIR is a string literal that contains directory path where plugins (dynamic libraries) are. One can provide multiple path using semicolumn separators. All the dynamic libraries present at the locations are loaded! ex. PUGS_PLUGIN="/path/to/a/plugin/list/;/anotherpath/to/another/plugin/list/" --- CMakeLists.txt | 18 +++-- src/language/modules/ModuleRepository.cpp | 21 +++++ src/language/modules/ModuleRepository.hpp | 11 ++- src/main.cpp | 7 ++ src/utils/CMakeLists.txt | 1 + src/utils/PluginsLoader.cpp | 96 +++++++++++++++++++++++ src/utils/PluginsLoader.hpp | 23 ++++++ 7 files changed, 164 insertions(+), 13 deletions(-) create mode 100644 src/utils/PluginsLoader.cpp create mode 100644 src/utils/PluginsLoader.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 66f561885..08782444a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,12 +22,19 @@ if("${PUGS_SHORT_VERSION}" STREQUAL "") message(FATAL_ERROR "Unable to compute short version from PUGS_VERSION=${PUGS_VERSION}") endif() +# set project version as PUGS_SHORT_VERSION +project (Pugs VERSION ${PUGS_SHORT_VERSION}) + +# ----------------------------------------------------- +# dynamic libraries + +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +link_libraries("-rdynamic") set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") -set(CMAKE_CONFIGURATION_TYPES "Release;Debug;Coverage" CACHE STRING INTERNAL FORCE ) +#------------------------------------------------------ -# set project version as PUGS_SHORT_VERSION -project (Pugs VERSION ${PUGS_SHORT_VERSION}) +set(CMAKE_CONFIGURATION_TYPES "Release;Debug;Coverage" CACHE STRING INTERNAL FORCE ) #------------------------------------------------------ @@ -380,6 +387,7 @@ include_directories(SYSTEM "${PUGS_SOURCE_DIR}/packages/rang/include") include_directories(SYSTEM "${PUGS_SOURCE_DIR}/packages/CLI11/include") # PEGTL +add_subdirectory(${PUGS_SOURCE_DIR}/packages/PEGTL/) include_directories(SYSTEM "${PUGS_SOURCE_DIR}/packages/PEGTL/include/tao") # Pugs src @@ -597,10 +605,6 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Coverage") endif() endif() -# ----------------------------------------------------- - -link_libraries("-rdynamic") - # ------------------- Source files -------------------- # Pugs binary add_executable( diff --git a/src/language/modules/ModuleRepository.cpp b/src/language/modules/ModuleRepository.cpp index 42d62fa0a..c9c487b67 100644 --- a/src/language/modules/ModuleRepository.cpp +++ b/src/language/modules/ModuleRepository.cpp @@ -13,6 +13,27 @@ #include <set> +ModuleRepository* ModuleRepository::m_instance = nullptr; + +ModuleRepository& +ModuleRepository::getInstance() +{ + if (m_instance == nullptr) { + m_instance = new ModuleRepository; + } + + return *m_instance; +} + +void +ModuleRepository::destroy() +{ + if (m_instance != nullptr) { + delete m_instance; + m_instance = nullptr; + } +} + void ModuleRepository::_subscribe(std::unique_ptr<IModule> m) { diff --git a/src/language/modules/ModuleRepository.hpp b/src/language/modules/ModuleRepository.hpp index b2e217b93..35bf6f7aa 100644 --- a/src/language/modules/ModuleRepository.hpp +++ b/src/language/modules/ModuleRepository.hpp @@ -31,13 +31,12 @@ class ModuleRepository const IModule::NameValueMap& name_value_map, SymbolTable& symbol_table); + static ModuleRepository* m_instance; + public: - static ModuleRepository& - getInstance() - { - static ModuleRepository m_instance; - return m_instance; - } + static ModuleRepository& getInstance(); + + static void destroy(); template <typename ModuleT> struct Subscribe diff --git a/src/main.cpp b/src/main.cpp index a373bd2cd..cd576a9f6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,7 @@ #include <analysis/QuadratureManager.hpp> #include <dev/ParallelChecker.hpp> #include <language/PugsParser.hpp> +#include <language/modules/ModuleRepository.hpp> #include <mesh/DualConnectivityManager.hpp> #include <mesh/DualMeshManager.hpp> #include <mesh/MeshDataManager.hpp> @@ -11,6 +12,8 @@ #include <utils/RandomEngine.hpp> #include <utils/checkpointing/ResumingManager.hpp> +#include <utils/PluginsLoader.hpp> + int main(int argc, char* argv[]) { @@ -20,6 +23,8 @@ main(int argc, char* argv[]) std::string filename = initialize(argc, argv); + PluginsLoader plugins_loader; + SynchronizerManager::create(); RandomEngine::create(); QuadratureManager::create(); @@ -32,6 +37,8 @@ main(int argc, char* argv[]) parser(filename); ExecutionStatManager::printInfo(); + ModuleRepository::destroy(); + GlobalVariableManager::destroy(); DualMeshManager::destroy(); diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index 13b0db808..39e8cb359 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -16,6 +16,7 @@ add_library( Messenger.cpp Partitioner.cpp PETScWrapper.cpp + PluginsLoader.cpp PugsUtils.cpp RandomEngine.cpp ReproducibleSumManager.cpp diff --git a/src/utils/PluginsLoader.cpp b/src/utils/PluginsLoader.cpp new file mode 100644 index 000000000..8616c7a68 --- /dev/null +++ b/src/utils/PluginsLoader.cpp @@ -0,0 +1,96 @@ +#include <utils/PluginsLoader.hpp> + +#include <dlfcn.h> + +#include <rang.hpp> + +#include <filesystem> +#include <iostream> +#include <sstream> +#include <unistd.h> +#include <vector> + +std::vector<std::string> +split(const std::string& full_string) +{ + std::vector<std::string> split_string; + + std::stringstream is(full_string); + + std::string segment; + while (std::getline(is, segment, ';')) { + if (segment.size() > 0) { + split_string.push_back(segment); + } + } + return split_string; +} + +void +PluginsLoader::_open(const std::string& plugin) +{ + auto handle = dlopen(plugin.c_str(), RTLD_NOW); + if (handle != nullptr) { + m_dl_handler_stack.push(handle); + std::cout << " * \"" << rang::fgB::green << plugin << rang::fg::reset << "\"\n"; + } else { + std::cout << " " << rang::fgB::red << "cannot load " << rang::fg::reset << '\"' << rang::fgB::yellow << plugin + << rang::fg::reset << "\"\n"; + } +} + +PluginsLoader::PluginsLoader() +{ + std::vector<std::string> plugin_vector; + + { + char* env = getenv("PUGS_PLUGIN"); + if (env != nullptr) { + std::string plugins = env; + plugin_vector = split(plugins); + } + } + + { + char* env = getenv("PUGS_PLUGIN_DIR"); + if (env != nullptr) { + std::string paths = env; + std::vector<std::string> path_vector = split(paths); + for (auto&& path : path_vector) { + if (access(path.c_str(), R_OK) == -1) { + std::cout << ' ' << rang::fgB::red << 'X' << rang::fg::reset << " cannot access plugin dir \"" + << rang::fgB::yellow << path << rang::fg::reset << "\"\n"; + } else { + for (auto&& entry : + std::filesystem::directory_iterator(path, + (std::filesystem::directory_options::follow_directory_symlink | + std::filesystem::directory_options::skip_permission_denied))) { + if (entry.path().extension() == ".so") { + plugin_vector.push_back(entry.path().string()); + } + } + } + } + } + } + + // keep unique entries + std::sort(plugin_vector.begin(), plugin_vector.end()); + plugin_vector.resize(std::distance(plugin_vector.begin(), std::unique(plugin_vector.begin(), plugin_vector.end()))); + + if (plugin_vector.size() > 0) { + std::cout << rang::style::bold << "Loading plugins" << rang::style::reset << '\n'; + for (auto&& plugin : plugin_vector) { + this->_open(plugin); + } + std::cout << "-------------------------------------------------------\n"; + } +} + +PluginsLoader::~PluginsLoader() +{ + while (not m_dl_handler_stack.empty()) { + dlclose(m_dl_handler_stack.top()); + m_dl_handler_stack.pop(); + } +} diff --git a/src/utils/PluginsLoader.hpp b/src/utils/PluginsLoader.hpp new file mode 100644 index 000000000..76be25c69 --- /dev/null +++ b/src/utils/PluginsLoader.hpp @@ -0,0 +1,23 @@ +#ifndef PLUGINS_LOADER_HPP +#define PLUGINS_LOADER_HPP + +#include <stack> +#include <string> + +class PluginsLoader +{ + private: + std::stack<void*> m_dl_handler_stack; + + void _open(const std::string& filename); + + public: + PluginsLoader(); + + PluginsLoader(const PluginsLoader&) = delete; + PluginsLoader(PluginsLoader&&) = delete; + + ~PluginsLoader(); +}; + +#endif // PLUGINS_LOADER_HPP -- GitLab