diff --git a/CMakeLists.txt b/CMakeLists.txt index 8047520391cb75d3f46acad5c87a720414f3c040..08782444aaad92cb5142f5940b19272dfea18249 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,12 +22,20 @@ if("${PUGS_SHORT_VERSION}" STREQUAL "") message(FATAL_ERROR "Unable to compute short version from PUGS_VERSION=${PUGS_VERSION}") endif() - -set(CMAKE_CONFIGURATION_TYPES "Release;Debug;Coverage" CACHE STRING INTERNAL FORCE ) - # 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(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -372,12 +380,14 @@ endif() #------------------------------------------------------ # Rang (colors? Useless thus necessary!) +add_subdirectory(${PUGS_SOURCE_DIR}/packages/rang/) include_directories(SYSTEM "${PUGS_SOURCE_DIR}/packages/rang/include") # CLI11 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 @@ -400,7 +410,7 @@ if(${PUGS_HAS_MPI}) endif() set(MPIEXEC_NUMPROC 3) set(MPIEXEC_PATH_FLAG --path) - set(MPI_LAUNCHER ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_NUMPROC} ${MPIEXEC_PATH_FLAG} ${PUGS_BINARY_DIR} ${MPIEXEC_OPTION_FLAGS}) + set(MPI_LAUNCHER ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_NUMPROC} ${MPIEXEC_OPTION_FLAGS}) endif() add_custom_target(all_unit_tests @@ -427,6 +437,7 @@ endif() add_custom_target(run_mpi_unit_tests COMMAND ${MPI_LAUNCHER} "${PUGS_BINARY_DIR}/mpi_unit_tests" + WORKING_DIRECTORY ${PUGS_BINARY_DIR} DEPENDS run_unit_tests COMMENT ${RUN_MPI_UNIT_TESTS_COMMENT} ) @@ -594,10 +605,6 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Coverage") endif() endif() -# ----------------------------------------------------- - -link_libraries("-rdynamic") - # ------------------- Source files -------------------- # Pugs binary add_executable( diff --git a/README.md b/README.md index 36e460a851a53d40b4ab442460594091fa22b20f..c859bc694043fc05a83ed47dae3f515eca0bbb42 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,10 @@ that are assembled together by a user friendly language. ## Requirements For the most basic build, `pugs` only requires -- a C++-17 compiler. +- a C++-20 compiler. - g++-10 or higher versions - - clang-10 or higher versions -- `CMake` (at least 3.16) + - clang-11 or higher versions +- `CMake` (at least 3.19) > **Warning**:<br> > Building `pugs` in its source directory is **forbidden**. Trying to diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eebccac12c3c1c7b80b6b1e13ff81d0e802a8def..30d920bb0c111049ae655f67e3951424134dbb01 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,21 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) #------------------------------------------------------ +install( + DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION "include" + FILES_MATCHING + PATTERN "*.hpp" +) + +install( + DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/" + DESTINATION "include" + FILES_MATCHING + PATTERN "*.hpp" + PATTERN "CMakeFiles" EXCLUDE +) + # Pugs utils add_subdirectory(utils) diff --git a/src/language/ast/ASTModulesImporter.cpp b/src/language/ast/ASTModulesImporter.cpp index 4cae0a921c139b3ae68a3decb0ce4f83876c4701..e1dc0043e689b506776540bb57e4851dc10883ae 100644 --- a/src/language/ast/ASTModulesImporter.cpp +++ b/src/language/ast/ASTModulesImporter.cpp @@ -26,10 +26,10 @@ ASTModulesImporter::_importModule(ASTNode& import_node) std::cout << " * importing '" << rang::fgB::green << module_name << rang::style::reset << "' module\n"; } - m_module_repository.populateSymbolTable(module_name_node, m_symbol_table); - m_module_repository.registerOperators(module_name); + ModuleRepository::getInstance().populateSymbolTable(module_name_node, m_symbol_table); + ModuleRepository::getInstance().registerOperators(module_name); if (CheckpointResumeRepository::isCreated()) { - m_module_repository.registerCheckpointResume(module_name); + ModuleRepository::getInstance().registerCheckpointResume(module_name); } } @@ -49,7 +49,7 @@ ASTModulesImporter::ASTModulesImporter(ASTNode& root_node) : m_symbol_table{*roo { Assert(root_node.is_root()); OperatorRepository::instance().reset(); - m_module_repository.populateMandatoryData(root_node, m_symbol_table); + ModuleRepository::getInstance().populateMandatoryData(root_node, m_symbol_table); this->_importAllModules(root_node); diff --git a/src/language/ast/ASTModulesImporter.hpp b/src/language/ast/ASTModulesImporter.hpp index 566155c4a19ecd00f0b049a29030c0036f212d8a..15ba8a7dc6cecbbb39bfb11c4d202d39200061a4 100644 --- a/src/language/ast/ASTModulesImporter.hpp +++ b/src/language/ast/ASTModulesImporter.hpp @@ -14,8 +14,6 @@ class ASTModulesImporter std::set<std::string> m_imported_modules; SymbolTable& m_symbol_table; - ModuleRepository m_module_repository; - void _importModule(ASTNode& import_node); void _importAllModules(ASTNode& node); @@ -23,7 +21,7 @@ class ASTModulesImporter const ModuleRepository& moduleRepository() const { - return m_module_repository; + return ModuleRepository::getInstance(); } ASTModulesImporter(ASTNode& root_node); diff --git a/src/language/modules/BinaryOperatorRegisterForVh.cpp b/src/language/modules/BinaryOperatorRegisterForVh.cpp index 3eb83537323d91bbf6266cbefebf4d004d74c2be..d1c20cb78718568a3535e30f0b5c9ce255be1db6 100644 --- a/src/language/modules/BinaryOperatorRegisterForVh.cpp +++ b/src/language/modules/BinaryOperatorRegisterForVh.cpp @@ -1,6 +1,6 @@ #include <language/modules/BinaryOperatorRegisterForVh.hpp> -#include <language/modules/SchemeModule.hpp> +#include <language/modules/SchemeModuleTypes.hpp> #include <language/utils/BinaryOperatorProcessorBuilder.hpp> #include <language/utils/DataHandler.hpp> #include <language/utils/DataVariant.hpp> diff --git a/src/language/modules/CoreModule.cpp b/src/language/modules/CoreModule.cpp index d7b331a1dc606a83cf77dfe405b184b9ff143308..47e0183256413b7579165b26364dff68f0614a74 100644 --- a/src/language/modules/CoreModule.cpp +++ b/src/language/modules/CoreModule.cpp @@ -42,7 +42,7 @@ #include <utils/checkpointing/ResumingManager.hpp> #include <utils/checkpointing/WriteOStream.hpp> -#include <random> +#include <language/modules/ModuleRepository.hpp> CoreModule::CoreModule() : BuiltinModule(true) { @@ -219,3 +219,5 @@ CoreModule::registerCheckpointResume() const #endif // PUGS_HAS_HDF5 } + +ModuleRepository::Subscribe<CoreModule> core_module; diff --git a/src/language/modules/DevUtilsModule.cpp b/src/language/modules/DevUtilsModule.cpp index 361b4357eda0ebbfe4350cc6c64bbe72cfaa0829..4595ea6c9d9a45431b303c00b4de6defdda38b7b 100644 --- a/src/language/modules/DevUtilsModule.cpp +++ b/src/language/modules/DevUtilsModule.cpp @@ -1,5 +1,7 @@ #include <language/modules/DevUtilsModule.hpp> +#include <language/modules/ModuleRepository.hpp> + #include <dev/ParallelChecker.hpp> #include <language/modules/MeshModuleTypes.hpp> #include <language/modules/SchemeModuleTypes.hpp> @@ -126,3 +128,5 @@ DevUtilsModule::registerOperators() const void DevUtilsModule::registerCheckpointResume() const {} + +ModuleRepository::Subscribe<DevUtilsModule> dev_utils_module; diff --git a/src/language/modules/LinearSolverModule.cpp b/src/language/modules/LinearSolverModule.cpp index aef6470d2455909f5ad2d307aa4e5cb859b8bcbb..d3e2de0faeb52c213f372e3a751f075ea2d735d7 100644 --- a/src/language/modules/LinearSolverModule.cpp +++ b/src/language/modules/LinearSolverModule.cpp @@ -1,5 +1,7 @@ #include <language/modules/LinearSolverModule.hpp> +#include <language/modules/ModuleRepository.hpp> + #include <algebra/LinearSolver.hpp> #include <language/utils/BuiltinFunctionEmbedder.hpp> #include <language/utils/TypeDescriptor.hpp> @@ -98,3 +100,5 @@ LinearSolverModule::registerOperators() const void LinearSolverModule::registerCheckpointResume() const {} + +ModuleRepository::Subscribe<LinearSolverModule> linear_solver_module; diff --git a/src/language/modules/MathFunctionRegisterForVh.cpp b/src/language/modules/MathFunctionRegisterForVh.cpp index b31fe47d0eba87ff2e7f0823a530bf170e410d6c..d9a30e86996a9cd6b99af63d64a8ab33264c7fe3 100644 --- a/src/language/modules/MathFunctionRegisterForVh.cpp +++ b/src/language/modules/MathFunctionRegisterForVh.cpp @@ -1,6 +1,7 @@ #include <language/modules/MathFunctionRegisterForVh.hpp> #include <language/modules/SchemeModule.hpp> +#include <language/modules/SchemeModuleTypes.hpp> #include <language/utils/BuiltinFunctionEmbedder.hpp> #include <language/utils/EmbeddedDiscreteFunctionMathFunctions.hpp> #include <scheme/DiscreteFunctionVariant.hpp> diff --git a/src/language/modules/MathModule.cpp b/src/language/modules/MathModule.cpp index 19a35a1529b1b65310c3c51d69fe4c5d02dc4d8a..1caea452428125e7a1c16aa88cb8278a5685fb35 100644 --- a/src/language/modules/MathModule.cpp +++ b/src/language/modules/MathModule.cpp @@ -1,5 +1,6 @@ #include <language/modules/MathModule.hpp> +#include <language/modules/ModuleRepository.hpp> #include <language/utils/BuiltinFunctionEmbedder.hpp> #include <cmath> @@ -136,3 +137,5 @@ MathModule::registerOperators() const void MathModule::registerCheckpointResume() const {} + +ModuleRepository::Subscribe<MathModule> math_module; diff --git a/src/language/modules/MeshModule.cpp b/src/language/modules/MeshModule.cpp index c76260ce58c75c130e4638054fc394458fedbf63..c060da50d6da17915937edda6f5403a9e604355e 100644 --- a/src/language/modules/MeshModule.cpp +++ b/src/language/modules/MeshModule.cpp @@ -1,5 +1,7 @@ #include <language/modules/MeshModule.hpp> +#include <language/modules/ModuleRepository.hpp> + #include <algebra/TinyVector.hpp> #include <language/node_processor/ExecutionPolicy.hpp> #include <language/utils/BinaryOperatorProcessorBuilder.hpp> @@ -160,27 +162,28 @@ MeshModule::MeshModule() )); - this - ->_addBuiltinFunction("interpolate", - std::function( + this->_addBuiltinFunction("interpolate", + std::function( - [](std::shared_ptr<const MeshVariant> mesh_v, std::shared_ptr<const ItemType> item_type, - const FunctionSymbolId& function_id) -> std::shared_ptr<const ItemValueVariant> { - return ItemValueVariantFunctionInterpoler{mesh_v, *item_type, function_id}.interpolate(); - } + [](std::shared_ptr<const MeshVariant> mesh_v, std::shared_ptr<const ItemType> item_type, + const FunctionSymbolId& function_id) -> std::shared_ptr<const ItemValueVariant> { + return ItemValueVariantFunctionInterpoler{mesh_v, *item_type, function_id} + .interpolate(); + } - )); + )); - this->_addBuiltinFunction( - "interpolate_array", - std::function( + this->_addBuiltinFunction("interpolate_array", + std::function( - [](std::shared_ptr<const MeshVariant> mesh_v, std::shared_ptr<const ItemType> item_type, - const std::vector<FunctionSymbolId>& function_id_list) -> std::shared_ptr<const ItemArrayVariant> { - return ItemArrayVariantFunctionInterpoler{mesh_v, *item_type, function_id_list}.interpolate(); - } + [](std::shared_ptr<const MeshVariant> mesh_v, std::shared_ptr<const ItemType> item_type, + const std::vector<FunctionSymbolId>& function_id_list) + -> std::shared_ptr<const ItemArrayVariant> { + return ItemArrayVariantFunctionInterpoler{mesh_v, *item_type, function_id_list} + .interpolate(); + } - )); + )); this->_addBuiltinFunction("transform", std::function( @@ -442,3 +445,5 @@ MeshModule::registerCheckpointResume() const #endif // PUGS_HAS_HDF5 } + +ModuleRepository::Subscribe<MeshModule> mesh_module; diff --git a/src/language/modules/ModuleRepository.cpp b/src/language/modules/ModuleRepository.cpp index 59689fb6fee512e45cd76c7c9d3cd5c11d543ee8..c9c487b67b5fdbf63d2b307baf1497519666a5d8 100644 --- a/src/language/modules/ModuleRepository.cpp +++ b/src/language/modules/ModuleRepository.cpp @@ -1,14 +1,6 @@ #include <language/modules/ModuleRepository.hpp> #include <language/ast/ASTNode.hpp> -#include <language/modules/CoreModule.hpp> -#include <language/modules/DevUtilsModule.hpp> -#include <language/modules/LinearSolverModule.hpp> -#include <language/modules/MathModule.hpp> -#include <language/modules/MeshModule.hpp> -#include <language/modules/SchemeModule.hpp> -#include <language/modules/SocketModule.hpp> -#include <language/modules/WriterModule.hpp> #include <language/utils/BasicAffectationRegistrerFor.hpp> #include <language/utils/BuiltinFunctionEmbedder.hpp> #include <language/utils/CheckpointResumeRepository.hpp> @@ -19,9 +11,29 @@ #include <utils/PugsAssert.hpp> -#include <algorithm> #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) { @@ -52,18 +64,6 @@ ModuleRepository::_subscribe(std::unique_ptr<IModule> m) Assert(success, "module has already been subscribed"); } -ModuleRepository::ModuleRepository() -{ - this->_subscribe(std::make_unique<CoreModule>()); - this->_subscribe(std::make_unique<LinearSolverModule>()); - this->_subscribe(std::make_unique<MathModule>()); - this->_subscribe(std::make_unique<MeshModule>()); - this->_subscribe(std::make_unique<SchemeModule>()); - this->_subscribe(std::make_unique<SocketModule>()); - this->_subscribe(std::make_unique<DevUtilsModule>()); - this->_subscribe(std::make_unique<WriterModule>()); -} - template <typename NameEmbedderMapT, typename EmbedderTableT> void ModuleRepository::_populateEmbedderTableT(const ASTNode& module_node, diff --git a/src/language/modules/ModuleRepository.hpp b/src/language/modules/ModuleRepository.hpp index 407d7b55bd9b7c8454159a315b9c2f7a256eecb6..35bf6f7aa6a7704f2804125c488ac0bf115ddf39 100644 --- a/src/language/modules/ModuleRepository.hpp +++ b/src/language/modules/ModuleRepository.hpp @@ -31,7 +31,23 @@ class ModuleRepository const IModule::NameValueMap& name_value_map, SymbolTable& symbol_table); + static ModuleRepository* m_instance; + public: + static ModuleRepository& getInstance(); + + static void destroy(); + + template <typename ModuleT> + struct Subscribe + { + Subscribe() + { + static_assert(std::is_base_of_v<IModule, ModuleT>, "module must inherit IModule interface"); + ModuleRepository::getInstance()._subscribe(std::make_unique<ModuleT>()); + } + }; + void populateSymbolTable(const ASTNode& module_name_node, SymbolTable& symbol_table); void populateMandatoryData(const ASTNode& root_node, SymbolTable& symbol_table); void registerOperators(const std::string& module_name); @@ -46,7 +62,10 @@ class ModuleRepository ModuleRepository(const ModuleRepository&) = delete; ModuleRepository(ModuleRepository&&) = delete; - ModuleRepository(); + private: + ModuleRepository() = default; + + public: ~ModuleRepository() = default; }; diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp index f1a7d8d73606a6cd71e4aa6b4f7253f8773a804e..40cc703cc6dcc0029da81366fb95134fc1329599 100644 --- a/src/language/modules/SchemeModule.cpp +++ b/src/language/modules/SchemeModule.cpp @@ -1,4 +1,7 @@ #include <language/modules/SchemeModule.hpp> +#include <language/modules/SchemeModuleTypes.hpp> + +#include <language/modules/ModuleRepository.hpp> #include <analysis/GaussLegendreQuadratureDescriptor.hpp> #include <analysis/GaussLobattoQuadratureDescriptor.hpp> @@ -809,3 +812,5 @@ SchemeModule::registerCheckpointResume() const #endif // PUGS_HAS_HDF5 } + +ModuleRepository::Subscribe<SchemeModule> scheme_module; diff --git a/src/language/modules/SchemeModule.hpp b/src/language/modules/SchemeModule.hpp index c61b3084406dbd8ae9889c79b4172195daaa6fe8..cf169175c4b46f7364799e16bdb4b84633d1f61c 100644 --- a/src/language/modules/SchemeModule.hpp +++ b/src/language/modules/SchemeModule.hpp @@ -2,7 +2,6 @@ #define SCHEME_MODULE_HPP #include <language/modules/BuiltinModule.hpp> -#include <language/modules/SchemeModuleTypes.hpp> class SchemeModule : public BuiltinModule { diff --git a/src/language/modules/SocketModule.cpp b/src/language/modules/SocketModule.cpp index 79321d088f960e0bb7450c82820cf6568e79d174..9c2ecdbe1b40730d0181d7f4ee6f3bf396f70a34 100644 --- a/src/language/modules/SocketModule.cpp +++ b/src/language/modules/SocketModule.cpp @@ -1,5 +1,7 @@ #include <language/modules/SocketModule.hpp> +#include <language/modules/ModuleRepository.hpp> + #include <language/utils/BinaryOperatorProcessorBuilder.hpp> #include <language/utils/BuiltinFunctionEmbedder.hpp> #include <language/utils/CheckpointResumeRepository.hpp> @@ -271,3 +273,5 @@ SocketModule::registerCheckpointResume() const throw NotImplementedError("checkpoint/resume with sockets"); })); } + +ModuleRepository::Subscribe<SocketModule> socket_module; diff --git a/src/language/modules/UnaryOperatorRegisterForVh.cpp b/src/language/modules/UnaryOperatorRegisterForVh.cpp index e2e9c2db9b72a9a687806d24dee836cfd37a22e8..3d52ab54687eabcd6162536d88325b3285d45e1f 100644 --- a/src/language/modules/UnaryOperatorRegisterForVh.cpp +++ b/src/language/modules/UnaryOperatorRegisterForVh.cpp @@ -1,6 +1,6 @@ #include <language/modules/UnaryOperatorRegisterForVh.hpp> -#include <language/modules/SchemeModule.hpp> +#include <language/modules/SchemeModuleTypes.hpp> #include <language/utils/DataHandler.hpp> #include <language/utils/DataVariant.hpp> #include <language/utils/EmbeddedDiscreteFunctionOperators.hpp> diff --git a/src/language/modules/WriterModule.cpp b/src/language/modules/WriterModule.cpp index 6d84506501de277f1970c13a7c24cd587ed79f20..e524a885639ac9a2a2da6330422565447bcb347d 100644 --- a/src/language/modules/WriterModule.cpp +++ b/src/language/modules/WriterModule.cpp @@ -1,7 +1,9 @@ #include <language/modules/WriterModule.hpp> -#include <language/modules/MeshModule.hpp> -#include <language/modules/SchemeModule.hpp> +#include <language/modules/ModuleRepository.hpp> + +#include <language/modules/MeshModuleTypes.hpp> +#include <language/modules/SchemeModuleTypes.hpp> #include <language/utils/BuiltinFunctionEmbedder.hpp> #include <language/utils/CheckpointResumeRepository.hpp> #include <language/utils/TypeDescriptor.hpp> @@ -242,3 +244,5 @@ WriterModule::registerCheckpointResume() const #endif // PUGS_HAS_HDF5 } + +ModuleRepository::Subscribe<WriterModule> writer_module{}; diff --git a/src/main.cpp b/src/main.cpp index a373bd2cd867b21b1d931449f12b64239ef03c22..cd576a9f63a8273b366a76a298b508e2fbb1ff54 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 13b0db80862c2b28e80dc18ff22951b08157db28..39e8cb35925fb1417222080e2ac0e060814ad353 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/ConsoleManager.hpp b/src/utils/ConsoleManager.hpp index a2afe46fbc0ad16e263d1f5a9b3f8a84d5202d94..693219e30285d1b0acae26d4b43d310882069784 100644 --- a/src/utils/ConsoleManager.hpp +++ b/src/utils/ConsoleManager.hpp @@ -1,7 +1,7 @@ #ifndef CONSOLE_MANAGER_HPP #define CONSOLE_MANAGER_HPP -#include <string> +#include <ostream> class ConsoleManager { diff --git a/src/utils/PluginsLoader.cpp b/src/utils/PluginsLoader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..35e24605e8a01b4d350aadb18bcacda313e9004c --- /dev/null +++ b/src/utils/PluginsLoader.cpp @@ -0,0 +1,104 @@ +#include <utils/PluginsLoader.hpp> + +#include <utils/ConsoleManager.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); + if (ConsoleManager::showPreamble()) { + std::cout << " * \"" << rang::fgB::green << plugin << rang::fg::reset << "\"\n"; + } + } else { + std::cerr << " " << 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::cerr << ' ' << 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) { + if (ConsoleManager::showPreamble()) { + std::cout << rang::style::bold << "Loading plugins" << rang::style::reset << '\n'; + } + for (auto&& plugin : plugin_vector) { + this->_open(plugin); + } + if (ConsoleManager::showPreamble()) { + 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 0000000000000000000000000000000000000000..76be25c6934c5f336360e938d9a40d75f075e6d3 --- /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 diff --git a/tools/generate-plugin.sh b/tools/generate-plugin.sh new file mode 100755 index 0000000000000000000000000000000000000000..a99f6976013582125f678a705a7a337dc5c3ac2d --- /dev/null +++ b/tools/generate-plugin.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +BOLD='\e[1m' +RESET='\e[0m' + +GREEN='\e[92m' +RED='\e[91m' +YELLOW='\e[93m' + +echo -ne ${BOLD} +echo -e "---------------------" +echo -e "pugs plugin generator" +echo -e "---------------------" +echo -e ${RESET} + +CURRENT_DIR="$(pwd -P)" +SCRIPT_DIR="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +PUGS_DIR="$(dirname ${SCRIPT_DIR})" + +if [[ "${CURRENT_DIR}" =~ "${PUGS_DIR}" ]] +then + echo -e ${RED}"Aborting..."${RESET} + echo -e "run this script outside of pugs sources" + exit 1 +fi + +NAME_RE='^[A-Z][a-zA-Z0-9]*$' + +echo " Plugin name must fulfill the following constrains:" +echo " - be a single word that starts by an upper case," +echo " - contains only letters or numbers," +echo " and preferably separate words with caps." +echo +echo " ex.: MyFirstPlugin" +echo + +while [[ ! "${PLUGIN_NAME}" =~ $NAME_RE ]] +do + echo -n "Give plugin name: " + read -r PLUGIN_NAME + + if [[ ! "${PLUGIN_NAME}" =~ $NAME_RE ]] + then + echo -e ${RED}" invalid name!"${RESET} + echo + unset PLUGIN_NAME + fi + +done + +PLUGIN_UP="${PLUGIN_NAME^^}" +PLUGIN_LOW="${PLUGIN_NAME,,}" +echo +echo -e "creating plugin ${YELLOW}${PLUGIN_NAME}${RESET} in directory ${YELLOW}${PLUGIN_LOW}${RESET}" +echo + +if [[ -e ${PLUGIN_LOW} ]] +then + echo -e ${RED}"Aborting..."${RESET} + echo -e "directory \"${PLUGIN_LOW}\" ${YELLOW}already exists${RESET}!" + exit 1 +fi + + +mkdir "${PLUGIN_LOW}" +mkdir "${PLUGIN_LOW}/cmake" + +cp "${PUGS_DIR}"/cmake/CheckNotInSources.cmake "${PLUGIN_LOW}"/cmake/ +cp "${PUGS_DIR}"/tools/plugin-template/FindPugs.cmake "${PLUGIN_LOW}"/cmake/ +cp "${PUGS_DIR}"/.gitignore "${PLUGIN_LOW}" +cp "${PUGS_DIR}"/.clang-format "${PLUGIN_LOW}" +cat "${PUGS_DIR}"/tools/plugin-template/CMakeLists.txt-template | sed s/_PLUGIN_NAME_/${PLUGIN_NAME}/g | sed s/_PLUGIN_LOW_/${PLUGIN_LOW}/g | sed s/_PLUGIN_UP_/${PLUGIN_UP}/g > "${PLUGIN_LOW}"/CMakeLists.txt +cat "${PUGS_DIR}"/tools/plugin-template/Module.hpp-template | sed s/_PLUGIN_NAME_/${PLUGIN_NAME}/g | sed s/_PLUGIN_LOW_/${PLUGIN_LOW}/g | sed s/_PLUGIN_UP_/${PLUGIN_UP}/g > "${PLUGIN_LOW}"/${PLUGIN_NAME}Module.hpp +cat "${PUGS_DIR}"/tools/plugin-template/Module.cpp-template | sed s/_PLUGIN_NAME_/${PLUGIN_NAME}/g | sed s/_PLUGIN_LOW_/${PLUGIN_LOW}/g | sed s/_PLUGIN_UP_/${PLUGIN_UP}/g > "${PLUGIN_LOW}"/${PLUGIN_NAME}Module.cpp +cat "${PUGS_DIR}"/tools/plugin-template/README.md-template | sed s/_PLUGIN_NAME_/${PLUGIN_NAME}/g | sed s/_PLUGIN_LOW_/${PLUGIN_LOW}/g | sed s/_PLUGIN_UP_/${PLUGIN_UP}/g > "${PLUGIN_LOW}"/README.md + +(cd "${PLUGIN_LOW}"; git init -q) +(cd "${PLUGIN_LOW}"; git add .) +(cd "${PLUGIN_LOW}"; git commit -m "init" -q) + +echo -e ${GREEN}"Creation finished successfully!"${RESET} diff --git a/tools/plugin-template/CMakeLists.txt-template b/tools/plugin-template/CMakeLists.txt-template new file mode 100644 index 0000000000000000000000000000000000000000..ae56000c37ed40cf18def1262e67554e0f5ee302 --- /dev/null +++ b/tools/plugin-template/CMakeLists.txt-template @@ -0,0 +1,95 @@ +cmake_minimum_required (VERSION 3.19) + +project("_PLUGIN_LOW_") + +# CMake utils +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +# Forbids in-source builds +include(CheckNotInSources) + +# use PkgConfig to find packages +find_package(PkgConfig REQUIRED) +find_package(Pugs REQUIRED) + +# ----------------------------------------------------- +# 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(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +#------------------------------------------------------ + +set(PUGS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") +set(PUGS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") + +# Add new build types +set(CMAKE_CXX_FLAGS_COVERAGE + "-g -O0 --coverage" + CACHE STRING "Flags used by the C++ compiler during coverage builds." + FORCE ) +set(CMAKE_C_FLAGS_COVERAGE + "-g -O0 --coverage" + CACHE STRING "Flags used by the C compiler during coverage builds." + FORCE ) +set(CMAKE_EXE_LINKER_FLAGS_COVERAGE + "--coverage" + CACHE STRING "Flags used for linking binaries during coverage builds." + FORCE ) +set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE + "--coverage" + CACHE STRING "Flags used by the shared libraries linker during coverage builds." + FORCE ) +mark_as_advanced( + CMAKE_CXX_FLAGS_COVERAGE + CMAKE_C_FLAGS_COVERAGE + CMAKE_EXE_LINKER_FLAGS_COVERAGE + CMAKE_SHARED_LINKER_FLAGS_COVERAGE ) + +if(CMAKE_BUILD_TYPE) + string(REGEX MATCH "^(Release|Debug|Coverage)$" VALID_BUILD_TYPE "${CMAKE_BUILD_TYPE}") + if(NOT VALID_BUILD_TYPE) + message(FATAL_ERROR "Invalid CMAKE_BUILD_TYPE: '${CMAKE_BUILD_TYPE}'") + endif() +endif() + +# Default build type is Release +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING + "Choose the type of build: Release Debug Coverage." + FORCE) +endif() + +#------------------------------------------------------ +# default build shared libraries +if (NOT BUILD_SHARED_LIBS) + set(BUILD_SHARED_LIBS ON CACHE STRING "" FORCE) +endif() + +#------------------------------------------------------ + +# Checks if compiler version is compatible with Pugs sources +set(GNU_CXX_MIN_VERSION "10.0.0") +set(CLANG_CXX_MIN_VERSION "11.0.0") + +#------------------------------------------------------ +# Change Kokkos namespace to avoid conflicts +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DKokkos=InlineKokkos") + +include_directories("${CMAKE_CURRENT_SOURCE_DIR}") +include_directories(SYSTEM "${PUGS_PREFIX_PATH}/include") +include_directories(SYSTEM "${PUGS_PREFIX_PATH}/include/kokkos") +include_directories(SYSTEM "${PUGS_PREFIX_PATH}/include/tao/") + +add_library(_PLUGIN_NAME_ + _PLUGIN_NAME_Module.cpp +) diff --git a/tools/plugin-template/FindPugs.cmake b/tools/plugin-template/FindPugs.cmake new file mode 100644 index 0000000000000000000000000000000000000000..6269bed8a9055339894cdd9fa9e63b2b479c9b70 --- /dev/null +++ b/tools/plugin-template/FindPugs.cmake @@ -0,0 +1,10 @@ +# Finds for the pugs installation directory + +find_path(PUGS_PREFIX_PATH include/utils/pugs_version.hpp + HINTS + $ENV{PUGS_INSTALL_DIR} + /usr/local/pugs + NO_DEFAULT_PATH +) + +find_package_handle_standard_args(Pugs REQUIRED_VARS PUGS_PREFIX_PATH ) diff --git a/tools/plugin-template/Module.cpp-template b/tools/plugin-template/Module.cpp-template new file mode 100644 index 0000000000000000000000000000000000000000..dd264e03631590e3cf0db152779e2118df86d474 --- /dev/null +++ b/tools/plugin-template/Module.cpp-template @@ -0,0 +1,28 @@ +#include <_PLUGIN_NAME_Module.hpp> + +#include <language/modules/ModuleRepository.hpp> +#include <language/utils/BuiltinFunctionEmbedder.hpp> + +_PLUGIN_NAME_Module::_PLUGIN_NAME_Module() : BuiltinModule(false) +{ + // Simple hello world example + this->_addBuiltinFunction("_PLUGIN_LOW__hello", std::function( + + []() -> void { std::cout << "_PLUGIN_NAME_: Hello world\n"; } + + )); +} + +void +_PLUGIN_NAME_Module::registerOperators() const +{ + // Kept empty for basic use +} + +void +_PLUGIN_NAME_Module::registerCheckpointResume() const +{ + // kept empty for basic use +} + +ModuleRepository::Subscribe<_PLUGIN_NAME_Module> _PLUGIN_LOW__module; diff --git a/tools/plugin-template/Module.hpp-template b/tools/plugin-template/Module.hpp-template new file mode 100644 index 0000000000000000000000000000000000000000..757e3b5e650390251d15515cfdcf26a9c970a102 --- /dev/null +++ b/tools/plugin-template/Module.hpp-template @@ -0,0 +1,22 @@ +#ifndef _PLUGIN_UP__MODULE_HPP +#define _PLUGIN_UP__MODULE_HPP + +#include <language/modules/BuiltinModule.hpp> + +class _PLUGIN_NAME_Module : public BuiltinModule +{ + public: + std::string_view + name() const final + { + return "_PLUGIN_LOW_"; + } + + void registerOperators() const final; + void registerCheckpointResume() const final; + + _PLUGIN_NAME_Module(); + ~_PLUGIN_NAME_Module() = default; +}; + +#endif // _PLUGIN_UP__MODULE_HPP diff --git a/tools/plugin-template/README.md-template b/tools/plugin-template/README.md-template new file mode 100644 index 0000000000000000000000000000000000000000..d89c74f974696b95dc875e5357007b5b67fba557 --- /dev/null +++ b/tools/plugin-template/README.md-template @@ -0,0 +1,67 @@ +`pugs`'s plugin `_PLUGIN_NAME_` +=============================== + +# Building `_PLUGIN_NAME_` + +## `pugs` installation + +Building this plugin requires an **installed** version of `pugs`. +`pugs` follows standard `cmake` installation recipes. + +Before building `pugs` one should define its installation directory. +In the `pugs` compilation directory one should execute +```shell +cmake -DCMAKE_INSTALL_PREFIX=pugs_install_dir ... +``` +where `pugs_install_dir` is the chosen installation directory. + +Then one simply runs +```shell +make install +``` + +## building the plugin `_PLUGIN_NAME_` + +> **Warning**:<br> +> Building `_PLUGIN_NAME_` in its source directory is +> **forbidden**. Trying to do so will result in a failure. However it +> generally leaves some garbage files in the source directory, namely +> the `CMakeCache.txt` and the `CMakeFiles` directory. `CMake` itself +> is not able to remove them, to avoid the risk of compilation issues, +> one has to dot it manually... + +In the build directory one runs +```shell +PUGS_INSTALL_DIR=pugs_install_dir cmake _PLUGIN_LOW__dir +``` +where `pugs_install_dir` has the same value as above and `_PLUGIN_LOW__dir` +is the directory that contains this `README.md` file. + +Then to build the plugin, one runs +```shell +make +``` + +If anything runs fine, the dynamic library `lib_PLUGIN_NAME_.so` is +built. + +# Using `_PLUGIN_NAME_` + +In order to use the created plugin, one simply has to give the +location of `lib_PLUGIN_NAME_.so` to `pugs`. This is done by means of +environment variables. There are two possibilities: +- `PUGS_PLUGIN` contains a semicolumn separated list of plugin + libraries, +- `PUGS_PLUGIN_DIR` contains a semicolumn separated list of path to + plugin libraries. + +Example +```shell +export PUGS_PLUGIN="/pathtoplugin/lib_PLUGIN_NAME_.so" +``` +or +```shell +export PUGS_PLUGIN_DIR="/pathtoplugin1;/pathtoplugin2" +``` + +Then one launches `pugs` classically.