From 24a961001509e5d25bcbd59f706799f824b69151 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Tue, 31 Dec 2024 10:59:11 +0100
Subject: [PATCH] Add template plugin generation tool and its self
 documentation

---
 tools/generate-plugin.sh                      | 81 ++++++++++++++++
 tools/plugin-template/CMakeLists.txt-template | 95 +++++++++++++++++++
 tools/plugin-template/FindPugs.cmake          | 10 ++
 tools/plugin-template/Module.cpp-template     | 28 ++++++
 tools/plugin-template/Module.hpp-template     | 22 +++++
 tools/plugin-template/README.md-template      | 67 +++++++++++++
 6 files changed, 303 insertions(+)
 create mode 100755 tools/generate-plugin.sh
 create mode 100644 tools/plugin-template/CMakeLists.txt-template
 create mode 100644 tools/plugin-template/FindPugs.cmake
 create mode 100644 tools/plugin-template/Module.cpp-template
 create mode 100644 tools/plugin-template/Module.hpp-template
 create mode 100644 tools/plugin-template/README.md-template

diff --git a/tools/generate-plugin.sh b/tools/generate-plugin.sh
new file mode 100755
index 000000000..a99f69760
--- /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 000000000..ae56000c3
--- /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 000000000..6269bed8a
--- /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 000000000..dd264e036
--- /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 000000000..757e3b5e6
--- /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 000000000..d89c74f97
--- /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.
-- 
GitLab