From 125ae33ccfa4aa97212607bab3487fb4193d015e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 16 Mar 2021 22:43:13 -0400 Subject: [PATCH] convert plugin functionality into a package --- cmake/CMakeLists.txt | 19 +++++-- cmake/presets/most.cmake | 2 +- lib/README | 20 ++++--- lib/plugin/README | 16 ++++++ src/.gitignore | 4 ++ src/MAKE/Makefile.mpi | 2 +- src/MAKE/Makefile.serial | 2 +- src/Makefile | 2 +- src/PLUGIN/Install.sh | 64 ++++++++++++++++++++++ src/PLUGIN/README | 12 ++++ src/{ => PLUGIN}/plugin.cpp | 49 +++++++++++++++++ src/{ => PLUGIN}/plugin.h | 15 ++++- src/input.cpp | 30 ---------- src/library.cpp | 8 +++ unittest/commands/CMakeLists.txt | 2 +- unittest/commands/test_simple_commands.cpp | 2 + 16 files changed, 198 insertions(+), 51 deletions(-) create mode 100644 lib/plugin/README create mode 100755 src/PLUGIN/Install.sh create mode 100644 src/PLUGIN/README rename src/{ => PLUGIN}/plugin.cpp (87%) rename src/{ => PLUGIN}/plugin.h (84%) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 7081d6aa80..f05c7f97eb 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -113,7 +113,7 @@ option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF) set(STANDARD_PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS DIPOLE GRANULAR KSPACE LATTE MANYBODY MC MESSAGE MISC MLIAP MOLECULE PERI POEMS - QEQ REPLICA RIGID SHOCK SPIN SNAP SRD KIM PYTHON MSCG MPIIO VORONOI + PLUGIN QEQ REPLICA RIGID SHOCK SPIN SNAP SRD KIM PYTHON MSCG MPIIO VORONOI USER-ADIOS USER-ATC USER-AWPMD USER-BOCS USER-CGDNA USER-MESODPD USER-CGSDK USER-COLVARS USER-DIFFRACTION USER-DPD USER-DRUDE USER-EFF USER-FEP USER-H5MD USER-LB USER-MANIFOLD USER-MEAMC USER-MESONT USER-MGPT USER-MISC USER-MOFFF @@ -240,11 +240,6 @@ if(BUILD_OMP) target_link_libraries(lammps PRIVATE OpenMP::OpenMP_CXX) endif() -# link with -ldl or equivalent for plugin loading; except on Windows -if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - target_link_libraries(lammps PRIVATE ${CMAKE_DL_LIBS}) -endif() - # Compiler specific features for testing if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") option(ENABLE_COVERAGE "Enable collecting code coverage data" OFF) @@ -538,6 +533,18 @@ foreach(PKG_WITH_INCL CORESHELL QEQ USER-OMP USER-SDPD KOKKOS OPT USER-INTEL GPU endif() endforeach() +if(PKG_PLUGIN) + if(BUILD_SHARED_LIBS) + target_compile_definitions(lammps PRIVATE -DLMP_PLUGIN) + else() + message(WARNING "Plugin loading will not work unless BUILD_SHARED_LIBS is enabled") + endif() + # link with -ldl or equivalent for plugin loading; except on Windows + if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + target_link_libraries(lammps PRIVATE ${CMAKE_DL_LIBS}) + endif() +endif() + ###################################################################### # the windows version of LAMMPS requires a couple extra libraries # and the MPI library - if use - has to be linked right before those diff --git a/cmake/presets/most.cmake b/cmake/presets/most.cmake index bddefc077b..5dc58b735b 100644 --- a/cmake/presets/most.cmake +++ b/cmake/presets/most.cmake @@ -4,7 +4,7 @@ set(ALL_PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR KSPACE MANYBODY MC MISC MLIAP MOLECULE OPT PERI - POEMS PYTHON QEQ REPLICA RIGID SHOCK SNAP SPIN SRD VORONOI + PLUGIN POEMS PYTHON QEQ REPLICA RIGID SHOCK SNAP SPIN SRD VORONOI USER-BOCS USER-CGDNA USER-CGSDK USER-COLVARS USER-DIFFRACTION USER-DPD USER-DRUDE USER-EFF USER-FEP USER-MEAMC USER-MESODPD USER-MISC USER-MOFFF USER-OMP USER-PHONON USER-REACTION diff --git a/lib/README b/lib/README index d89490e202..26c3fad9e0 100644 --- a/lib/README +++ b/lib/README @@ -19,12 +19,12 @@ atc atomistic-to-continuum methods, USER-ATC package from Reese Jones, Jeremy Templeton, Jon Zimmerman (Sandia) awpmd antisymmetrized wave packet molecular dynamics, AWPMD package from Ilya Valuev (JIHT RAS) -colvars collective variable module (Metadynamics, ABF and more) +colvars collective variable module (Metadynamics, ABF and more) from Giacomo Fiorin and Jerome Henin (ICMS, Temple U) compress hook to system lib for performing I/O compression, COMPRESS pkg - from Axel Kohlmeyer (Temple U) -gpu general GPU routines, GPU package - from Mike Brown (ORNL) + from Axel Kohlmeyer (Temple U) +gpu general GPU routines, GPU package + from Mike Brown (ORNL) h5md ch5md library for output of MD data in HDF5 format from Pierre de Buyl (KU Leuven) kim hooks to the KIM library, used by KIM package @@ -32,26 +32,28 @@ kim hooks to the KIM library, used by KIM package kokkos Kokkos package for GPU and many-core acceleration from Kokkos development team (Sandia) linalg set of BLAS and LAPACK routines needed by USER-ATC package - from Axel Kohlmeyer (Temple U) + from Axel Kohlmeyer (Temple U) message client/server communication library via MPI, sockets, files - from Steve Plimpton (Sandia) + from Steve Plimpton (Sandia) molfile hooks to VMD molfile plugins, used by the USER-MOLFILE package from Axel Kohlmeyer (Temple U) and the VMD development team mscg hooks to the MSCG library, used by fix_mscg command from Jacob Wagner and Greg Voth group (U Chicago) netcdf hooks to a NetCDF library installed on your system from Lars Pastewka (Karlsruhe Institute of Technology) -poems POEMS rigid-body integration package, POEMS package +plugin settings to load styles into LAMMPS from plugins + from Axel Kohlmeyer (Temple U) +poems POEMS rigid-body integration package, POEMS package from Rudranarayan Mukherjee (RPI) python hooks to the system Python library, used by the PYTHON package from the LAMMPS development team -qmmm quantum mechanics/molecular mechanics coupling interface +qmmm quantum mechanics/molecular mechanics coupling interface from Axel Kohlmeyer (Temple U) quip interface to QUIP/libAtoms framework, USER-QUIP package from Albert Bartok-Partay and Gabor Csanyi (U Cambridge) smd hooks to Eigen library, used by USER-SMD package from Georg Ganzenmueller (Ernst Mach Institute, Germany) voronoi hooks to the Voro++ library, used by compute voronoi/atom command - from Daniel Schwen (LANL) + from Daniel Schwen (LANL) vtk hooks to the VTK library, used by dump custom/vtk command from Richard Berger (JKU) diff --git a/lib/plugin/README b/lib/plugin/README new file mode 100644 index 0000000000..15abea011d --- /dev/null +++ b/lib/plugin/README @@ -0,0 +1,16 @@ +This directory has a Makefile.lammps file with settings that allows +LAMMPS to dynamically link LAMMPS plugins. More details about this +are in the manual. + +In order to be able to dynamically load and execute the plugins from +inside LAMMPS, you need to link with a system library containing functions +like dlopen(), dlsym() and so on for dynamic linking of executable code +into an executable. This library is defined by setting the plugin_SYSLIB +variable in the Makefile.lammps file in this dir. For this mechanism +to work, LAMMPS must be built as a shared library (i.e. with mode=shared). + +For Linux and most current unix-like operating systems, this can be +kept at the default setting of "-ldl" (on some platforms this library +is called "-ldld"). The Windows platform is currently not supported. + +See the header of Makefile.lammps for more info. diff --git a/src/.gitignore b/src/.gitignore index 45ec71e485..6fa3aef513 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -172,6 +172,10 @@ /pair_lj_charmmfsw_coul_long.cpp /pair_lj_charmmfsw_coul_long.h +/plugin.cpp +/plugin.h +/lammpsplugin.h + /atom_vec_spin.cpp /atom_vec_spin.h /compute_spin.cpp diff --git a/src/MAKE/Makefile.mpi b/src/MAKE/Makefile.mpi index 68e79e9e8e..9776b0153e 100644 --- a/src/MAKE/Makefile.mpi +++ b/src/MAKE/Makefile.mpi @@ -13,7 +13,7 @@ DEPFLAGS = -M LINK = mpicxx LINKFLAGS = -g -O3 -LIB = -ldl +LIB = SIZE = size ARCHIVE = ar diff --git a/src/MAKE/Makefile.serial b/src/MAKE/Makefile.serial index 8b4e2e5982..0f5952f317 100644 --- a/src/MAKE/Makefile.serial +++ b/src/MAKE/Makefile.serial @@ -13,7 +13,7 @@ DEPFLAGS = -M LINK = g++ LINKFLAGS = -g -O -LIB = -ldl +LIB = SIZE = size ARCHIVE = ar diff --git a/src/Makefile b/src/Makefile index 679cbe7b97..a63c49e344 100644 --- a/src/Makefile +++ b/src/Makefile @@ -48,7 +48,7 @@ endif PACKAGE = asphere body class2 colloid compress coreshell dipole gpu \ granular kim kokkos kspace latte manybody mc message misc \ - mliap molecule mpiio mscg opt peri poems \ + mliap molecule mpiio mscg opt peri plugin poems \ python qeq replica rigid shock snap spin srd voronoi PACKUSER = user-adios user-atc user-awpmd user-bocs user-cgdna user-cgsdk user-colvars \ diff --git a/src/PLUGIN/Install.sh b/src/PLUGIN/Install.sh new file mode 100755 index 0000000000..0df642193e --- /dev/null +++ b/src/PLUGIN/Install.sh @@ -0,0 +1,64 @@ +# Install/unInstall package files in LAMMPS +# mode = 0/1/2 for uninstall/install/update + +mode=$1 + +# enforce using portable C locale +LC_ALL=C +export LC_ALL + +# arg1 = file, arg2 = file it depends on + +action () { + if (test $mode = 0) then + rm -f ../$1 + elif (! cmp -s $1 ../$1) then + if (test -z "$2" || test -e ../$2) then + cp $1 .. + if (test $mode = 2) then + echo " updating src/$1" + fi + fi + elif (test -n "$2") then + if (test ! -e ../$2) then + rm -f ../$1 + fi + fi +} + +# all package files with no dependencies + +for file in *.cpp *.h; do + test -f ${file} && action $file +done + +# edit 2 Makefile.package files to include/exclude package info + +if (test $1 = 1) then + + if (test -e ../Makefile.package) then + sed -i -e 's/[^ \t]*plugin[^ \t]* //' ../Makefile.package + sed -i -e 's|^PKG_SYSINC =[ \t]*|&$(plugin_SYSINC) |' ../Makefile.package + sed -i -e 's|^PKG_SYSLIB =[ \t]*|&$(plugin_SYSLIB) |' ../Makefile.package + sed -i -e 's|^PKG_SYSPATH =[ \t]*|&$(plugin_SYSPATH) |' ../Makefile.package + fi + + if (test -e ../Makefile.package.settings) then + sed -i -e '/^include.*plugin.*$/d' ../Makefile.package.settings + # multiline form needed for BSD sed on Macs + sed -i -e '4 i \ +include ..\/..\/lib\/plugin\/Makefile.lammps +' ../Makefile.package.settings + fi + +elif (test $1 = 0) then + + if (test -e ../Makefile.package) then + sed -i -e 's/[^ \t]*plugin[^ \t]* //' ../Makefile.package + fi + + if (test -e ../Makefile.package.settings) then + sed -i -e '/^include.*plugin.*$/d' ../Makefile.package.settings + fi + +fi diff --git a/src/PLUGIN/README b/src/PLUGIN/README new file mode 100644 index 0000000000..4515428e35 --- /dev/null +++ b/src/PLUGIN/README @@ -0,0 +1,12 @@ +This package provides a plugin command that can load LAMMPS +styles linked into shared object files into a LAMMPS binary +at run time without having to recompile and relink LAMMPS. +For more details please see the LAMMPS manual. + +To be able to dynamically load and execute the plugins from inside +LAMMPS, you need to link with an appropriate system library, which +is done using the settings in lib/plugin/Makefile.lammps. See +that file and the lib/plugin/README file for more details. + +The person who created this package is Axel Kohlmeyer at Temple U +(akohlmey at gmail.com). Contact him directly if you have questions. diff --git a/src/plugin.cpp b/src/PLUGIN/plugin.cpp similarity index 87% rename from src/plugin.cpp rename to src/PLUGIN/plugin.cpp index e252ce67e1..1449d0d90f 100644 --- a/src/plugin.cpp +++ b/src/PLUGIN/plugin.cpp @@ -38,9 +38,53 @@ namespace LAMMPS_NS // map for counting references to dso handles static std::map dso_refcounter; + +/* ---------------------------------------------------------------------- */ + + Plugin::Plugin(LAMMPS *lmp) : Pointers(lmp) {} + +/* ---------------------------------------------------------------------- */ + + void Plugin::command(int narg, char **arg) + { + if (narg < 1) error->all(FLERR,"Illegal plugin command"); + +#if defined(LMP_PLUGIN) + std::string cmd = arg[0]; + if (cmd == "load") { + if (narg < 2) error->all(FLERR,"Illegal plugin load command"); + for (int i=1; i < narg; ++i) + plugin_load(arg[i],lmp); + + } else if (cmd == "unload") { + if (narg != 3) error->all(FLERR,"Illegal plugin unload command"); + plugin_unload(arg[1],arg[2],lmp); + + } else if (cmd == "clear") { + plugin_clear(lmp); + + } else if (cmd == "list") { + if (comm->me == 0) { + int num = plugin_get_num_plugins(); + utils::logmesg(lmp,"Currently loaded plugins\n"); + for (int i=0; i < num; ++i) { + auto entry = plugin_get_info(i); + utils::logmesg(lmp,fmt::format("{:4}: {} style plugin {}\n", + i+1,entry->style,entry->name)); + } + } + } else error->all(FLERR,"Illegal plugin command"); +#else + if (comm->me == 0) + error->warning(FLERR,"Ignoring plugin command. LAMMPS must be built as " + "a shared library for it to work."); +#endif + } + // load DSO and call included registration function void plugin_load(const char *file, LAMMPS *lmp) { +#if defined(LMP_PLUGIN) int me = lmp->comm->me; #if defined(WIN32) lmp->error->all(FLERR,"Loading of plugins on Windows is not supported\n"); @@ -77,6 +121,7 @@ namespace LAMMPS_NS (*(lammpsplugin_initfunc)(initfunc))((void *)lmp, dso, (void *)&plugin_register); +#endif #endif } @@ -89,6 +134,7 @@ namespace LAMMPS_NS void plugin_register(lammpsplugin_t *plugin, void *ptr) { +#if defined(LMP_PLUGIN) LAMMPS *lmp = (LAMMPS *)ptr; int me = lmp->comm->me; @@ -158,6 +204,7 @@ namespace LAMMPS_NS "yet implemented\n",pstyle)); pluginlist.pop_back(); } +#endif } /* -------------------------------------------------------------------- @@ -168,6 +215,7 @@ namespace LAMMPS_NS void plugin_unload(const char *style, const char *name, LAMMPS *lmp) { +#if defined(LMP_PLUGIN) int me = lmp->comm->me; // ignore unload request from unsupported style categories @@ -246,6 +294,7 @@ namespace LAMMPS_NS dlclose(handle); #endif } +#endif } /* -------------------------------------------------------------------- diff --git a/src/plugin.h b/src/PLUGIN/plugin.h similarity index 84% rename from src/plugin.h rename to src/PLUGIN/plugin.h index 90952224a6..946b08db1a 100644 --- a/src/plugin.h +++ b/src/PLUGIN/plugin.h @@ -11,14 +11,26 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#ifdef COMMAND_CLASS + +CommandStyle(plugin,Plugin) + +#else + #ifndef LMP_PLUGIN_H #define LMP_PLUGIN_H #include "lammpsplugin.h" +#include "pointers.h" namespace LAMMPS_NS { - class LAMMPS; + + class Plugin : protected Pointers { + public: + Plugin(class LAMMPS *); + void command(int, char **); + }; void plugin_load(const char *, LAMMPS *); void plugin_register(lammpsplugin_t *, void *); @@ -33,3 +45,4 @@ namespace LAMMPS_NS } #endif +#endif diff --git a/src/input.cpp b/src/input.cpp index 9979bb7705..eeb211a6d1 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -35,7 +35,6 @@ #include "neighbor.h" #include "output.h" #include "pair.h" -#include "plugin.h" #include "special.h" #include "style_command.h" #include "thermo.h" @@ -718,7 +717,6 @@ int Input::execute_command() else if (!strcmp(command,"log")) log(); else if (!strcmp(command,"next")) next_command(); else if (!strcmp(command,"partition")) partition(); - else if (!strcmp(command,"plugin")) plugin(); else if (!strcmp(command,"print")) print(); else if (!strcmp(command,"python")) python(); else if (!strcmp(command,"quit")) quit(); @@ -1097,34 +1095,6 @@ void Input::partition() /* ---------------------------------------------------------------------- */ -void Input::plugin() -{ - if (narg < 1) error->all(FLERR,"Illegal plugin command"); - std::string cmd = arg[0]; - if (cmd == "load") { - if (narg < 2) error->all(FLERR,"Illegal plugin load command"); - for (int i=1; i < narg; ++i) - plugin_load(arg[i],lmp); - } else if (cmd == "unload") { - if (narg != 3) error->all(FLERR,"Illegal plugin unload command"); - plugin_unload(arg[1],arg[2],lmp); - } else if (cmd == "clear") { - plugin_clear(lmp); - } else if (cmd == "list") { - if (comm->me == 0) { - int num = plugin_get_num_plugins(); - utils::logmesg(lmp,"Currently loaded plugins\n"); - for (int i=0; i < num; ++i) { - auto entry = plugin_get_info(i); - utils::logmesg(lmp,fmt::format("{:4}: {} style plugin {}\n", - i+1,entry->style,entry->name)); - } - } - } else error->all(FLERR,"Illegal plugin command"); -} - -/* ---------------------------------------------------------------------- */ - void Input::print() { if (narg < 1) error->all(FLERR,"Illegal print command"); diff --git a/src/library.cpp b/src/library.cpp index 68ce180107..414d0f9f3a 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -38,7 +38,9 @@ #include "neighbor.h" #include "region.h" #include "output.h" +#if defined(LMP_PLUGIN) #include "plugin.h" +#endif #include "thermo.h" #include "timer.h" #include "universe.h" @@ -4590,7 +4592,11 @@ This function counts how many plugins are currently loaded. */ int lammps_plugin_count() { +#if defined(LMP_PLUGIN) return plugin_get_num_plugins(); +#else + return 0; +#endif } /* ---------------------------------------------------------------------- */ @@ -4617,6 +4623,7 @@ set to an empty string, otherwise 1. */ int lammps_plugin_name(int idx, char *stylebuf, char *namebuf, int buf_size) { +#if defined(LMP_PLUGIN) stylebuf[0] = namebuf[0] = '\0'; const lammpsplugin_t *plugin = plugin_get_info(idx); @@ -4625,6 +4632,7 @@ int lammps_plugin_name(int idx, char *stylebuf, char *namebuf, int buf_size) strncpy(namebuf,plugin->name,buf_size); return 1; } +#endif return 0; } diff --git a/unittest/commands/CMakeLists.txt b/unittest/commands/CMakeLists.txt index 50f85475d3..6fae0c2463 100644 --- a/unittest/commands/CMakeLists.txt +++ b/unittest/commands/CMakeLists.txt @@ -1,6 +1,6 @@ # build LAMMPS plugins, but not on Windows -if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") +if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows" AND PKG_PLUGIN) ExternalProject_Add(plugins SOURCE_DIR "${LAMMPS_DIR}/examples/plugins" BINARY_DIR ${CMAKE_BINARY_DIR}/build-plugins diff --git a/unittest/commands/test_simple_commands.cpp b/unittest/commands/test_simple_commands.cpp index 448224f730..d98146d4f3 100644 --- a/unittest/commands/test_simple_commands.cpp +++ b/unittest/commands/test_simple_commands.cpp @@ -367,6 +367,7 @@ TEST_F(SimpleCommandsTest, Units) TEST_FAILURE(".*ERROR: Illegal units command.*", lmp->input->one("units unknown");); } +#if defined(LMP_PLUGIN) TEST_F(SimpleCommandsTest, Plugin) { #if defined(__APPLE__) @@ -437,6 +438,7 @@ TEST_F(SimpleCommandsTest, Plugin) if (verbose) std::cout << text; ASSERT_THAT(text, MatchesRegex(".*Currently loaded plugins.*")); } +#endif TEST_F(SimpleCommandsTest, Shell) {