diff --git a/doc/src/Developer_plugins.rst b/doc/src/Developer_plugins.rst index 1beedcf213f..4947bf53a0b 100644 --- a/doc/src/Developer_plugins.rst +++ b/doc/src/Developer_plugins.rst @@ -8,11 +8,20 @@ without recompiling LAMMPS. The functionality for this and the Plugins use the operating system's capability to load dynamic shared object (DSO) files in a way similar shared libraries and then reference -specific functions in those DSOs. Any DSO file with plugins has to include -an initialization function with a specific name, "lammpsplugin_init", that -has to follow specific rules described below. When loading the DSO with -the "plugin" command, this function is looked up and called and will then -register the contained plugin(s) with LAMMPS. +specific functions in those DSOs. Any DSO file with plugins has to +include an initialization function with a specific name, +"lammpsplugin_init", that has to follow specific rules described below. +When loading the DSO with the "plugin" command, this function is looked +up and called and will then register the contained plugin(s) with +LAMMPS. + +When the environment variable ``LAMMPS_PLUGIN_PATH`` is set, then LAMMPS +will search the directory (or directories) listed in this path for files +with names that end in ``plugin.so`` (e.g. ``helloplugin.so``) and will +try to load the contained plugins automatically at start-up. For +plugins that are loaded this way, the behavior of LAMMPS should be +identical to a binary where the corresponding code was compiled in +statically as a package. From the programmer perspective this can work because of the object oriented design of LAMMPS where all pair style commands are derived from @@ -65,19 +74,18 @@ Members of ``lammpsplugin_t`` * - handle - Pointer to the open DSO file handle -Only one of the three alternate creator entries can be used at a time -and which of those is determined by the style of plugin. The -"creator.v1" element is for factory functions of supported styles -computing forces (i.e. command, pair, bond, angle, dihedral, or -improper styles) and the function takes as single argument the pointer -to the LAMMPS instance. The factory function is cast to the -``lammpsplugin_factory1`` type before assignment. The "creator.v2" -element is for factory functions creating an instance of a fix, compute, -or region style and takes three arguments: a pointer to the LAMMPS -instance, an integer with the length of the argument list and a ``char -**`` pointer to the list of arguments. The factory function pointer -needs to be cast to the ``lammpsplugin_factory2`` type before -assignment. +Only one of the two alternate creator entries can be used at a time and +which of those is determined by the style of plugin. The "creator.v1" +element is for factory functions of supported styles computing forces +(i.e. pair, bond, angle, dihedral, or improper styles) or command styles +and the function takes as single argument the pointer to the LAMMPS +instance. The factory function is cast to the ``lammpsplugin_factory1`` +type before assignment. The "creator.v2" element is for factory +functions creating an instance of a fix, compute, or region style and +takes three arguments: a pointer to the LAMMPS instance, an integer with +the length of the argument list and a ``char **`` pointer to the list of +arguments. The factory function pointer needs to be cast to the +``lammpsplugin_factory2`` type before assignment. Pair style example ^^^^^^^^^^^^^^^^^^ @@ -249,3 +257,8 @@ by ``#ifdef PAIR_CLASS`` is not needed, since the mapping of the class name to the style name is done by the plugin registration function with the information from the ``lammpsplugin_t`` struct. It may be included in case the new code is intended to be later included in LAMMPS directly. + +A plugin may be registered under an existing style name. In that case +the plugin will override the existing code. This can be used to modify +the behavior of existing styles or to debug new versions of them without +having to recompile/reinstall all of LAMMPS. diff --git a/doc/src/Packages_details.rst b/doc/src/Packages_details.rst index 396ecd6442f..5876d82cc58 100644 --- a/doc/src/Packages_details.rst +++ b/doc/src/Packages_details.rst @@ -2154,6 +2154,11 @@ A :doc:`plugin ` command that can load and unload several kind of styles in LAMMPS from shared object files at runtime without having to recompile and relink LAMMPS. +When the environment variable ``LAMMPS_PLUGIN_PATH`` is set, then LAMMPS +will search the directory (or directories) listed in this path for files +with names that end in ``plugin.so`` (e.g. ``helloplugin.so``) and will +try to load the contained plugins automatically at start-up. + **Authors:** Axel Kohlmeyer (Temple U) **Supporting info:** diff --git a/doc/src/plugin.rst b/doc/src/plugin.rst index 5372dffc83b..3ce9e41870a 100644 --- a/doc/src/plugin.rst +++ b/doc/src/plugin.rst @@ -56,6 +56,15 @@ styles and names. The *clear* command will unload all currently loaded plugins. +.. admonition:: Automatic loading of plugins + :class: note + + When the environment variable ``LAMMPS_PLUGIN_PATH`` is set, then + LAMMPS will search the directory (or directories) listed in this path + for files with names that end in ``plugin.so`` + (e.g. ``helloplugin.so``) and will try to load the contained plugins + automatically at start-up. + Restrictions """""""""""" diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 4e05cd51820..6799e62d24d 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -1927,6 +1927,7 @@ Mayoral mbt MBytes mc +mcmoves McLachlan mcmoves md diff --git a/src/PLUGIN/plugin.cpp b/src/PLUGIN/plugin.cpp index 33a252c39eb..3b28a32dbf7 100644 --- a/src/PLUGIN/plugin.cpp +++ b/src/PLUGIN/plugin.cpp @@ -34,6 +34,8 @@ static std::list pluginlist; // map for counting references to dso handles static std::map dso_refcounter; +static bool verbose = true; + /* ---------------------------------------------------------------------- */ Plugin::Plugin(LAMMPS *lmp) : Command(lmp) {} @@ -67,15 +69,26 @@ void Plugin::command(int narg, char **arg) } } else error->all(FLERR, "Illegal plugin command"); -#if 0 - if (comm->me == 0) - error->warning( - FLERR, "LAMMPS must be built as a shared library for it to work."); +} + +// auto-load DSOs from designated folder(s) +void plugin_auto_load(LAMMPS *lmp) +{ +#if defined(LMP_PLUGIN) + for (const auto &plugin_dir : platform::list_pathenv("LAMMPS_PLUGIN_PATH")) { + verbose = false; + int count = 0; + for (const auto &file : platform::list_directory(plugin_dir)) { + if (utils::strmatch(file, "\\plugin.so$")) + count += plugin_load(platform::path_join(plugin_dir, file).c_str(), lmp); + } + if (lmp->comm->me == 0) utils::logmesg(lmp, "Loaded {} plugins from {}\n", count, plugin_dir); + } #endif } // load DSO and call included registration function -void plugin_load(const char *file, LAMMPS *lmp) +int plugin_load(const char *file, LAMMPS *lmp) { #if defined(LMP_PLUGIN) int me = lmp->comm->me; @@ -86,7 +99,7 @@ void plugin_load(const char *file, LAMMPS *lmp) void *dso = platform::dlopen(file); if (dso == nullptr) { if (me == 0) utils::logmesg(lmp, "Open of file {} failed: {}\n", file, platform::dlerror()); - return; + return 0; } // look up lammpsplugin_init() function in DSO @@ -100,7 +113,7 @@ void plugin_load(const char *file, LAMMPS *lmp) if (me == 0) utils::logmesg(lmp, "Plugin symbol lookup failure in file {}: {}\n", file, platform::dlerror()); - return; + return 0; } // call initializer function loaded from DSO and pass a pointer @@ -108,6 +121,7 @@ void plugin_load(const char *file, LAMMPS *lmp) // and plugin registration function pointer (*(lammpsplugin_initfunc) (initfunc))((void *) lmp, dso, (void *) &plugin_register); + return 1; #endif } @@ -129,13 +143,13 @@ void plugin_register(lammpsplugin_t *plugin, void *ptr) // ignore load request if same plugin already loaded int idx = plugin_find(plugin->style, plugin->name); if (idx >= 0) { - if (me == 0) + if (verbose && (me == 0)) utils::logmesg(lmp, "Ignoring load of {} style {}: must unload existing {} plugin first\n", plugin->style, plugin->name, plugin->name); return; } - if (me == 0) { + if (verbose && (me == 0)) { utils::logmesg(lmp, "Loading plugin: {} by {}\n", plugin->info, plugin->author); // print version info only if the versions of host and plugin don't match if ((plugin->version) && (strcmp(plugin->version, lmp->version) != 0)) @@ -270,7 +284,7 @@ void plugin_unload(const char *style, const char *name, LAMMPS *lmp) // remove selected plugin from list of plugins - if (me == 0) utils::logmesg(lmp, "Unloading {} style {}\n", style, name); + if (verbose && (me == 0)) utils::logmesg(lmp, "Unloading {} style {}\n", style, name); plugin_erase(style, name); // remove style of given name from corresponding map @@ -383,10 +397,12 @@ void plugin_unload(const char *style, const char *name, LAMMPS *lmp) void plugin_clear(LAMMPS *lmp) { + verbose = false; while (pluginlist.size() > 0) { auto p = pluginlist.begin(); plugin_unload(p->style, p->name, lmp); } + verbose = true; } /* -------------------------------------------------------------------- diff --git a/src/PLUGIN/plugin.h b/src/PLUGIN/plugin.h index cc1a3bf2dc3..0fd2cd50424 100644 --- a/src/PLUGIN/plugin.h +++ b/src/PLUGIN/plugin.h @@ -31,7 +31,8 @@ class Plugin : public Command { void command(int, char **) override; }; -void plugin_load(const char *, LAMMPS *); +void plugin_auto_load(LAMMPS *); +int plugin_load(const char *, LAMMPS *); void plugin_register(lammpsplugin_t *, void *); void plugin_unload(const char *, const char *, LAMMPS *); diff --git a/src/lammps.cpp b/src/lammps.cpp index e6ff6efb237..c74983be43c 100644 --- a/src/lammps.cpp +++ b/src/lammps.cpp @@ -824,6 +824,11 @@ void LAMMPS::create() timer = new Timer(this); python = new Python(this); + + // auto-load plugins +#if defined(LMP_PLUGIN) + plugin_auto_load(this); +#endif } /* ----------------------------------------------------------------------