*******> update.9
Author: Jamie Smith
Date: Sept. 1, 2020
Programs: sander interface to plumed
Description: Fix PLUMED linking by updating interface to latest version
--------------------------------------------------------------------------------
AmberTools/src/sander/CMakeLists.txt | 4 +-
AmberTools/src/sander/Plumed.c | 306 +---
AmberTools/src/sander/Plumed.h | 2726 +++++++++++++++++++++++++++++++---
cmake/3rdPartyTools.cmake | 42 +-
cmake/FindAPBS.cmake | 2 +-
cmake/FindPLUMED.cmake | 90 ++
6 files changed, 2647 insertions(+), 537 deletions(-)
diff --git AmberTools/src/sander/CMakeLists.txt AmberTools/src/sander/CMakeLists.txt
index 38538da5d0..48a6024af5 100644
--- AmberTools/src/sander/CMakeLists.txt
+++ AmberTools/src/sander/CMakeLists.txt
@@ -236,7 +236,7 @@ set(ALL_FORTRAN_SOURCES ${SANDER_COMMON_SOURCE} ${LES_SOURCE} ${PUPIL_SOURCE} ${
apply_optimization_declarations(${ALL_FORTRAN_SOURCES})
-set_property(SOURCE ${PLUMED_SOURCE} PROPERTY COMPILE_FLAGS ${NO_OPT_CFLAGS})
+set_property(SOURCE ${PLUMED_SOURCE} PROPERTY COMPILE_FLAGS ${OPT_CFLAGS_SPC})
if(plumed_ENABLED)
set_property(SOURCE ${PLUMED_SOURCE} PROPERTY COMPILE_DEFINITIONS __PLUMED_STATIC_KERNEL)
@@ -464,7 +464,7 @@ if(PLUMED_RUNTIME_LINK)
set_target_properties(${EXECUTABLES} ${OPENMP_EXECUTABLES} ${MPI_EXECUTABLES} PROPERTIES ENABLE_EXPORTS TRUE)
else()
if(plumed_ENABLED)
- targets_link_libraries(${EXECUTABLES} ${OPENMP_EXECUTABLES} ${MPI_EXECUTABLES} ${LIBRARIES} LIBRARIES plumed)
+ targets_link_libraries(${EXECUTABLES} ${OPENMP_EXECUTABLES} ${MPI_EXECUTABLES} ${LIBRARIES} LIBRARIES plumed::plumed)
endif()
endif()
diff --git AmberTools/src/sander/Plumed.c AmberTools/src/sander/Plumed.c
index 5189ca7f30..69e103e35c 100644
--- AmberTools/src/sander/Plumed.c
+++ AmberTools/src/sander/Plumed.c
@@ -1,8 +1,8 @@
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Copyright (c) 2011-2014 The plumed team
+ Copyright (c) 2011-2020 The plumed team
(see the PEOPLE file at the root of the distribution for a list of names)
- See http://www.plumed-code.org for more information.
+ See http://www.plumed.org for more information.
This file is part of plumed, version 2.
@@ -19,306 +19,30 @@
You should have received a copy of the GNU Lesser General Public License
along with plumed. If not, see .
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
-#ifdef __PLUMED_HAS_DLOPEN
-#include
-#endif
-
-#include "Plumed.h"
-#include
-#include
-#include
-#include
-
-/* DECLARATION USED ONLY IN THIS FILE */
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-/**
- Holder for plumedmain function pointers.
-*/
-typedef struct {
- void*(*create)(void);
- void(*cmd)(void*,const char*,const void*);
- void(*finalize)(void*);
-} plumed_plumedmain_function_holder;
-/**
- Register for plumedmain function pointers
+/*
+ Do not link plumed directly but rather do it at runtime
*/
-plumed_plumedmain_function_holder* plumed_kernel_register(const plumed_plumedmain_function_holder*);
-
+// AMBER: use old __PLUMED_STATIC_KERNEL name for this option for compatibility
#ifdef __PLUMED_STATIC_KERNEL
-/* Real interface */
-void*plumedmain_create(void);
-void plumedmain_cmd(void*,const char*,const void*);
-void plumedmain_finalize(void*);
-#else
-/* dummy interface */
-void*plumed_dummy_create(void);
-void plumed_dummy_cmd(void*,const char*,const void*);
-void plumed_dummy_finalize(void*);
-#endif
-
-#ifdef __cplusplus
- }
-#endif
-
-/* END OF DECLARATION USED ONLY IN THIS FILE */
-
-/* These are the dummy routines which are used when plumed is not available */
-
-#ifdef __PLUMED_STATIC_KERNEL
-
-static int installed=1;
-
+#define __PLUMED_WRAPPER_LINK_RUNTIME 0
#else
-
-static int installed=0;
-
-static int dummy;
-
-void*plumed_dummy_create(void){
- return (void*)&dummy;
-}
-
-void plumed_dummy_cmd(void*p,const char*key,const void*val){
- (void) p; /* avoid warning on unused parameter */
- (void) key; /* avoid warning on unused parameter */
- (void) val; /* avoid warning on unused parameter */
- fprintf(stderr,"+++ ERROR: you are trying to use plumed, but it is not available +++\n");
- fprintf(stderr,"+++ Check your PLUMED_KERNEL environment variable +++\n");
- exit(1);
-}
-
-void plumed_dummy_finalize(void*p){
- (void) p; /* avoid warning on unused parameter */
-}
-
+#define __PLUMED_WRAPPER_LINK_RUNTIME 1
#endif
-
-plumed_plumedmain_function_holder* plumed_kernel_register(const plumed_plumedmain_function_holder* f){
-#ifdef __PLUMED_STATIC_KERNEL
-/*
- When __PLUMED_STATIC_KERNEL is defined, the function holder is initialized
- to statically bound plumedmain_create,plumedmain_cmd,plumedmain_finalize and
- cannot be changed. This saves from mis-set values for PLUMED_KERNEL
-*/
- static plumed_plumedmain_function_holder g={plumedmain_create,plumedmain_cmd,plumedmain_finalize};
- (void) f; /* avoid warning on unused parameter */
- return &g;
-#else
/*
- On the other hand, for runtime binding, we allow to reset the function holder on the
- first call to plumed_kernel_register.
- Notice that in principle plumed_kernel_register is entered *twice*: one for the first
- plumed usage, and then from the PlumedMainInitializer object of the shared library.
- This is why we set "first=0" only *after* loading the shared library.
- Also notice that we should put some guard here for safe multithread calculations.
+ Make sure the inline C++ interface is not included here.
+ Should not be necessary, but it doesn't hurt.
*/
- static plumed_plumedmain_function_holder g={plumed_dummy_create,plumed_dummy_cmd,plumed_dummy_finalize};
- static int first=1;
-#ifdef __PLUMED_HAS_DLOPEN
- char* path;
- void* p;
- if(first && f==NULL){
- path=getenv("PLUMED_KERNEL");
- if(path && (*path)){
- fprintf(stderr,"+++ Loading the PLUMED kernel runtime +++\n");
- fprintf(stderr,"+++ PLUMED_KERNEL=\"%s\" +++\n",path);
- p=dlopen(path,RTLD_NOW|RTLD_GLOBAL);
- if(p){
- fprintf(stderr,"+++ PLUMED kernel successfully loaded +++\n");
- installed=1;
- } else{
- fprintf(stderr,"+++ PLUMED kernel not found ! +++\n");
- fprintf(stderr,"+++ error message from dlopen(): %s\n",dlerror());
- }
- }
- }
-#endif
- first=0;
- if(f) g=*f;
- return &g;
-#endif
-}
-
-/* C wrappers: */
-
-plumed plumed_create(void){
- plumed p;
- p.p=(*(plumed_kernel_register(NULL)->create))();
- return p;
-}
-
-void plumed_cmd(plumed p,const char*key,const void*val){
- (*(plumed_kernel_register(NULL)->cmd))(p.p,key,val);
-}
-
-void plumed_finalize(plumed p){
- (*(plumed_kernel_register(NULL)->finalize))(p.p);
-}
-
-int plumed_installed(void){
- plumed_kernel_register(NULL);
- return installed;
-}
-
-/* we declare a Plumed_g_main object here, in such a way that it is always available */
-
-static plumed gmain={NULL};
-
-plumed plumed_global(void){
- return gmain;
-}
-
-void plumed_gcreate(void){
- assert(gmain.p==NULL);
- gmain=plumed_create();
-}
-
-void plumed_gcmd(const char*key,const void*val){
- plumed_cmd(gmain,key,val);
-}
-
-void plumed_gfinalize(void){
- plumed_finalize(gmain);
- gmain.p=NULL;
-}
-
-int plumed_ginitialized(void){
- if(gmain.p) return 1;
- else return 0;
-}
-
-void plumed_c2f(plumed p,char*c){
- unsigned i;
- unsigned char* cc;
-/*
- Convert the address stored in p.p into a proper FORTRAN string
- made of only ASCII characters. For this to work, the two following
- assertions should be satisfied:
-*/
- assert(CHAR_BIT<=12);
- assert(sizeof(p.p)<=16);
-
- assert(c);
- cc=(unsigned char*)&p.p;
- for(i=0;i=2.5.
+
+ The remapping of exceptions takes care of all the standard C++ exceptions plus all the exceptions raised within
+ PLUMED. Unexpected exceptions that are derived from std::exception will be rethrown as std::exception.
+ Notice that this implies some loss of information, since the original exception might have been of a different type.
+ However, it also implies that the virtual table of the original exception won't be needed anymore. This allows to
+ completely decouple the MD code from the PLUMED library.
+
+\section ReferencePlumedH-2-5 New in PLUMED 2.5
+
+ The wrappers in PLUMED 2.5 have been completely rewritten with several improvements.
+ The interface is almost perfectly backward compatible, although the behavior of C++ constructors
+ has been modified slightly.
+ In addition, a few new functions are introduced (explicitly marked in the documentation).
+ As a consequence, if your code uses some of the new functions, you will not be able
+ to link it directly with an older PLUMED library (though you will still be able to load
+ an older PLUMED library at runtime). In addition, the reference counter changes slightly
+ the behavior of the C++ methods used to interoperate with C and FORTRAN.
+
+ An important novelty is in the way the runtime loader is implemented.
+ In particular, the loader works also if the symbols of the main executable are not exported.
+ The proper functions from the kernel are indeed searched explicitly now using `dlsym`.
+
+ Some additional features can be enabled using suitable environment variables. In particular:
+ - `PLUMED_LOAD_DEBUG` can be set to report more information about the loading process.
+ - `PLUMED_LOAD_NAMESPACE` can be set to `LOCAL` to load the PLUMED kernel in a separate
+ namespace. The default is global namespace, which is the same behavior of PLUMED <=2.4,
+ and is consistent with what happens when linking PLUMED as a shared library.
+ - `PLUMED_LOAD_NODEEPBIND` can be set to load the PLUMED kernel in not-deepbind mode. Deepbind
+ mode implies that the symbols defined in the library are preferred to other symbols with the same name.
+ Only works on systems supporting `RTLD_DEEPBIND` and is mostly for debugging purposes.
+
+ Another difference is that the implementation of the wrappers is now completely contained in the `Plumed.h`
+ file. You can see that the `Plumed.c` is much simpler now and just includes `Plumed.h`. With a similar
+ procedure you could compile the wrappers directly into your code making it unnecessary to link
+ the libplumedWrapper.a library. The corresponding macros are still subject to change and are not documented here.
+
+ As written above, the plumed object now implements a reference counter. Consider the following example
+\verbatim
+ plumed p=plumed_create();
+ plumed_cmd(p,"init",NULL);
+ plumed q=plumed_create_reference(p);
+ plumed_finalize(p);
+// at this stage, object q still exists
+ plumed_cmd(q,"whatever",NULL);
+ plumed_finalize(q);
+// now plumed has been really finalized
\endverbatim
- The main routine is "cmd", which accepts two arguments:
- key is a string containing the name of the command
- val is the argument. it is declared const so as to use allow passing const objects, but in practice plumed
- is going to modify val in several cases (using a const_cast).
- In some cases val can be omitted: just pass a NULL pointer (in C++, val is optional and can be omitted).
- The set of possible keys is the real API of the plumed library, and will be expanded with time.
- New commands will be added, but backward compatibility will be retained as long as possible.
+ In other words, every \ref plumed_create, \ref plumed_create_dlopen, \ref plumed_create_reference,
+ \ref plumed_create_reference_f, and \ref plumed_create_reference_v call must be matched by a \ref plumed_finalize.
+ Notice that in C++ whenever an object goes out of scope the reference counter
+ will be decreased. In addition, consider that conversion from C/FORTRAN/void* to C++ implies calling a C++ constructor, that
+ is increases the number of references by one. Converting from C++ to C/FORTRAN/void* instead does not call any constructor,
+ that is the number of references is unchanged.
- To pass plumed a callback function use the following syntax (not available in FORTRAN yet)
+ The change in the behavior of C++ constructors means that the following code will behave in a backward incompatible manner:
\verbatim
- plumed_function_holder ff;
- ff.p=your_function;
- plumed_cmd(plumed,"xxxx",&ff);
+ plumed p=plumed_create();
+ plumed_cmd(p,"init",NULL);
+ Plumed q(p);
+ plumed_finalize(p);
+// at this stage, object q still exists with PLUMED 2.5
+// on the other hand, with PLUMED 2.4 object q refers to an
+// already finalized object
+ q.cmd("whatever",NULL);
\endverbatim
- (this is passing the your_function() function to the "xxxx" command)
+
+ Another difference is that the value of the variable `PLUMED_KERNEL` is read every time a new
+ plumed object is instantiated. So, you might even use it to load different plumed versions
+ simultaneously, although the preferred way to do this is using the function \ref plumed_create_dlopen.
+ Notice that if you want to load multiple versions simultaneously you should load them in a local namespace.
+ \ref plumed_create_dlopen does it automatically, whereas loading through env var `PLUMED_KERNEL` only does it if
+ you also set env var `PLUMED_NAMESPACE=LOCAL`.
+
+ Finally, a few functions have been added, namely:
+ - Functions to find if a plumed object is valid
+ (\ref plumed_valid(), \ref plumed_gvalid(), \ref PLMD::Plumed::valid(), and \ref PLMD::Plumed::gvalid()).
+ - Functions to create a plumed object based on the path of a specific kernel
+ (\ref plumed_create_dlopen() and \ref PLMD::Plumed::dlopen()).
+ - Functions to create a plumed object referencing to another one, implementing a reference counter
+ (\ref plumed_create_reference(), \ref plumed_create_reference_v(), \ref plumed_create_reference_f().
+
*/
-#ifdef __cplusplus
- extern "C" {
+/* BEGINNING OF DECLARATIONS */
+
+/* SETTING DEFAULT VALUES FOR CONTROL MACROS */
+
+/*
+ 1: make the C wrapper functions extern (default)
+ 0: make the C wrapper functions static (C) or inline (C++)
+
+ If set to zero, it disables all functions that only make sense as extern, such as
+ Fortran wrappers, global objects, and plumed_kernel_register.
+
+ It can be set to zero to include multiple copies of the wrapper implementation without worrying
+ about duplicated symbols.
+
+ Notice that C++ wrappers are always inline. What this function controls is if the C wrappers
+ (called by the C++ wrappers) is inline or not. Also consider that if this header is compiled
+ with C++ and inline C wrappers, the C wrappers will be actually compiled with C++ linkage
+ in the root namespace.
+
+ Used both in declarations (to know which functions to declare) and definitions (to know which functions to define).
+*/
+
+#ifndef __PLUMED_WRAPPER_EXTERN
+#define __PLUMED_WRAPPER_EXTERN 1
#endif
-/* Generic function pointer */
-typedef void (*plumed_function_pointer)(void);
+/*
+ 1: emit global plumed object and related functions (default)
+ 0: do not emit global plumed object and related functions
-/**
- \brief Holder for function pointer.
+ Used both in declarations (to know which functions to declare) and definitions (to know which functions to define).
+*/
- To pass plumed a callback function use the following syntax:
-\verbatim
- plumed_function_holder ff;
- ff.p=your_function;
- plumed_cmd(plumed,"xxxx",&ff);
-\endverbatim
- (this is going to pass the your_function() function to the "xxxx" command)
+#ifndef __PLUMED_WRAPPER_GLOBAL
+#define __PLUMED_WRAPPER_GLOBAL 1
+#endif
+
+/*
+ 1: enable C++ wrapper (default)
+ 0: disable C++ wrapper
+
+ Only used in declarations, but affects the scope of the C interface also in definitions.
*/
-typedef struct {
- plumed_function_pointer p;
-} plumed_function_holder;
+#ifndef __PLUMED_WRAPPER_CXX
+#define __PLUMED_WRAPPER_CXX 1
+#endif
+
+/*
+ 1: new headers such as cstdlib are included in C++ (default)
+ 0: old headers such as stdlib.h are included in C++
+
+ Should only be set to zero when including the Plumed.h file in a file using the
+ old (stdlib.h) convention.
+
+ Used both in declarations and definitions.
+*/
+
+#ifndef __PLUMED_WRAPPER_CXX_STD
+#define __PLUMED_WRAPPER_CXX_STD 1
+#endif
+
+/*
+ 1: place C++ wrappers in an anonymous namespace
+ 0: place C++ wrappers in the PLMD namespace (default)
+
+ It will make PLMD::Plumed a different class (though with the same name)
+ in each of the translation units in which `Plumed.h` is included.
+
+ Can be used to completey separate C++ implementations. However, it will make
+ it impossible to transfer Plumed objects between different translation units
+ without converting to a void* or plumed object.
+
+ Only used in declarations, but affects the scope of the C interface also in definitions.
+*/
+
+#ifndef __PLUMED_WRAPPER_CXX_ANONYMOUS_NAMESPACE
+#define __PLUMED_WRAPPER_CXX_ANONYMOUS_NAMESPACE 0
+#endif
+
+/*
+ 1: make PLMD::Plumed class polymorphic (default)
+ 0: make PLMD::Plumed class non-polymorphic
+
+ Only used in declarations.
+*/
+
+#ifndef __PLUMED_WRAPPER_CXX_POLYMORPHIC
+#define __PLUMED_WRAPPER_CXX_POLYMORPHIC 1
+#endif
+
+/*
+ 1: make the default constructor create an invalid object
+ 0: make the default constructor create a valid object
+
+ Only for internal usage.
+*/
+#ifndef __PLUMED_WRAPPER_CXX_DEFAULT_INVALID
+#define __PLUMED_WRAPPER_CXX_DEFAULT_INVALID 0
+#endif
+
+/*
+ Size of a buffer used to store message for exceptions with noexcept constructor.
+ Should typically hold short messages. Anyway, as long as the stack size stays within the correct
+ limits it does not seem to affect efficiency. Notice that there cannot be recursive calls of
+ PLMD::Plumed::cmd, so that it should be in practice irrelevant.
+*/
+#ifndef __PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER
+#define __PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER 512
+#endif
+
+
+/*
+ By default, assume C++11 compliant library is not available.
+*/
+
+#ifndef __PLUMED_WRAPPER_LIBCXX11
+#define __PLUMED_WRAPPER_LIBCXX11 0
+#endif
+
+/* The following macros are just to define shortcuts */
+
+/* Simplify addition of extern "C" blocks. */
+#ifdef __cplusplus
+#define __PLUMED_WRAPPER_EXTERN_C_BEGIN extern "C" {
+#define __PLUMED_WRAPPER_EXTERN_C_END }
+#else
+#define __PLUMED_WRAPPER_EXTERN_C_BEGIN
+#define __PLUMED_WRAPPER_EXTERN_C_END
+#endif
+
+/* Without C++, stdlib functions should not be prepended with ::std:: */
+#ifndef __cplusplus
+#undef __PLUMED_WRAPPER_CXX_STD
+#define __PLUMED_WRAPPER_CXX_STD 0
+#endif
+
+/* Set prefix for stdlib functions */
+#if __PLUMED_WRAPPER_CXX_STD
+#define __PLUMED_WRAPPER_STD ::std::
+#else
+#define __PLUMED_WRAPPER_STD
+#endif
+
+/* Allow using noexcept, explicit, and override with C++11 compilers */
+#if __cplusplus > 199711L
+#define __PLUMED_WRAPPER_CXX_NOEXCEPT noexcept
+#define __PLUMED_WRAPPER_CXX_EXPLICIT explicit
+#define __PLUMED_WRAPPER_CXX_OVERRIDE override
+#else
+#define __PLUMED_WRAPPER_CXX_NOEXCEPT throw()
+#define __PLUMED_WRAPPER_CXX_EXPLICIT
+#define __PLUMED_WRAPPER_CXX_OVERRIDE
+#endif
+
+/* Macros for anonymous namespace */
+#if __PLUMED_WRAPPER_CXX_ANONYMOUS_NAMESPACE && defined(__cplusplus) /*{*/
+#define __PLUMED_WRAPPER_ANONYMOUS_BEGIN namespace {
+#define __PLUMED_WRAPPER_ANONYMOUS_END }
+#else
+#define __PLUMED_WRAPPER_ANONYMOUS_BEGIN
+#define __PLUMED_WRAPPER_ANONYMOUS_END
+#endif /*}*/
+
+#if __PLUMED_WRAPPER_EXTERN /*{*/
+
+#define __PLUMED_WRAPPER_C_BEGIN __PLUMED_WRAPPER_EXTERN_C_BEGIN extern
+#define __PLUMED_WRAPPER_C_END __PLUMED_WRAPPER_EXTERN_C_END
+#define __PLUMED_WRAPPER_INTERNALS_BEGIN __PLUMED_WRAPPER_EXTERN_C_BEGIN static
+#define __PLUMED_WRAPPER_INTERNALS_END __PLUMED_WRAPPER_EXTERN_C_END
+
+#else
+
+#ifdef __cplusplus
+#define __PLUMED_WRAPPER_C_BEGIN __PLUMED_WRAPPER_ANONYMOUS_BEGIN inline
+#define __PLUMED_WRAPPER_C_END __PLUMED_WRAPPER_ANONYMOUS_END
+#else
+#define __PLUMED_WRAPPER_C_BEGIN static
+#define __PLUMED_WRAPPER_C_END
+#endif
+
+#define __PLUMED_WRAPPER_INTERNALS_BEGIN __PLUMED_WRAPPER_C_BEGIN
+#define __PLUMED_WRAPPER_INTERNALS_END __PLUMED_WRAPPER_C_END
+
+/* with an not-external interface, it does not make sense to define global functions */
+#undef __PLUMED_WRAPPER_GLOBAL
+#define __PLUMED_WRAPPER_GLOBAL 0
+
+#endif /*}*/
/**
\brief Main plumed object
@@ -199,63 +576,384 @@ typedef struct {
not to change across plumed versions. See \ref ReferencePlumedH.
*/
typedef struct {
-/**
- \private
- \brief Void pointer holding the real PlumedMain structure
-*/
+ /**
+ \private
+ \brief Void pointer holding the real PlumedMain structure
+
+ To maintain binary compatibility, we should not add members to this structure.
+ As of PLUMED 2.5, in order to add new components we do not store the pointer
+ to \ref PlumedMain here but rather a pointer to an intermediate private structure
+ that contains all the details.
+ */
void*p;
} plumed;
+typedef struct {
+ void* ptr;
+ void (*handler)(void*,int,const char*,const void*);
+} plumed_nothrow_handler;
+
/** \relates plumed
\brief Constructor
+ Constructs a plumed object.
+
+ Notice that if you are linking against libplumedWrapper.a, if you are
+ using a code patched in runtime mode, or if you are including the `Plumed.c`
+ file directly in your code, this constructor might return an invalid plumed
+ object. In particular, this could happen if the `PLUMED_KERNEL` environment
+ variable is not set or set incorrectly. In order to detect an incorrect
+ plumed object you might use \ref plumed_valid() on the resulting object.
+ Alternatively, if you use \ref plumed_cmd() on an invalid plumed object the code will exit.
+ Also notice that to avoid memory leaks you should call \ref plumed_finalize()
+ to finalize a plumed object even if it is invalid:
+\verbatim
+ plumed p=plumed_create();
+ if(!plumed_valid(p)) {
+// this will happen if the PLUMED_KERNEL variable is not set correctly
+ plumed_finalize(p);
+ return whatever;
+ }
+\endverbatim
+
\return The constructed plumed object
*/
+__PLUMED_WRAPPER_C_BEGIN
plumed plumed_create(void);
+__PLUMED_WRAPPER_C_END
+
+/** \relates plumed
+ \brief Constructor from path. Available as of PLUMED 2.5
+
+ It tries to construct a plumed object loading the kernel located at path.
+ Notice that it could leave the resulting object in an invalid state.
+ In order to detect an invalid
+ plumed object you might use \ref plumed_valid() on the resulting object.
+ Alternatively, if you use \ref plumed_cmd() on an invalid plumed object the code will exit.
+
+ Also notice that to avoid memory leaks you should call \ref plumed_finalize()
+ to finalize a plumed object even if it is invalid.
+\verbatim
+ plumed p=plumed_create(path);
+ if(!plumed_valid(p)) {
+// this will happen if the path argument is not set correctly
+ plumed_finalize(p);
+ return whatever;
+ }
+\endverbatim
+
+ \return The constructed plumed object
+*/
+__PLUMED_WRAPPER_C_BEGIN
+plumed plumed_create_dlopen(const char*path);
+__PLUMED_WRAPPER_C_END
+
+
+/**
+ \brief Constructor from path. Available as of PLUMED 2.5
+
+ Same as \ref plumed_create_dlopen, but also allows to specify the mode for dlopen.
+
+ \warning
+ Use with care, since not all the possible modes work correctly with PLUMED.
+*/
+__PLUMED_WRAPPER_C_BEGIN
+plumed plumed_create_dlopen2(const char*path,int mode);
+__PLUMED_WRAPPER_C_END
+
+/** \relates plumed
+ Create a new reference to an existing object, increasing its reference count. Available as of PLUMED 2.5
+
+ Use it to increase by one the reference count of a plumed object.
+ The resulting pointer might be identical to the one passed as an
+ argument, but the reference count will be incremented by one.
+ Notice that you should finalize the resulting object.
+\verbatim
+ plumed p1;
+ plumed p2;
+ p1=plumed_create();
+ p2=plumed_create_reference(p1);
+ plumed_finalize(p1);
+// now you can still use p2
+ plumed_cmd(p2,"init",NULL);
+ plumed_finalize(p2);
+// now the underlying object is destroyed.
+\endverbatim
+
+ If the `p` object is invalid, also the returned object will be invalid.
+
+ \param p The plumed object that will be referenced to.
+ \return The constructed plumed object
+*/
+
+__PLUMED_WRAPPER_C_BEGIN
+plumed plumed_create_reference(plumed p);
+__PLUMED_WRAPPER_C_END
+
+/** \relates plumed
+ \brief Create a new reference to an existing object passed as a void pointer, increasing its reference count. Available as of PLUMED 2.5
+
+ \return The constructed plumed object
+*/
+
+__PLUMED_WRAPPER_C_BEGIN
+plumed plumed_create_reference_v(void*v);
+__PLUMED_WRAPPER_C_END
+
+/** \relates plumed
+ \brief Create a new reference to an existing object passed as a fortran string, increasing its reference count. Available as of PLUMED 2.5
+
+ \return The constructed plumed object
+*/
+
+__PLUMED_WRAPPER_C_BEGIN
+plumed plumed_create_reference_f(const char*f);
+__PLUMED_WRAPPER_C_END
+
+/** \relates plumed
+ \brief Constructor as invalid. Available as of PLUMED 2.5
+
+ Can be used to create an object in the same state as if it was returned by
+ plumed_create_dlopen with an incorrect path (or plumed_create using runtime binding
+ and an incorrect PLUMED_KERNEL).
+
+ Can be used to initialize a plumed object to a well-defined state without explicitly
+ creating it. The resulting object can be checked later with \ref plumed_valid.
+ Consider the following example
+\verbatim
+ plumed p;
+ p=plumed_create_invalid();
+// at this point p is initialized to a well-defined (invalid) state.
+ setenv("PLUMED_KERNEL","/path/to/kernel/libplumedKernel.so",1);
+ plumed_finalize(p);
+ p=plumed_create();
+\endverbatim
+
+ \return The constructed plumed object
+*/
+
+__PLUMED_WRAPPER_C_BEGIN
+plumed plumed_create_invalid();
+__PLUMED_WRAPPER_C_END
/** \relates plumed
- \brief Tells p to execute a command
+ \brief Tells p to execute a command.
+
+ If the object is not valid (see \ref plumed_valid), this command will exit.
\param p The plumed object on which command is acting
\param key The name of the command to be executed
\param val The argument. It is declared as const to allow calls like plumed_cmd(p,"A","B"),
- but for some choice of key it can change the content
+ but for some choice of key it can change the content.
+
+ Notice that within PLUMED we use a const_cast to remove any const qualifier from the second
+ argument of \ref plumed_cmd.
+
+ In some cases val can be omitted: just pass a NULL pointer (in C++, val is optional and can be omitted,
+ or you can equivalently pass NULL or nullptr).
+ The set of possible keys is the real API of the plumed library, and will be expanded with time.
+ New commands will be added, but backward compatibility will be retained as long as possible.
*/
+
+__PLUMED_WRAPPER_C_BEGIN
void plumed_cmd(plumed p,const char*key,const void*val);
+__PLUMED_WRAPPER_C_END
+
+/**
+ \relates plumed
+ \brief Same as \ref plumed_cmd, but does not throw exceptions.
+
+ This function is meant to be used when errors should be handled explicitly.
+ if an exception is raised within PLUMED, the function nothrow.handler() will
+ be called with arguments (nothrow.ptr,code,message,opt). This allows the C++ interface
+ to correctly rethrow exceptions, but might be used from C as well. opt can be used
+ to pass further information (not used yet).
+*/
+
+__PLUMED_WRAPPER_C_BEGIN
+void plumed_cmd_nothrow(plumed p,const char*key,const void*val,plumed_nothrow_handler nothrow);
+__PLUMED_WRAPPER_C_END
/** \relates plumed
- \brief Destructor
+ \brief Destructor.
+
+ It must be used for any object created using \ref plumed_create(),
+ even if the created object is not valid.
\param p The plumed object to be deallocated
*/
+
+__PLUMED_WRAPPER_C_BEGIN
void plumed_finalize(plumed p);
+__PLUMED_WRAPPER_C_END
/** \relates plumed
- \brief Check if plumed is installed (for runtime binding)
+ \brief Check if plumed is installed (for runtime binding).
+
+ Notice that this is equivalent to creating a dummy object and checking if it is valid.
- \return 1 if plumed is installed, to 0 otherwise
+\verbatim
+ // this:
+ //int a=plumed_installed();
+ // is equivalent to this:
+
+ plumed p=plumed_create();
+ int a=plumed_valid(p);
+ plumed_finalize(p);
+
+\endverbatim
+
+ This function is mostly provided for compatibility with PLUMED 2.4, where \ref plumed_valid()
+ was not available. Using \ref plumed_valid() is now preferred since it creates a single object
+ instead of creating a dummy object that is then discarded.
+
+ \return 1 if plumed is installed, 0 otherwise
*/
+
+__PLUMED_WRAPPER_C_BEGIN
int plumed_installed(void);
+__PLUMED_WRAPPER_C_END
+
+/** \relates plumed
+ \brief Check if plumed object is valid. Available as of PLUMED 2.5
+
+ It might return false if plumed is not available at runtime.
+
+ \return 1 if plumed is valid, 0 otherwise
+*/
+
+__PLUMED_WRAPPER_C_BEGIN
+int plumed_valid(plumed p);
+__PLUMED_WRAPPER_C_END
+
+/** \relates plumed
+ \brief Returns the number of references to the underlying object. Available as of PLUMED 2.5.
+*/
+
+__PLUMED_WRAPPER_C_BEGIN
+int plumed_use_count(plumed p);
+__PLUMED_WRAPPER_C_END
+
+
+/* routines to convert char handler from/to plumed objects */
+
+/** \related plumed
+ \brief Converts a C handler to a FORTRAN handler
+
+ \param p The C handler
+ \param c The FORTRAN handler (a char[32])
+
+ This function can be used to convert a plumed object created in C to
+ a plumed handler that can be used in FORTRAN. Notice that the reference counter
+ is not incremented. In other words, the FORTRAN object will be a weak reference.
+ If you later finalize the C handler, the FORTRAN handler will be invalid.
+\verbatim
+#include
+int main(int argc,char*argv[]){
+ plumed p;
+ p=plumed_create();
+ char fortran_handler[32];
+ plumed_c2f(p,fortran_handler);
+ printf("DEBUG: this is a string representation for the plumed handler: %s\n",fortran_handler);
+ fortran_routine(fortran_handler);
+ plumed_finalize(p);
+ return 0;
+}
+\endverbatim
+ Here `fortran_routine` is a routine implemented in FORTRAN that manipulates the
+ fortran_handler.
+*/
+
+__PLUMED_WRAPPER_C_BEGIN
+void plumed_c2f(plumed p,char* c);
+__PLUMED_WRAPPER_C_END
+
+/** \related plumed
+ \brief Converts a FORTRAN handler to a C handler
+ \param c The FORTRAN handler (a char[32])
+ \return The C handler
+
+ This function can be used to convert a plumed object created in FORTRAN
+ to a plumed handler that can be used in C. Notice that the reference counter
+ is not incremented. In other words, the C object will be a weak reference.
+ If you later finalize the FORTRAN handler, the C handler will be invalid.
+\verbatim
+void c_routine(char handler[32]){
+ plumed p;
+ p=plumed_f2c(handler);
+ plumed_cmd(p,"init",NULL);
+}
+\endverbatim
+ Here `c_routine` is a C function that can be called from FORTRAN
+ and interact with the provided plumed handler.
+*/
+
+__PLUMED_WRAPPER_C_BEGIN
+plumed plumed_f2c(const char* c);
+__PLUMED_WRAPPER_C_END
+
+/** \related plumed
+ \brief Converts a plumed object to a void pointer. Available as of PLUMED 2.5.
+
+ It returns a void pointer that can be converted back to a plumed object using \ref plumed_v2c.
+ When compiling without NDEBUG, it checks if the plumed object was properly created.
+ Notice that an invalid object (see \ref plumed_valid) can be converted to void* and back.
+
+ Can be used to store a reference to a plumed object without including the Plumed.h header.
+*/
+
+__PLUMED_WRAPPER_C_BEGIN
+void* plumed_c2v(plumed p);
+__PLUMED_WRAPPER_C_END
+
+
+/** \related plumed
+ \brief Converts a void pointer to a plumed object. Available as of PLUMED 2.5.
+
+ It returns a plumed object from a void pointer obtained with \ref plumed_c2v.
+ When compiling without NDEBUG, it checks if the plumed object was properly created.
+
+ Can be used to store a reference to a plumed object without including the Plumed.h header.
+*/
+
+__PLUMED_WRAPPER_C_BEGIN
+plumed plumed_v2c(void*);
+__PLUMED_WRAPPER_C_END
+
+
+#if __PLUMED_WRAPPER_GLOBAL /*{*/
+
+/* Global C functions are always extern */
+__PLUMED_WRAPPER_EXTERN_C_BEGIN /*{*/
/** \relates plumed
\brief Retrieves an handler to the global structure.
+
+ You can use this if you work on a code that uses the global structure and you want to
+ pass to a generic routine an handler to the same structure. E.g.
+
+\verbatim
+ plumed p=plumed_global();
+ some_routine(p);
+\endverbatim
*/
+extern
plumed plumed_global(void);
/** \relates plumed
- \brief Check if the global interface has been initialized
+ \brief Check if the global interface has been initialized.
\return 1 if plumed has been initialized, 0 otherwise
*/
+extern
int plumed_ginitialized(void);
-/* global C interface, working on a global object */
-
/** \relates plumed
\brief Constructor for the global interface.
- \note Equivalent to plumed_create(), but initialize a static global plumed object
+ \note Equivalent to plumed_create(), but initialize the static global plumed object
*/
+extern
void plumed_gcreate(void);
/** \relates plumed
@@ -265,230 +963,1856 @@ void plumed_gcreate(void);
\param val The argument. It is declared as const to allow calls like plumed_gcmd("A","B"),
but for some choice of key it can change the content
- \note Equivalent to plumed_cmd(), but skipping the plumed argument
+ `plumed_gcmd(a,b);` is equivalent to `plumed_cmd(plumed_global(),a,b);`.
*/
+extern
void plumed_gcmd(const char* key,const void* val);
/** \relates plumed
\brief Destructor for the global interface.
- \note Equivalent to plumed_finalize(), but skipping the plumed argument
+ `plumed_gfinalize(a,b);` is similar to `plumed_finalize(plumed_global(),a,b);`, but not completely
+ equivalent. In particular, plumed_gfinalize() also makes sure that the global object
+ is reset to its initial status. After calling it, \ref plumed_ginitialized() will thus return 0.
*/
+extern
void plumed_gfinalize(void);
-/* routines to convert char handler from/to plumed objects */
+/** \relates plumed
+ \brief Check if global plumed object is valid. Available as of PLUMED 2.5
-/** \related plumed
- \brief Converts a C handler to a FORTRAN handler
+ It might return zero if plumed is not available at runtime.
- \param p The C handler
- \param c The FORTRAN handler (a char[32])
+ \return 1 if plumed is valid, 0 otherwise.
*/
-void plumed_c2f(plumed p,char* c);
+extern
+int plumed_gvalid();
-/** \related plumed
- \brief Converts a FORTRAN handler to a C handler
- \param c The FORTRAN handler (a char[32])
- \return The C handler
-*/
-plumed plumed_f2c(const char* c);
+__PLUMED_WRAPPER_EXTERN_C_END /*}*/
-#ifdef __cplusplus
- }
-#endif
+#endif /*}*/
-#ifdef __cplusplus
+#if defined( __cplusplus) && __PLUMED_WRAPPER_CXX /*{*/
+
+#if __PLUMED_WRAPPER_CXX_STD
+#include /* NULL getenv */
+#include /* strncat strlen */
+#include /* fprintf */
+#else
+#include
+#include
+#include
+#endif
-/* this is to include the NULL pointer */
-#include
+#include /* exception bad_exception */
+#include /* runtime_error logic_error invalid_argument domain_error length_error out_of_range range_error overflow_error underflow_error */
+#include /* string */
+#include /* iostream_category (C++11) ios_base::failure (C++11 and C++<11) */
+#include /* bad_alloc bad_array_new_length (C++11) */
+#include /* bad_typeid bad_cast */
+#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11
+#include /* system_error generic_category system_category */
+#include /* future_category */
+#include /* bad_weak_ptr */
+#include /* bad_function_call */
+#endif
/* C++ interface is hidden in PLMD namespace (same as plumed library) */
namespace PLMD {
+/* Optionally, it is further hidden in an anonymous namespace */
+
+__PLUMED_WRAPPER_ANONYMOUS_BEGIN /*{*/
+
/**
C++ wrapper for \ref plumed.
This class provides a C++ interface to PLUMED.
+ It only containts a \ref plumed object, but wraps it with a number of useful methods.
+ All methods are inlined so as to avoid the compilation of an extra c++ file.
+
*/
-class Plumed{
+class Plumed {
+ /**
+ C structure.
+ */
plumed main;
+
+ /**
+ Error handler used to rethrow exceptions.
+ */
+
+ struct NothrowHandler {
+ /** code used for translating messages */
+ int code;
+ /** short message buffer for non-throwing exceptions */
+ char exception_buffer[__PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER];
+ /** if exception_buffer='\0', message stored as an allocatable string */
+ ::std::string what;
+ /** error code for system_error */
+ int error_code;
+ };
+
+ /**
+ Callback function that sets the error handler.
+
+ opt argument is interpreted as the pointer to a null terminated array of void*.
+ The number of non-null element is expected to be even, and there should be a null element
+ that follows. Every pair of pointers should point
+ to a char, identifying the type of argument passed, and an arbitrary object.
+ Currently used to (optionally) pass error_code.
+ */
+ static void nothrow_handler(void*ptr,int code,const char*what,const void* opt) {
+ NothrowHandler* h=(NothrowHandler*) ptr;
+ h->code=code;
+ h->exception_buffer[0]='\0';
+ h->what.clear();
+ h->error_code=0;
+ /*
+ These codes correspond to exceptions that should not allocate a separate buffer but use the fixed one.
+ Notice that a mismatch between the exceptions using the stack buffer here and those implementing
+ the stack buffer would be in practice harmless. However, it makes sense to be consistent.
+ */
+ if(code==10000 || (code>=11000 && code<12000)) {
+ __PLUMED_WRAPPER_STD strncat(h->exception_buffer,what,__PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER-1);
+ } else {
+ h->what=what;
+ }
+
+ /* interpret optional arguments */
+ const void** options=(const void**)opt;
+ if(options) while(*options) {
+ if(*((char*)*options)=='c') h->error_code=*((int*)*(options+1));
+ options+=2;
+ }
+
+ static const char* debug=__PLUMED_WRAPPER_STD getenv("PLUMED_EXCEPTIONS_DEBUG");
+
+ if(debug) {
+ __PLUMED_WRAPPER_STD fprintf(stderr,"+++ PLUMED_EXCEPTIONS_DEBUG\n");
+ __PLUMED_WRAPPER_STD fprintf(stderr,"+++ code: %d error_code: %d message:\n%s\n",h->code,h->error_code,what);
+ if(__PLUMED_WRAPPER_STD strlen(what) > __PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER-1) __PLUMED_WRAPPER_STD fprintf(stderr,"+++ WARNING: message will be truncated\n");
+ __PLUMED_WRAPPER_STD fprintf(stderr,"+++ END PLUMED_EXCEPTIONS_DEBUG\n");
+ }
+
+ }
+
+ /**
+ Rethrow the exception based on the information saved in the NothrowHandler.
+ */
+
+ static void rethrow(const NothrowHandler&h) {
+ /* The interpretation of the codes should be kept in sync with core/PlumedMainInitializer.cpp */
+ /* check if we are using a full string or a fixes size buffer */
+ const char* msg=(h.exception_buffer[0]?h.exception_buffer:h.what.c_str());
+ if(h.code==1) throw Plumed::Invalid(msg);
+ /* logic errors */
+ if(h.code>=10100 && h.code<10200) {
+ if(h.code>=10105 && h.code<10110) throw ::std::invalid_argument(msg);
+ if(h.code>=10110 && h.code<10115) throw ::std::domain_error(msg);
+ if(h.code>=10115 && h.code<10120) throw ::std::length_error(msg);
+ if(h.code>=10120 && h.code<10125) throw ::std::out_of_range(msg);
+ throw ::std::logic_error(msg);
+ }
+ /* runtime errors */
+ if(h.code>=10200 && h.code<10300) {
+ if(h.code>=10205 && h.code<10210) throw ::std::range_error(msg);
+ if(h.code>=10210 && h.code<10215) throw ::std::overflow_error(msg);
+ if(h.code>=10215 && h.code<10220) throw ::std::underflow_error(msg);
+#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11
+ if(h.code==10220) throw ::std::system_error(h.error_code,::std::generic_category(),msg);
+ if(h.code==10221) throw ::std::system_error(h.error_code,::std::system_category(),msg);
+ if(h.code==10222) throw ::std::system_error(h.error_code,::std::iostream_category(),msg);
+ if(h.code==10223) throw ::std::system_error(h.error_code,::std::future_category(),msg);
+#endif
+ if(h.code>=10230 && h.code<10240) {
+#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11
+// These cases are probably useless as it looks like this should always be std::iostream_category
+ if(h.code==10230) throw ::std::ios_base::failure(msg,std::error_code(h.error_code,::std::generic_category()));
+ if(h.code==10231) throw ::std::ios_base::failure(msg,std::error_code(h.error_code,::std::system_category()));
+ if(h.code==10232) throw ::std::ios_base::failure(msg,std::error_code(h.error_code,::std::iostream_category()));
+ if(h.code==10233) throw ::std::ios_base::failure(msg,std::error_code(h.error_code,::std::future_category()));
+#endif
+ throw ::std::ios_base::failure(msg);
+ }
+ throw ::std::runtime_error(msg);
+ }
+ /* "bad" errors */
+ if(h.code>=11000 && h.code<11100) throw Plumed::std_bad_typeid(msg);
+ if(h.code>=11100 && h.code<11200) throw Plumed::std_bad_cast(msg);
+#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11
+ if(h.code>=11200 && h.code<11300) throw Plumed::std_bad_weak_ptr(msg);
+ if(h.code>=11300 && h.code<11400) throw Plumed::std_bad_function_call(msg);
+#endif
+ if(h.code>=11400 && h.code<11500) {
+#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11
+ if(h.code>=11410 && h.code<11420) throw Plumed::std_bad_array_new_length(msg);
+#endif
+ throw Plumed::std_bad_alloc(msg);
+ }
+ if(h.code>=11500 && h.code<11600) throw Plumed::std_bad_exception(msg);
+ /* lepton error */
+ if(h.code>=19900 && h.code<20000) throw Plumed::LeptonException(msg);
+ /* plumed exceptions */
+ if(h.code>=20000 && h.code<30000) {
+ /* debug - only raised with debug options */
+ if(h.code>=20100 && h.code<20200) throw Plumed::ExceptionDebug(msg);
+ /* error - runtime check */
+ if(h.code>=20200 && h.code<20300) throw Plumed::ExceptionError(msg);
+ throw Plumed::Exception(msg);
+ }
+ /* fallback for any other exception */
+ throw Plumed::std_exception(msg);
+ }
+
+ /**
+ Rethrow the current exception.
+
+ This is useful in order to handle an exception thrown by a kernel <=2.4.
+ Only std exceptions are handled, though some of them are thrown as special
+ Plumed exceptions in order to be attached a message.
+ */
+ static void rethrow() {
+ try {
+ throw;
+ } catch(const ::std::bad_exception & e) {
+ throw Plumed::std_bad_exception(e.what());
+#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11
+ } catch(const ::std::bad_array_new_length & e) {
+ throw Plumed::std_bad_array_new_length(e.what());
+#endif
+ } catch(const ::std::bad_alloc & e) {
+ throw Plumed::std_bad_alloc(e.what());
+#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11
+ } catch(const ::std::bad_function_call & e) {
+ throw Plumed::std_bad_function_call(e.what());
+ } catch(const ::std::bad_weak_ptr & e) {
+ throw Plumed::std_bad_weak_ptr(e.what());
+#endif
+ } catch(const ::std::bad_cast & e) {
+ throw Plumed::std_bad_cast(e.what());
+ } catch(const ::std::bad_typeid & e) {
+ throw Plumed::std_bad_typeid(e.what());
+ // not implemented yet: std::regex_error
+ // we do not allow regex yet due to portability problems with gcc 4.8
+ // as soon as we transition to using it should be straightforward to add
+ } catch(const ::std::ios_base::failure & e) {
+#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11
+ throw ::std::ios_base::failure(e.what(),e.code());
+#else
+ throw ::std::ios_base::failure(e.what());
+#endif
+#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11
+ } catch(const ::std::system_error & e) {
+ throw ::std::system_error(e.code(),e.what());
+#endif
+ } catch(const ::std::underflow_error &e) {
+ throw ::std::underflow_error(e.what());
+ } catch(const ::std::overflow_error &e) {
+ throw ::std::overflow_error(e.what());
+ } catch(const ::std::range_error &e) {
+ throw ::std::range_error(e.what());
+ } catch(const ::std::runtime_error & e) {
+ throw ::std::runtime_error(e.what());
+ // not implemented yet: std::future_error
+ // not clear how useful it would be.
+ } catch(const ::std::out_of_range & e) {
+ throw ::std::out_of_range(e.what());
+ } catch(const ::std::length_error & e) {
+ throw ::std::length_error(e.what());
+ } catch(const ::std::domain_error & e) {
+ throw ::std::domain_error(e.what());
+ } catch(const ::std::invalid_argument & e) {
+ throw ::std::invalid_argument(e.what());
+ } catch(const ::std::logic_error & e) {
+ throw ::std::logic_error(e.what());
+ } catch(const ::std::exception & e) {
+ throw Plumed::std_exception(e.what());
+ } catch(...) {
+ throw Plumed::std_bad_exception("plumed could not translate exception");
+ }
+ }
+
+public:
+
+ /**
+ Base class used to rethrow PLUMED exceptions.
+ */
+
+ class Exception :
+ public ::std::exception
+ {
+ ::std::string msg;
+ public:
+ __PLUMED_WRAPPER_CXX_EXPLICIT Exception(const char* msg): msg(msg) {}
+ const char* what() const __PLUMED_WRAPPER_CXX_NOEXCEPT __PLUMED_WRAPPER_CXX_OVERRIDE {return msg.c_str();}
+ /* Destructor should be declared in order to have the correct throw() */
+ ~Exception() __PLUMED_WRAPPER_CXX_NOEXCEPT __PLUMED_WRAPPER_CXX_OVERRIDE {}
+ };
+
+ /**
+ Used to rethrow a PLMD::ExceptionError
+ */
+
+ class ExceptionError :
+ public Exception {
+ public:
+ __PLUMED_WRAPPER_CXX_EXPLICIT ExceptionError(const char* msg): Exception(msg) {}
+ /* Destructor should be declared in order to have the correct throw() */
+ ~ExceptionError() __PLUMED_WRAPPER_CXX_NOEXCEPT __PLUMED_WRAPPER_CXX_OVERRIDE {}
+ };
+
+ /**
+ Used to rethrow a PLMD::ExceptionDebug
+ */
+
+ class ExceptionDebug :
+ public Exception {
+ public:
+ __PLUMED_WRAPPER_CXX_EXPLICIT ExceptionDebug(const char* msg): Exception(msg) {}
+ /* Destructor should be declared in order to have the correct throw() */
+ ~ExceptionDebug() __PLUMED_WRAPPER_CXX_NOEXCEPT __PLUMED_WRAPPER_CXX_OVERRIDE {}
+ };
+
+ /**
+ Thrown when trying to access an invalid plumed object
+ */
+
+ class Invalid :
+ public Exception {
+ public:
+ __PLUMED_WRAPPER_CXX_EXPLICIT Invalid(const char* msg): Exception(msg) {}
+ /* Destructor should be declared in order to have the correct throw() */
+ ~Invalid() __PLUMED_WRAPPER_CXX_NOEXCEPT __PLUMED_WRAPPER_CXX_OVERRIDE {}
+ };
+
+ /**
+ Class used to rethrow Lepton exceptions.
+ */
+
+ class LeptonException :
+ public ::std::exception
+ {
+ ::std::string msg;
+ public:
+ __PLUMED_WRAPPER_CXX_EXPLICIT LeptonException(const char* msg): msg(msg) {}
+ const char* what() const __PLUMED_WRAPPER_CXX_NOEXCEPT __PLUMED_WRAPPER_CXX_OVERRIDE {return msg.c_str();}
+ /* Destructor should be declared in order to have the correct throw() */
+ ~LeptonException() __PLUMED_WRAPPER_CXX_NOEXCEPT __PLUMED_WRAPPER_CXX_OVERRIDE {}
+ };
+
+private:
+ /*
+ These exceptions are declared as private as they are not supposed to be
+ catched by value. they only exist to allow a buffer to be attached to
+ the std::exceptions that do not contain it already.
+ Notice that these exceptions are those whose constructor should never throw, and as
+ such they use a fixed size buffer.
+ */
+
+#define __PLUMED_WRAPPER_NOSTRING_EXCEPTION(name) \
+ class std_ ## name : \
+ public ::std::name \
+ { \
+ char msg[__PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER]; \
+ public: \
+ __PLUMED_WRAPPER_CXX_EXPLICIT std_ ## name(const char * msg) __PLUMED_WRAPPER_CXX_NOEXCEPT { \
+ this->msg[0]='\0'; \
+ __PLUMED_WRAPPER_STD strncat(this->msg,msg,__PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER-1); \
+ static const char* debug=__PLUMED_WRAPPER_STD getenv("PLUMED_EXCEPTIONS_DEBUG"); \
+ if(debug && __PLUMED_WRAPPER_STD strlen(msg) > __PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER-1) __PLUMED_WRAPPER_STD fprintf(stderr,"+++ WARNING: message will be truncated\n"); \
+ } \
+ std_ ## name(const std_ ## name & other) __PLUMED_WRAPPER_CXX_NOEXCEPT { \
+ msg[0]='\0'; \
+ __PLUMED_WRAPPER_STD strncat(msg,other.msg,__PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER-1); \
+ } \
+ std_ ## name & operator=(const std_ ## name & other) __PLUMED_WRAPPER_CXX_NOEXCEPT { \
+ if(this==&other) return *this;\
+ msg[0]='\0'; \
+ __PLUMED_WRAPPER_STD strncat(msg,other.msg,__PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER-1); \
+ return *this; \
+ } \
+ const char* what() const __PLUMED_WRAPPER_CXX_NOEXCEPT __PLUMED_WRAPPER_CXX_OVERRIDE {return msg;} \
+ ~std_ ## name() __PLUMED_WRAPPER_CXX_NOEXCEPT __PLUMED_WRAPPER_CXX_OVERRIDE {} \
+ };
+
+ __PLUMED_WRAPPER_NOSTRING_EXCEPTION(bad_typeid)
+ __PLUMED_WRAPPER_NOSTRING_EXCEPTION(bad_cast)
+#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11
+ __PLUMED_WRAPPER_NOSTRING_EXCEPTION(bad_weak_ptr)
+ __PLUMED_WRAPPER_NOSTRING_EXCEPTION(bad_function_call)
+#endif
+ __PLUMED_WRAPPER_NOSTRING_EXCEPTION(bad_alloc)
+#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11
+ __PLUMED_WRAPPER_NOSTRING_EXCEPTION(bad_array_new_length)
+#endif
+ __PLUMED_WRAPPER_NOSTRING_EXCEPTION(bad_exception)
+ __PLUMED_WRAPPER_NOSTRING_EXCEPTION(exception)
+
+public:
+
+ /**
+ Check if plumed is installed (for runtime binding)
+ \return true if plumed is installed, false otherwise
+ \note Equivalent to plumed_installed() but returns a bool
+ */
+ static bool installed() __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ return plumed_installed();
+ }
+ /**
+ Check if Plumed object is valid. Available as of PLUMED 2.5
+ \return true if plumed is valid, false otherwise
+ \note Equivalent to plumed_valid() but returns a bool
+ */
+ bool valid() const __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ return plumed_valid(main);
+ }
+#if __cplusplus > 199711L
+ /**
+ Same as \ref valid(). Available as of PLUMED 2.5.
+
+ Allow code such as
+ \verbatim
+ Plumed p;
+ if(!p) raise_error();
+ p.cmd("init");
+ \endverbatim
+
+ In order to avoid ambiguous conversions, this is only allowed when compiling with C++11
+ where it is marked as explicit.
+ */
+ explicit
+ operator bool() const __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ return plumed_valid(main);
+ }
+#endif
+
+ /**
+ Returns the number of references to this object. Available as of PLUMED 2.5.
+ \note Equivalent to plumed_use_count()
+ */
+ int useCount() const __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ return plumed_use_count(main);
+ }
+
+#if __PLUMED_WRAPPER_GLOBAL /*{*/
+ /**
+ Check if global-plumed has been initialized
+ \return true if global plumed object (see global()) is initialized (i.e. if gcreate() has been
+ called), false otherwise.
+ \note Equivalent to plumed_ginitialized() but returns a bool
+ */
+ static bool ginitialized() __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ return plumed_ginitialized();
+ }
+ /**
+ Check if global-plumed is valid
+ \return true if global plumed object (see global()) is valid.
+ \note Equivalent to plumed_gvalid() but returns a bool
+ */
+ static bool gvalid() __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ return plumed_gvalid();
+ }
+ /**
+ Initialize global-plumed.
+ \note Equivalent to plumed_gcreate()
+ */
+ static void gcreate() __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ plumed_gcreate();
+ }
+ /**
+ Send a command to global-plumed
+ \param key The name of the command to be executed
+ \param val The argument. It is declared as const to allow calls like gcmd("A","B"),
+ but for some choice of key it can change the content
+ \note Equivalent to plumed_gcmd()
+ */
+ static void gcmd(const char* key,const void* val=NULL) {
+ global().cmd(key,val);
+ }
+ /**
+ Finalize global-plumed
+ */
+ static void gfinalize() __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ plumed_gfinalize();
+ }
+ /**
+ Returns the Plumed global object
+
+ Notice that the object is copied, thus increasing the reference counter of the
+ global object. In this manner, the global object will survive after a call to
+ \ref gfinalize() if the resulting object is still in scope.
+
+ \return The Plumed global object
+ */
+ static Plumed global() __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ return Plumed(plumed_global());
+ }
+#endif /*}*/
+ /**
+ Constructor.
+
+ Notice that when using runtime binding the constructed object might be
+ invalid. One might check it using the \ref valid() method.
+
+ \note Performs the same task a plumed_create()
+ */
+Plumed()__PLUMED_WRAPPER_CXX_NOEXCEPT :
+#if __PLUMED_WRAPPER_CXX_DEFAULT_INVALID
+ main(plumed_create_invalid())
+#else
+ main(plumed_create())
+#endif
+ {
+ }
+
+ /**
+ Clone a Plumed object from a FORTRAN char* handler.
+
+ \param c The FORTRAN handler (a char[32]).
+
+ The reference counter for the corresponding object will be increased
+ to make sure that the object will be available after plumed_f_finalize is called
+ if the created object is still in scope.
+ */
+__PLUMED_WRAPPER_CXX_EXPLICIT Plumed(const char*c)__PLUMED_WRAPPER_CXX_NOEXCEPT :
+ main(plumed_create_reference_f(c))
+ {
+ }
+
+ /**
+ Create a reference from a void* pointer. Available as of PLUMED 2.5.
+ */
+__PLUMED_WRAPPER_CXX_EXPLICIT Plumed(void*v)__PLUMED_WRAPPER_CXX_NOEXCEPT :
+ main(plumed_create_reference_v(v))
+ {
+ }
+
+ /**
+ Clone a Plumed object from a C plumed structure
+
+ \param p The C plumed structure.
+
+ The reference counter for the corresponding object will be increased
+ to make sure that the object will be available after plumed_finalize is called
+ if the created object is still in scope.
+ */
+__PLUMED_WRAPPER_CXX_EXPLICIT Plumed(plumed p)__PLUMED_WRAPPER_CXX_NOEXCEPT :
+ main(plumed_create_reference(p))
+ {
+ }
+
+ /** Copy constructor.
+
+ Takes a reference, incrementing the reference counter of the corresponding object.
+ */
+Plumed(const Plumed& p)__PLUMED_WRAPPER_CXX_NOEXCEPT :
+ main(plumed_create_reference(p.main))
+ {
+ }
+
+ /** Assignment operator. Available as of PLUMED 2.5.
+
+ Takes a reference,incrementing the reference counter of the corresponding object.
+ */
+ Plumed&operator=(const Plumed&p) __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ if(this != &p) {
+// the check is needed to avoid calling plumed_finalize on moved objects
+ if(main.p) decref();
+ main=plumed_create_reference(p.main);
+ }
+ return *this;
+ }
+
+ /*
+ PLUMED >= 2.4 requires a C++11 compiler.
+ Anyway, since Plumed.h file might be redistributed with other codes
+ and it should be possible to combine it with earlier PLUMED versions,
+ we here explicitly check if C+11 is available before enabling move semantics.
+ */
+#if __cplusplus > 199711L
+ /** Move constructor. Available as of PLUMED 2.5.
+ Only if move semantics is enabled.
+ */
+Plumed(Plumed&&p)__PLUMED_WRAPPER_CXX_NOEXCEPT :
+ main(p.main)
+ {
+ p.main.p=nullptr;
+ }
+ /** Move assignment. Available as of PLUMED 2.5.
+ Only if move semantics is enabled.
+ */
+ Plumed& operator=(Plumed&&p)__PLUMED_WRAPPER_CXX_NOEXCEPT {
+ if(this != &p) {
+// the check is needed to avoid calling plumed_finalize on moved objects
+ if(main.p) decref();
+ main=p.main;
+ p.main.p=nullptr;
+ }
+ return *this;
+ }
+#endif
+ /**
+ Create a PLUMED object loading a specific kernel. Available as of PLUMED 2.5.
+
+ It returns an object created with \ref plumed_create_dlopen. The object is owned and
+ is then finalized in the destructor. It can be used as follows:
+ \verbatim
+ PLMD::Plumed p = PLMD::Plumed::dlopen("/path/to/libplumedKernel.so");
+ // or, equivalenty:
+ // PLMD::Plumed p(PLMD::Plumed::dlopen("/path/to/libplumedKernel.so"));
+ p.cmd("init");
+ \endverbatim
+ or, equivalently, as
+ \verbatim
+ auto p = PLMD::Plumed::dlopen("/path/to/libplumedKernel.so");
+ p.cmd("init");
+ \endverbatim
+ */
+ static Plumed dlopen(const char* path)__PLUMED_WRAPPER_CXX_NOEXCEPT {
+// use decref to remove the extra reference
+ return Plumed(plumed_create_dlopen(path)).decref();
+ }
+
+ /**
+ Create a PLUMED object loading a specific kernel. Available as of PLUMED 2.5.
+
+ Same as \ref dlopen(const char* path), but allows a dlopen mode to be chosen explicitly.
+ */
+ static Plumed dlopen(const char* path,int mode)__PLUMED_WRAPPER_CXX_NOEXCEPT {
+// use decref to remove the extra reference
+ return Plumed(plumed_create_dlopen2(path,mode)).decref();
+ }
+ /** Invalid constructor. Available as of PLUMED 2.5.
+
+ Can be used to initialize an invalid object. It might be useful to postpone
+ the initialization of a Plumed object. Consider the following case
+ \verbatim
+ Plumed p;
+ setenv("PLUMED_KERNEL","/path/to/kernel/libplumedKernel.so",1);
+ p.cmd("init")
+ \endverbatim
+ Here the `p` object will be initialized *before* the `PLUMED_KERNEL` env var has been set.
+ This can be particularly problematic if `p` is stored in some high level class.
+ The following case would do the job
+ \verbatim
+ Plumed p;
+ setenv("PLUMED_KERNEL","/path/to/kernel/libplumedKernel.so",1);
+ p=Plumed();
+ p.cmd("init")
+ \endverbatim
+ However, there will be some error reported related to the attempt to load the kernel
+ when `p` is initialized. The following solution is the optimal one:
+ \verbatim
+ Plumed p(Plumed::makeInvalid());
+ setenv("PLUMED_KERNEL","/path/to/kernel/libplumedKernel.so",1);
+ p=Plumed();
+ p.cmd("init")
+ \endverbatim
+ */
+ static Plumed makeInvalid() __PLUMED_WRAPPER_CXX_NOEXCEPT {
+// use decref to remove the extra reference
+ return Plumed(plumed_create_invalid()).decref();
+ }
+
+ /**
+ Create a valid PLMD::Plumed object.
+
+ Can be used to create a valid object e.g. when Plumed.h was compiled with
+ `-D__PLUMED_WRAPPER_CXX_DEFAULT_INVALID`. For internal usage.
+ */
+
+ static Plumed makeValid()__PLUMED_WRAPPER_CXX_NOEXCEPT {
+// use decref to remove the extra reference
+ return Plumed(plumed_create()).decref();
+ }
+
+
+ /**
+ Retrieve the C plumed structure for this object.
+
+ Notice that the resulting plumed structure is a weak reference and
+ should NOT be finalized, unless a new reference is explicitly added
+ \verbatim
+ Plumed p;
+ plumed c=p;
+ plumed_finalize(c); // <- this is wrong
+ \endverbatim
+ \verbatim
+ Plumed p;
+ plumed c=plumed_create_reference(p);
+ plumed_finalize(c); // <- this is right
+ \endverbatim
+ */
+ operator plumed()const __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ return main;
+ }
+
+ /**
+ Retrieve a FORTRAN handler for this object
+ \param c The FORTRAN handler (a char[32]).
+ Notice that the resulting plumed structure is a weak reference and
+ should NOT be finalized, unless a new reference is explicitly added.
+ */
+ void toFortran(char*c)const __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ plumed_c2f(main,c);
+ }
+
+ /**
+ Retrieve a void* handler for this object. Available as of PLUMED 2.5.
+ Notice that the resulting plumed structure is a weak reference and
+ should NOT be finalized, unless a new reference is explicitly added.
+ */
+ void* toVoid()const __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ return plumed_c2v(main);
+ }
+
+ /**
+ Increase reference counter. Available as of PLUMED 2.5.
+
+ Using this method improperly might interfere with correct object construction
+ and destruction.
+ If you want to play with this, also try to compile using `-D__PLUMED_WRAPPER_DEBUG_REFCOUNT=1` and see what happens.
+
+ A possible usage is to transfer the ownership of a temporary
+ object when it is converted
+ \verbatim
+ plumed p=Plumed::dlopen(path).incref()
+ // without incref(), the just constructed object will be destroyed
+ // when the temporary object is deleted.
+ ... do stuff ...
+ plumed_finalize(p);
+ \endverbatim
+
+ */
+ Plumed& incref() __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ plumed_create_reference(main);
+ return *this;
+ }
+
+ /**
+ Decrease reference counter. Available as of PLUMED 2.5.
+
+ Using this method improperly might interfere with correct object construction
+ and destruction.
+ If you want to play with this, also try to compile using `-D__PLUMED_WRAPPER_DEBUG_REFCOUNT=1` and see what happens.
+ */
+ Plumed& decref() __PLUMED_WRAPPER_CXX_NOEXCEPT {
+// calling decref on a moved plumed object should give an error, so we do not check if main.p!=NULL here:
+ plumed_finalize(main);
+ return *this;
+ }
+
+ /**
+ Send a command to this plumed object
+ \param key The name of the command to be executed
+ \param val The argument. It is declared as const to allow calls like p.cmd("A","B"),
+ but for some choice of key it can change the content
+ \note Similar to \ref plumed_cmd(). It actually called \ref plumed_cmd_nothrow() and
+ rethrow any exception raised within PLUMED.
+ */
+ void cmd(const char*key,const void*val=NULL) {
+ NothrowHandler h;
+ h.code=0;
+ plumed_nothrow_handler nothrow= {&h,nothrow_handler};
+ try {
+ plumed_cmd_nothrow(main,key,val,nothrow);
+ } catch (...) {
+ /*
+ When loading a kernel <=2.4, plumed_cmd_nothrow could throw an exception.
+ If the exception is transmitted through the C interface and arrives here,
+ we translate it so as to free the virtual tables of the loaded kernel.
+ */
+ rethrow();
+ }
+ if(h.code!=0) rethrow(h);
+ }
+
+ /**
+ Destructor
+
+ It calls \ref plumed_finalize(). Notice that this is done also if the
+ constructor failed (that is, if it returned an invalid object). This allows
+ declaring Plumed objects also if PLUMED is actually not available, provided
+ one does not use the \ref cmd method.
+
+ Destructor is virtual so as to allow correct inheritance from Plumed object.
+ */
+#if __PLUMED_WRAPPER_CXX_POLYMORPHIC
+ virtual
+#endif
+ ~Plumed() __PLUMED_WRAPPER_CXX_NOEXCEPT {
+// the check is needed to avoid calling plumed_finalize on moved objects
+ if(main.p) decref();
+ }
+};
+
/**
- keeps track if the object was created from scratch using
- the defaults destructor (cloned=false) or if it was imported
- from C or FORTRAN (cloned-true). In the latter case, the
- plumed_finalize() method is not called when destructing the object,
- since it is expected to be finalized in the C/FORTRAN code
+ \related Plumed
+ Comparison operator. Available as of PLUMED 2.5.
*/
- bool cloned;
-public:
+inline
+bool operator==(const Plumed&a,const Plumed&b) __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ return a.toVoid()==b.toVoid();
+}
+
/**
- Check if plumed is installed (for runtime binding)
- \return true if plumed is installed, false otherwise
+ \related Plumed
+ Comparison operator. Available as of PLUMED 2.5.
*/
- static bool installed();
+inline
+bool operator!=(const Plumed&a,const Plumed&b) __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ return a.toVoid()!=b.toVoid();
+}
+
/**
- Check if global-plumed has been initialized
- \return true if global plumed object (see global()) is initialized (i.e. if gcreate() has been
- called), false otherwise.
+ \related Plumed
+ Comparison operator. Available as of PLUMED 2.5.
*/
- static bool ginitialized();
+inline
+bool operator<=(const Plumed&a,const Plumed&b) __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ return a.toVoid()<=b.toVoid();
+}
+
/**
- Initialize global-plumed
+ \related Plumed
+ Comparison operator. Available as of PLUMED 2.5.
*/
- static void gcreate();
+inline
+bool operator<(const Plumed&a,const Plumed&b) __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ return a.toVoid()=(const Plumed&a,const Plumed&b) __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ return a.toVoid()>=b.toVoid();
+}
+
/**
- Finalize global-plumed
+ \related Plumed
+ Comparison operator. Available as of PLUMED 2.5.
+*/
+inline
+bool operator>(const Plumed&a,const Plumed&b) __PLUMED_WRAPPER_CXX_NOEXCEPT {
+ return a.toVoid()>b.toVoid();
+}
+
+__PLUMED_WRAPPER_ANONYMOUS_END /*}*/
+
+}
+
+#endif /*}*/
+
+#endif /*}*/
+
+/* END OF DECLARATIONS */
+
+/*
+
+ 1: emit implementation
+ 0: do not emit implementation
+
+ Allows an implementation to be emitted together with the declarations.
+
+ Used to decide if definitions should be emitted. This macro could have a different
+ value when Plumed.h is reincluded. As a consequence, we map it to a local
+ macro (__PLUMED_WRAPPER_IMPLEMENTATION_) that is reset at the end of this file.
+*/
+
+#ifdef __PLUMED_WRAPPER_IMPLEMENTATION
+#define __PLUMED_WRAPPER_IMPLEMENTATION_ __PLUMED_WRAPPER_IMPLEMENTATION
+#else
+#define __PLUMED_WRAPPER_IMPLEMENTATION_ 0
+#endif
+
+/* BEGINNING OF DEFINITIONS */
+
+#if __PLUMED_WRAPPER_IMPLEMENTATION_ /*{*/
+#ifndef __PLUMED_wrapper_Plumed_implementation /*{*/
+#define __PLUMED_wrapper_Plumed_implementation
+
+/*
+ the following macros only control the implementation
+*/
+
+/*
+ 1: enable the definition of plumed_symbol_table_reexport
+ 0: does not enable the definition of plumed_symbol_table_reexport
+
+ This is only needed in the official plumed library to make
+ the symbol table available. This is a hack to reexport the function table
+ and is only needed when creating the library libplumed.so.
+*/
+
+#ifndef __PLUMED_WRAPPER_REEXPORT_SYMBOL_TABLE
+#define __PLUMED_WRAPPER_REEXPORT_SYMBOL_TABLE 0
+#endif
+
+/*
+ 1: write on stderr changes in reference counters
+ 0: do not write changes in reference counters
+
+ Used for debugging.
+
+ Only used in definitions.
*/
- static void gfinalize();
+
+#ifndef __PLUMED_WRAPPER_DEBUG_REFCOUNT
+#define __PLUMED_WRAPPER_DEBUG_REFCOUNT 0
+#endif
+
+/*
+ 1: emit plumed_kernel_register function (default)
+ 0: do not emit plumed_kernel_register function
+
+ This function is only needed to avoid an extra warning when loading old (<=2.4) kernels.
+ We might change its default in the future.
+
+ Used only in definitions.
+*/
+
+#ifndef __PLUMED_WRAPPER_KERNEL_REGISTER
+#define __PLUMED_WRAPPER_KERNEL_REGISTER 1
+#endif
+
+/*
+ 1: emit Fortran wrappers
+ 0: do not emit Fortran wrappers (default)
+
+ Used only in definitions.
+*/
+
+#ifndef __PLUMED_WRAPPER_FORTRAN
+#define __PLUMED_WRAPPER_FORTRAN 0
+#endif
+
+/*
+ With internal interface, it does not make sence to emit kernel register or fortran interfaces
+*/
+
+#if ! __PLUMED_WRAPPER_EXTERN /*{*/
+#undef __PLUMED_WRAPPER_KERNEL_REGISTER
+#define __PLUMED_WRAPPER_KERNEL_REGISTER 0
+#undef __PLUMED_WRAPPER_FORTRAN
+#define __PLUMED_WRAPPER_FORTRAN 0
+#endif /*}*/
+
+#ifdef __PLUMED_HAS_DLOPEN
+#include /* dlopen dlerror dlsym */
+#endif
+
+#if __PLUMED_WRAPPER_CXX_STD
+#include /* fprintf */
+#include /* memcpy strlen strncpy memcmp memmove strcmp memcpy */
+#include /* assert */
+#include /* getenv malloc free abort exit */
+#include /* CHAR_BIT */
+#else
+#include
+#include
+#include
+#include
+#include
+#endif
+
/**
- Returns the Plumed global object
- \return The Plumed global object
+ Function pointer to plumed_create
*/
- static Plumed global();
+
+typedef void*(*plumed_create_pointer)(void);
/**
- Constructor
+ Function pointer to plumed_cmd
*/
- Plumed();
+typedef void(*plumed_cmd_pointer)(void*,const char*,const void*);
+
/**
- Clone a Plumed object from a FORTRAN char* handler
- \param c The FORTRAN handler (a char[32]).
+ Function pointer to plumed_finalize
+*/
+typedef void(*plumed_finalize_pointer)(void*);
- \attention The Plumed object created in this manner
- will not finalize the corresponding plumed structure.
- It is expected that the FORTRAN code calls plumed_c_finalize for it
+/**
+ Holder for plumedmain function pointers.
*/
- Plumed(const char*c);
+typedef struct {
+ plumed_create_pointer create;
+ plumed_cmd_pointer cmd;
+ plumed_finalize_pointer finalize;
+} plumed_plumedmain_function_holder;
+
/**
- Clone a Plumed object from a C plumed structure
- \param p The C plumed structure.
+ Holder for plumed symbol table.
+
+ The table contains pointers to function exported from plumed. Functions can be added increasing the version number.
+ Notice that the default way to extend functionalities is by adding cmd strings. This is a last resort, and all new
+ functions should be explicitly motivated. Here's the addition:
+
+ version=2, cmd_nothrow.
+
+ This function accepts an extra argument `plumed_nothrow_handler*handler`.
+ In case an exception is thrown withint plumed, it just calls `handler->handler(handler->ptr,code,message,opt)` and return.
+ An alternative would have been to install an error handler (with a call to cmd("setErrorHandler")). However, the cost
+ of doing it everytime Plumed::cmd is called is too high. On the other hand, installing it only at object construction
+ is very risky since and object created in that way would not report any error if manipulated from the C interface.
+ So, it looks like this is the only possibility.
- \attention The Plumed object created in this manner
- will not finalize the corresponding plumed structure.
- It is expected that the C code calls plumed_finalize for it
-*/
- Plumed(plumed p);
-private:
-/** Copy constructor is disabled (private and unimplemented)
- The problem here is that after copying it will not be clear who is
- going to finalize the corresponding plumed structure.
*/
- Plumed(const Plumed&);
-/** Assignment operator is disabled (private and unimplemented)
- The problem here is that after copying it will not be clear who is
- going to finalize the corresponding plumed structure.
+typedef struct {
+ /**
+ Version number.
+
+ Minimum value is 1.
+ */
+ int version;
+ /**
+ Pointers to standard plumed functions (create/cmd/finalize).
+
+ Always available.
+ */
+ plumed_plumedmain_function_holder functions;
+ /**
+ Pointer to a cmd function guaranteed not to throw exceptions.
+
+ Available with version>=2.
+ */
+ void (*cmd_nothrow)(void*plumed,const char*key,const void*val,plumed_nothrow_handler);
+} plumed_symbol_table_type;
+
+/* Utility to convert function pointers to pointers, just for the sake of printing them */
+#define __PLUMED_CONVERT_FPTR(ptr,fptr) { ptr=NULL; __PLUMED_WRAPPER_STD memcpy(&ptr,&fptr,(sizeof(fptr)>sizeof(ptr)?sizeof(ptr):sizeof(fptr))); }
+
+#define __PLUMED_GETENV __PLUMED_WRAPPER_STD getenv
+#define __PLUMED_FPRINTF __PLUMED_WRAPPER_STD fprintf
+#define __PLUMED_MALLOC __PLUMED_WRAPPER_STD malloc
+#define __PLUMED_FREE __PLUMED_WRAPPER_STD free
+
+/**
+ Historically (PLUMED<=2.4) register for plumedmain function pointers.
+ As of PLUMED>=2.5, this function does not do anything except for reporting the attempt to register
+ something. It always returns NULL. The function should be here anyway to allow an incomplete
+ libplumedKernel (<=2.4), expecting this function to be present, to be loaded correctly.
*/
- Plumed&operator=(const Plumed&);
-public:
+#if __PLUMED_WRAPPER_KERNEL_REGISTER
+/* Since it is only called from outside, it must be hardcoded to be extern */
+__PLUMED_WRAPPER_EXTERN_C_BEGIN /*{*/
+extern plumed_plumedmain_function_holder* plumed_kernel_register(const plumed_plumedmain_function_holder*);
+plumed_plumedmain_function_holder* plumed_kernel_register(const plumed_plumedmain_function_holder* f) {
+ void* tmpptr;
+ if(f) {
+ if(__PLUMED_GETENV("PLUMED_LOAD_DEBUG")) {
+ __PLUMED_FPRINTF(stderr,"+++ Ignoring registration at %p (",(void*)f);
+ __PLUMED_CONVERT_FPTR(tmpptr,f->create);
+ __PLUMED_FPRINTF(stderr,"%p,",tmpptr);
+ __PLUMED_CONVERT_FPTR(tmpptr,f->cmd);
+ __PLUMED_FPRINTF(stderr,"%p,",tmpptr);
+ __PLUMED_CONVERT_FPTR(tmpptr,f->finalize);
+ __PLUMED_FPRINTF(stderr,"%p) +++\n",tmpptr);
+ }
+ }
+ return NULL;
+}
+__PLUMED_WRAPPER_EXTERN_C_END /*}*/
+#endif
+
+#if defined( __PLUMED_HAS_DLOPEN) /*{*/
/**
- Retrieve the C plumed structure for this object
+Try to dlopen a path with a given mode.
+If the dlopen command fails, it tries to strip the `Kernel` part of the name.
+
+This function is declared static (internal linkage) so that it is not visible from outside.
+It is first declared then defined to make sure it is a regular C static function.
*/
- operator plumed()const;
+
+__PLUMED_WRAPPER_INTERNALS_BEGIN
+void* plumed_attempt_dlopen(const char*path,int mode) {
+ char* pathcopy;
+ void* p;
+ char* pc;
+ size_t strlenpath;
+ FILE* fp;
+ pathcopy=NULL;
+ p=NULL;
+ pc=NULL;
+ strlenpath=0;
+ fp=__PLUMED_WRAPPER_STD fopen(path,"r");
+ if(!fp) {
+ __PLUMED_FPRINTF(stderr,"+++ File %s does not exist or cannot be read\n",path);
+ return NULL;
+ }
+ __PLUMED_WRAPPER_STD fclose(fp);
+ dlerror();
+ p=dlopen(path,mode);
+ if(!p) {
+ /*
+ Something went wrong. We try to remove "Kernel" string from the PLUMED_KERNEL variable
+ and load directly the shared library. Notice that this particular path is only expected
+ to be necessary when using PLUMED<=2.4 and the symbols in the main executable are
+ not visible. All the other cases (either PLUMED>=2.5 or symbols in the main executable visible)
+ should work correctly without entering here.
+ */
+ __PLUMED_FPRINTF(stderr,"+++ An error occurred. Message from dlopen(): %s +++\n",dlerror());
+ strlenpath=__PLUMED_WRAPPER_STD strlen(path);
+ pathcopy=(char*) __PLUMED_MALLOC(strlenpath+1);
+ __PLUMED_WRAPPER_STD strncpy(pathcopy,path,strlenpath+1);
+ pc=pathcopy+strlenpath-6;
+ while(pc>=pathcopy && __PLUMED_WRAPPER_STD memcmp(pc,"Kernel",6)) pc--;
+ if(pc>=pathcopy) {
+ __PLUMED_WRAPPER_STD memmove(pc, pc+6, __PLUMED_WRAPPER_STD strlen(pc)-5);
+ __PLUMED_FPRINTF(stderr,"+++ This error is expected if you are trying to load a kernel <=2.4\n");
+ __PLUMED_FPRINTF(stderr,"+++ Trying %s +++\n",pathcopy);
+ fp=__PLUMED_WRAPPER_STD fopen(path,"r");
+ if(!fp) {
+ __PLUMED_FPRINTF(stderr,"+++ File %s does not exist or cannot be read\n",pathcopy);
+ __PLUMED_FREE(pathcopy);
+ return NULL;
+ }
+ __PLUMED_WRAPPER_STD fclose(fp);
+ dlerror();
+ p=dlopen(pathcopy,mode);
+ if(!p) __PLUMED_FPRINTF(stderr,"+++ An error occurred. Message from dlopen(): %s +++\n",dlerror());
+ }
+ __PLUMED_FREE(pathcopy);
+ }
+ return p;
+}
+__PLUMED_WRAPPER_INTERNALS_END
+
/**
- Retrieve a FORTRAN handler for this object
- \param c The FORTRAN handler (a char[32]).
+ Utility to search for a function.
*/
- void toFortran(char*c)const;
+#define __PLUMED_SEARCH_FUNCTION(tmpptr,handle,func,name,debug) \
+ if(!func) { \
+ tmpptr=dlsym(handle,name); \
+ if(tmpptr) { \
+ *(void **)(&func)=tmpptr; \
+ if(debug) __PLUMED_FPRINTF(stderr,"+++ %s found at %p +++\n",name,tmpptr); \
+ } else { \
+ if(debug) __PLUMED_FPRINTF(stderr,"+++ Function %s not found\n",name); \
+ } \
+ }
+
/**
- Send a command to this plumed object
- \param key The name of the command to be executed
- \param val The argument. It is declared as const to allow calls like p.cmd("A","B"),
- but for some choice of key it can change the content
+Search symbols in a dlopened library.
+
+This function is declared static (internal linkage) so that it is not visible from outside.
+*/
+__PLUMED_WRAPPER_INTERNALS_BEGIN
+void plumed_search_symbols(void* handle, plumed_plumedmain_function_holder* f,plumed_symbol_table_type** table) {
+ plumed_plumedmain_function_holder functions;
+ plumed_symbol_table_type* table_ptr;
+ void* tmpptr;
+ char* debug;
+ functions.create=NULL;
+ functions.cmd=NULL;
+ functions.finalize=NULL;
+ table_ptr=NULL;
+ tmpptr=NULL;
+ /*
+ Notice that as of PLUMED 2.5 we ignore self registrations.
+ Pointers are searched in the form of a single pointer to a structure, which
+ is the standard way in PLUMED 2.5, as well as using alternative names used in
+ PLUMED 2.0 to 2.4 (e.g. plumedmain_create) and in some intermediate versions between
+ PLUMED 2.4 and 2.5 (e.g. plumed_plumedmain_create). The last chance is probably
+ unnecessary and might be removed at some point.
+ */
+ debug=__PLUMED_GETENV("PLUMED_LOAD_DEBUG");
+ table_ptr=(plumed_symbol_table_type*) dlsym(handle,"plumed_symbol_table");
+ if(table_ptr) functions=table_ptr->functions;
+ if(debug) {
+ if(table_ptr) {
+ __PLUMED_FPRINTF(stderr,"+++ plumed_symbol_table version %i found at %p +++\n",table_ptr->version,(void*)table_ptr);
+ __PLUMED_FPRINTF(stderr,"+++ plumed_function_pointers found at %p (",(void*)&table_ptr->functions);
+ __PLUMED_CONVERT_FPTR(tmpptr,functions.create);
+ __PLUMED_FPRINTF(stderr,"%p,",tmpptr);
+ __PLUMED_CONVERT_FPTR(tmpptr,functions.cmd);
+ __PLUMED_FPRINTF(stderr,"%p,",tmpptr);
+ __PLUMED_CONVERT_FPTR(tmpptr,functions.finalize);
+ __PLUMED_FPRINTF(stderr,"%p) +++\n",tmpptr);
+ } else {
+ __PLUMED_FPRINTF(stderr,"+++ plumed_symbol_table (available in PLUMED>=2.5) not found, perhaps kernel is older +++\n");
+ }
+ }
+ /* only searches if they were not found already */
+ __PLUMED_SEARCH_FUNCTION(tmpptr,handle,functions.create,"plumedmain_create",debug);
+ __PLUMED_SEARCH_FUNCTION(tmpptr,handle,functions.create,"plumed_plumedmain_create",debug);
+ __PLUMED_SEARCH_FUNCTION(tmpptr,handle,functions.cmd,"plumedmain_cmd",debug);
+ __PLUMED_SEARCH_FUNCTION(tmpptr,handle,functions.cmd,"plumed_plumedmain_cmd",debug);
+ __PLUMED_SEARCH_FUNCTION(tmpptr,handle,functions.finalize,"plumedmain_finalize",debug);
+ __PLUMED_SEARCH_FUNCTION(tmpptr,handle,functions.finalize,"plumed_plumedmain_finalize",debug);
+ if(functions.create && functions.cmd && functions.finalize) {
+ if(debug) __PLUMED_FPRINTF(stderr,"+++ PLUMED was loaded correctly +++\n");
+ *f=functions;
+ if(table) *table=table_ptr;
+ } else {
+ if(!functions.create) __PLUMED_FPRINTF(stderr,"+++ Pointer to (plumed_)plumedmain_create not found +++\n");
+ if(!functions.cmd) __PLUMED_FPRINTF(stderr,"+++ Pointer to (plumed_)plumedmain_cmd not found +++\n");
+ if(!functions.finalize) __PLUMED_FPRINTF(stderr,"+++ Pointer to (plumed_)plumedmain_finalize not found +++\n");
+ f->create=NULL;
+ f->cmd=NULL;
+ f->finalize=NULL;
+ if(table) *table=NULL;
+ }
+}
+__PLUMED_WRAPPER_INTERNALS_END
+
+#endif /*}*/
+
+
+#if __PLUMED_WRAPPER_REEXPORT_SYMBOL_TABLE
+
+/*
+ Here is the case where plumed_symbol_table is
+ visible as extern. We first declare it (together with plumed_symbol_table_init) ...
+*/
+
+__PLUMED_WRAPPER_EXTERN_C_BEGIN
+extern
+plumed_symbol_table_type plumed_symbol_table;
+__PLUMED_WRAPPER_EXTERN_C_END
+__PLUMED_WRAPPER_EXTERN_C_BEGIN
+extern
+void plumed_symbol_table_init(void);
+__PLUMED_WRAPPER_EXTERN_C_END
+
+/*
+ ... and then make available a function that returns the address
+ of the symbol table.
+*/
+__PLUMED_WRAPPER_C_BEGIN
+plumed_symbol_table_type* plumed_symbol_table_reexport() {
+ /* make sure the table is initialized */
+ plumed_symbol_table_init();
+ return &plumed_symbol_table;
+}
+__PLUMED_WRAPPER_C_END
+
+#else
+
+/*
+ Here is the case where plumed_symbol_table is not
+ visible as extern. We thus assume that plumed_symbol_table_reexport is
+ available.
+*/
+
+__PLUMED_WRAPPER_EXTERN_C_BEGIN
+extern plumed_symbol_table_type* plumed_symbol_table_reexport();
+__PLUMED_WRAPPER_EXTERN_C_END
+#endif
+
+
+/*
+ Returns the global pointers, either those available at link time or those
+ found in the library loaded at PLUMED_KERNEL env var.
+ If plumed_symbol_table_ptr is not NULL, it is used to return a pointer to the symbol table
+ (if available).
+ Notice that problems can be detected checking if the functions have a NULL ptr.
+ On the other hand, the symbol table pointer might be NULL just because the plumed version is <=2.4.
+ If handle is not NULL, it is used to return a dlopen handle that could be subsequently dlclosed.
*/
- void cmd(const char*key,const void*val=NULL);
+__PLUMED_WRAPPER_INTERNALS_BEGIN
+void plumed_retrieve_functions(plumed_plumedmain_function_holder* functions, plumed_symbol_table_type** plumed_symbol_table_ptr,void** handle) {
+#if ! __PLUMED_WRAPPER_LINK_RUNTIME
+ /*
+ Real interface, constructed using the symbol table obtained with plumed_symbol_table_reexport.
+ This makes the symbols hardcoded and independent of a mis-set PLUMED_KERNEL variable.
+ */
+ plumed_symbol_table_type* ptr=plumed_symbol_table_reexport();
+ if(plumed_symbol_table_ptr) *plumed_symbol_table_ptr=ptr;
+ if(handle) *handle=NULL;
+ if(functions) *functions=ptr->functions;
+#elif ! defined(__PLUMED_HAS_DLOPEN)
+ /*
+ When dlopen is not available, we hard code them to NULL
+ */
+ fprintf(stderr,"+++ PLUMED has been compiled without dlopen and without a static kernel +++\n");
+ plumed_plumedmain_function_holder g= {NULL,NULL,NULL};
+ if(plumed_symbol_table_ptr) *plumed_symbol_table_ptr=NULL;
+ if(handle) *handle=NULL;
+ if(functions) *functions=g;
+#else
+ /*
+ On the other hand, for runtime binding, we use dlsym to find the relevant functions.
+ */
+ plumed_plumedmain_function_holder g;
+ /* search is done once and only once */
+ const char* path;
+ void* p;
+ char* debug;
+ int dlopenmode;
+ g.create=NULL;
+ g.cmd=NULL;
+ g.finalize=NULL;
+ path=__PLUMED_GETENV("PLUMED_KERNEL");
+ p=NULL;
+ debug=__PLUMED_GETENV("PLUMED_LOAD_DEBUG");
+ dlopenmode=0;
+ if(plumed_symbol_table_ptr) *plumed_symbol_table_ptr=NULL;
+ if(handle) *handle=NULL;
+#ifdef __PLUMED_DEFAULT_KERNEL
+ /*
+ This variable allows a default path for the kernel to be hardcoded.
+ Can be useful for hardcoding the predefined plumed location
+ still allowing the user to override this choice setting PLUMED_KERNEL.
+ The path should be chosen at compile time adding e.g.
+ -D__PLUMED_DEFAULT_KERNEL=/opt/local/lib/libplumed.dylib
+ */
+ /* This is required to add quotes */
+#define PLUMED_QUOTE_DIRECT(name) #name
+#define PLUMED_QUOTE(macro) PLUMED_QUOTE_DIRECT(macro)
+ if(! (path && (*path) )) path=PLUMED_QUOTE(__PLUMED_DEFAULT_KERNEL);
+#endif
+ if(path && (*path)) {
+ fprintf(stderr,"+++ Loading the PLUMED kernel runtime +++\n");
+ fprintf(stderr,"+++ PLUMED_KERNEL=\"%s\" +++\n",path);
+ if(debug) __PLUMED_FPRINTF(stderr,"+++ Loading with mode RTLD_NOW");
+ dlopenmode=RTLD_NOW;
+ if(__PLUMED_GETENV("PLUMED_LOAD_NAMESPACE") && !__PLUMED_WRAPPER_STD strcmp(__PLUMED_GETENV("PLUMED_LOAD_NAMESPACE"),"LOCAL")) {
+ dlopenmode=dlopenmode|RTLD_LOCAL;
+ if(debug) __PLUMED_FPRINTF(stderr,"|RTLD_LOCAL");
+ } else {
+ dlopenmode=dlopenmode|RTLD_GLOBAL;
+ if(debug) __PLUMED_FPRINTF(stderr,"|RTLD_GLOBAL");
+ }
+#ifdef RTLD_DEEPBIND
+ if(!__PLUMED_GETENV("PLUMED_LOAD_NODEEPBIND")) {
+ dlopenmode=dlopenmode|RTLD_DEEPBIND;
+ if(debug) __PLUMED_FPRINTF(stderr,"|RTLD_DEEPBIND");
+ }
+#endif
+ if(debug) __PLUMED_FPRINTF(stderr," +++\n");
+ p=plumed_attempt_dlopen(path,dlopenmode);
+ if(p) plumed_search_symbols(p,&g,plumed_symbol_table_ptr);
+ }
+ if(handle) *handle=p;
+ if(functions) *functions=g;
+#endif
+}
+__PLUMED_WRAPPER_INTERNALS_END
+
/**
- Destructor
+ Implementation.
+ Small object used to store pointers directly into the plumed object defined in Plumed.h.
+ This allows avoiding the extra function call to plumed_retrieve_functions at every cmd,
+ at the cost of an extra indirection.
+*/
+typedef struct {
+ /* allows errors with pointers to be found when debugging */
+ char magic[6];
+ /* reference count */
+ int refcount;
+ /* handler to dlopened library. NULL if there was no library opened */
+ void* dlhandle;
+ /* non zero if, upon destruction, the library should be dlclosed */
+ int dlclose;
+ /* 1 if path to kernel was taken from PLUMED_KERNEL var, 0 otherwise */
+ int used_plumed_kernel;
+ /* function pointers */
+ plumed_plumedmain_function_holder functions;
+ /* pointer to the symbol table. NULL if kernel <=2.4 */
+ plumed_symbol_table_type* table;
+ /* pointer to plumed object */
+ void* p;
+} plumed_implementation;
+
+__PLUMED_WRAPPER_INTERNALS_BEGIN
+plumed_implementation* plumed_malloc_pimpl() {
+ plumed_implementation* pimpl;
+ /* allocate space for implementation object. this is free-ed in plumed_finalize(). */
+ pimpl=(plumed_implementation*) __PLUMED_MALLOC(sizeof(plumed_implementation));
+ if(!pimpl) {
+ __PLUMED_FPRINTF(stderr,"+++ Allocation error +++\n");
+ __PLUMED_WRAPPER_STD abort();
+ }
+ __PLUMED_WRAPPER_STD memcpy(pimpl->magic,"pLuMEd",6);
+ pimpl->refcount=1;
+#if __PLUMED_WRAPPER_DEBUG_REFCOUNT
+ fprintf(stderr,"refcount: new at %p\n",(void*)pimpl);
+#endif
+ pimpl->dlhandle=NULL;
+ pimpl->dlclose=0;
+ pimpl->used_plumed_kernel=0;
+ pimpl->functions.create=NULL;
+ pimpl->functions.cmd=NULL;
+ pimpl->functions.finalize=NULL;
+ pimpl->table=NULL;
+ pimpl->p=NULL;
+ return pimpl;
+}
+__PLUMED_WRAPPER_INTERNALS_END
+
+#ifndef NDEBUG
+
+__PLUMED_WRAPPER_INTERNALS_BEGIN
+int plumed_check_pimpl(plumed_implementation*pimpl) {
+ if(!pimpl) return 0;
+ if(__PLUMED_WRAPPER_STD memcmp(pimpl->magic,"pLuMEd",6)) return 0;
+ return 1;
+}
+__PLUMED_WRAPPER_INTERNALS_END
+#endif
+
+/* C wrappers: */
+
+__PLUMED_WRAPPER_C_BEGIN
+plumed plumed_create(void) {
+ /* returned object */
+ plumed p;
+ /* pointer to implementation */
+ plumed_implementation* pimpl;
+ /* allocate space for implementation object. this is free-ed in plumed_finalize(). */
+ pimpl=plumed_malloc_pimpl();
+ /* store pointers in pimpl */
+ plumed_retrieve_functions(&pimpl->functions,&pimpl->table,&pimpl->dlhandle);
+#if __PLUMED_WRAPPER_LINK_RUNTIME
+ /* note if PLUMED_KERNEL variable was used */
+ pimpl->used_plumed_kernel=1;
+#endif
+ /* note if handle should not be dlclosed */
+ pimpl->dlclose=1;
+ if(__PLUMED_GETENV("PLUMED_LOAD_DLCLOSE") && !__PLUMED_WRAPPER_STD strcmp(__PLUMED_GETENV("PLUMED_LOAD_DLCLOSE"),"no")) pimpl->dlclose=0;
+ /* in case of failure, return */
+ /* the resulting object should be plumed_finalized, though you cannot use plumed_cmd */
+ if(!pimpl->functions.create) {
+ /* store pimpl in returned object */
+ p.p=pimpl;
+ return p;
+ }
+ assert(pimpl->functions.cmd);
+ assert(pimpl->functions.finalize);
+ /* obtain object */
+ pimpl->p=(*(pimpl->functions.create))();
+ /* notice: we do not assert pimpl->p since in principle it might be nullptr */
+ /* user might identify this using plumed_valid() */
+ /* store pimpl in returned object */
+ p.p=pimpl;
+ return p;
+}
+__PLUMED_WRAPPER_C_END
+
+__PLUMED_WRAPPER_C_BEGIN
+plumed plumed_create_dlopen(const char*path) {
+ int dlopenmode;
+ /* plumed_create_dlopen always uses RTLD_LOCAL and, when possible, RTLD_DEEPBIND to allow multiple versions */
+#ifdef __PLUMED_HAS_DLOPEN
+ dlopenmode=RTLD_NOW|RTLD_LOCAL;
+#ifdef RTLD_DEEPBIND
+ dlopenmode=dlopenmode|RTLD_DEEPBIND;
+#endif
+#else
+ dlopenmode=0;
+#endif
+ return plumed_create_dlopen2(path,dlopenmode);
+}
+__PLUMED_WRAPPER_C_END
+
+__PLUMED_WRAPPER_C_BEGIN
+plumed plumed_create_dlopen2(const char*path,int mode) {
+ /* returned object */
+ plumed p;
+ /* pointer to implementation */
+ plumed_implementation* pimpl;
+ /* allocate space for implementation object. this is free-ed in plumed_finalize(). */
+ pimpl=plumed_malloc_pimpl();
+#ifdef __PLUMED_HAS_DLOPEN
+ if(path) pimpl->dlhandle=plumed_attempt_dlopen(path,mode);
+ /* mark this library to be dlclosed when the object is finalized */
+ pimpl->dlclose=1;
+ if(pimpl->dlhandle) plumed_search_symbols(pimpl->dlhandle,&pimpl->functions,&pimpl->table);
+#endif
+ if(!pimpl->functions.create) {
+ p.p=pimpl;
+ return p;
+ }
+ assert(pimpl->functions.cmd);
+ assert(pimpl->functions.finalize);
+ /* obtain object */
+ pimpl->p=(*(pimpl->functions.create))();
+ /* notice: we do not assert pimpl->p since in principle it might be nullptr */
+ /* user might identify this using plumed_valid() */
+ /* store pimpl in returned object */
+ p.p=pimpl;
+ return p;
+}
+__PLUMED_WRAPPER_C_END
+
+__PLUMED_WRAPPER_C_BEGIN
+plumed plumed_create_reference(plumed p) {
+ plumed_implementation* pimpl;
+ /* obtain pimpl */
+ pimpl=(plumed_implementation*) p.p;
+ assert(plumed_check_pimpl(pimpl));
+ /* increase reference count */
+ pimpl->refcount++;
+#if __PLUMED_WRAPPER_DEBUG_REFCOUNT
+ fprintf(stderr,"refcount: increase at %p\n",(void*)pimpl);
+#endif
+ return p;
+}
+__PLUMED_WRAPPER_C_END
+
+__PLUMED_WRAPPER_C_BEGIN
+plumed plumed_create_reference_v(void*v) {
+ return plumed_create_reference(plumed_v2c(v));
+}
+__PLUMED_WRAPPER_C_END
+
+__PLUMED_WRAPPER_C_BEGIN
+plumed plumed_create_reference_f(const char*f) {
+ return plumed_create_reference(plumed_f2c(f));
+}
+__PLUMED_WRAPPER_C_END
+
+__PLUMED_WRAPPER_C_BEGIN
+plumed plumed_create_invalid() {
+ plumed p;
+ plumed_implementation* pimpl;
+ pimpl=plumed_malloc_pimpl();
+ p.p=pimpl;
+ return p;
+}
+__PLUMED_WRAPPER_C_END
+
+__PLUMED_WRAPPER_C_BEGIN
+void plumed_cmd(plumed p,const char*key,const void*val) {
+ plumed_implementation* pimpl;
+ /* obtain pimpl */
+ pimpl=(plumed_implementation*) p.p;
+ assert(plumed_check_pimpl(pimpl));
+ if(!pimpl->p) {
+ __PLUMED_FPRINTF(stderr,"+++ ERROR: You are trying to use an invalid plumed object. +++\n");
+ if(pimpl->used_plumed_kernel) __PLUMED_FPRINTF(stderr,"+++ Check your PLUMED_KERNEL environment variable. +++\n");
+ __PLUMED_WRAPPER_STD exit(1);
+ }
+ assert(pimpl->functions.create);
+ assert(pimpl->functions.cmd);
+ assert(pimpl->functions.finalize);
+ /* execute */
+ (*(pimpl->functions.cmd))(pimpl->p,key,val);
+}
+__PLUMED_WRAPPER_C_END
+
+__PLUMED_WRAPPER_C_BEGIN
+void plumed_cmd_nothrow(plumed p,const char*key,const void*val,plumed_nothrow_handler nothrow) {
+ plumed_implementation* pimpl;
+ /* obtain pimpl */
+ pimpl=(plumed_implementation*) p.p;
+ assert(plumed_check_pimpl(pimpl));
+ if(!pimpl->p) {
+ if(pimpl->used_plumed_kernel) {
+ nothrow.handler(nothrow.ptr,1,"You are trying to use plumed, but it is not available.\nCheck your PLUMED_KERNEL environment variable.",NULL);
+ } else {
+ nothrow.handler(nothrow.ptr,1,"You are trying to use plumed, but it is not available.",NULL);
+ }
+ return;
+ }
+ assert(pimpl->functions.create);
+ assert(pimpl->functions.cmd);
+ assert(pimpl->functions.finalize);
+ /* execute */
+ if(pimpl->table && pimpl->table->version>1) (*(pimpl->table->cmd_nothrow))(pimpl->p,key,val,nothrow);
+ else (*(pimpl->functions.cmd))(pimpl->p,key,val);
+}
+__PLUMED_WRAPPER_C_END
- Destructor is virtual so as to allow correct inheritance from Plumed object.
- To avoid linking problems with g++, I specify "inline" also here (in principle
- it should be enough to specify it down in the definition of the function, but
- for some reason that I do not understand g++ does not inline it properly in that
- case and complains when Plumed.h is included but Plumed.o is not linked. Anyway, the
- way it is done here seems to work properly).
+
+
+__PLUMED_WRAPPER_C_BEGIN
+void plumed_finalize(plumed p) {
+ plumed_implementation* pimpl;
+ /* obtain pimpl */
+ pimpl=(plumed_implementation*) p.p;
+ assert(plumed_check_pimpl(pimpl));
+ /* decrease reference count */
+ pimpl->refcount--;
+#if __PLUMED_WRAPPER_DEBUG_REFCOUNT
+ fprintf(stderr,"refcount: decrease at %p\n",(void*)pimpl);
+#endif
+ if(pimpl->refcount>0) return;
+ /* to allow finalizing an invalid plumed object, we only call
+ finalize if the object is valid */
+ if(pimpl->p) {
+ assert(pimpl->functions.create);
+ assert(pimpl->functions.cmd);
+ assert(pimpl->functions.finalize);
+ /* finalize */
+ (*(pimpl->functions.finalize))(pimpl->p);
+ }
+#ifdef __PLUMED_HAS_DLOPEN
+ /* dlclose library */
+ if(pimpl->dlhandle && pimpl->dlclose) {
+ if(__PLUMED_GETENV("PLUMED_LOAD_DEBUG")) fprintf(stderr,"+++ Unloading library\n");
+ dlclose(pimpl->dlhandle);
+ }
+#endif
+#if __PLUMED_WRAPPER_DEBUG_REFCOUNT
+ fprintf(stderr,"refcount: delete at %p\n",(void*)pimpl);
+#endif
+ /* free pimpl space */
+ __PLUMED_FREE(pimpl);
+}
+__PLUMED_WRAPPER_C_END
+
+__PLUMED_WRAPPER_C_BEGIN
+int plumed_valid(plumed p) {
+ plumed_implementation* pimpl;
+ /* obtain pimpl */
+ pimpl=(plumed_implementation*) p.p;
+ assert(plumed_check_pimpl(pimpl));
+ if(pimpl->p) return 1;
+ else return 0;
+}
+__PLUMED_WRAPPER_C_END
+
+__PLUMED_WRAPPER_C_BEGIN
+int plumed_use_count(plumed p) {
+ plumed_implementation* pimpl;
+ /* obtain pimpl */
+ pimpl=(plumed_implementation*) p.p;
+ assert(plumed_check_pimpl(pimpl));
+ return pimpl->refcount;
+}
+__PLUMED_WRAPPER_C_END
+
+__PLUMED_WRAPPER_C_BEGIN
+int plumed_installed(void) {
+ plumed p;
+ int result;
+ p=plumed_create();
+ result=plumed_valid(p);
+ plumed_finalize(p);
+ return result;
+}
+__PLUMED_WRAPPER_C_END
+
+#if __PLUMED_WRAPPER_GLOBAL /*{*/
+
+__PLUMED_WRAPPER_EXTERN_C_BEGIN
+
+/* we declare a Plumed_g_main object here, in such a way that it is always available */
+
+static plumed plumed_gmain= {NULL};
+
+plumed plumed_global(void) {
+ return plumed_gmain;
+}
+
+void plumed_gcreate(void) {
+ /* should be created once */
+ assert(plumed_gmain.p==NULL);
+ plumed_gmain=plumed_create();
+}
+
+void plumed_gcmd(const char*key,const void*val) {
+ plumed_cmd(plumed_gmain,key,val);
+}
+
+void plumed_gfinalize(void) {
+ plumed_finalize(plumed_gmain);
+ plumed_gmain.p=NULL;
+}
+
+int plumed_ginitialized(void) {
+ if(plumed_gmain.p) return 1;
+ else return 0;
+}
+
+int plumed_gvalid() {
+ assert(plumed_gmain.p);
+ return plumed_valid(plumed_gmain);
+}
+
+__PLUMED_WRAPPER_EXTERN_C_END
+
+#endif /*}*/
+
+__PLUMED_WRAPPER_C_BEGIN
+void plumed_c2f(plumed p,char*c) {
+ unsigned i;
+ unsigned char* cc;
+ /*
+ Convert the address stored in p.p into a proper FORTRAN string
+ made of only ASCII characters. For this to work, the two following
+ assertions should be satisfied:
+ */
+ assert(CHAR_BIT<=12);
+ assert(sizeof(p.p)<=16);
+
+ assert(c);
+ cc=(unsigned char*)&p.p;
+ for(i=0; i=48 && c[2*i]<48+64);
+ assert(c[2*i+1]>=48 && c[2*i+1]<48+64);
+ /*
+ perform the reversed transform
+ */
+ cc[i]=(c[2*i]-48)*64 + (c[2*i+1]-48);
+ }
+ for(; i<16; i++) {
+ assert(c[2*i]==' ');
+ assert(c[2*i+1]==' ');
+ }
+ return p;
+}
+__PLUMED_WRAPPER_C_END
+
+__PLUMED_WRAPPER_C_BEGIN
+void* plumed_c2v(plumed p) {
+ assert(plumed_check_pimpl((plumed_implementation*)p.p));
+ return p.p;
+}
+__PLUMED_WRAPPER_C_END
+
+__PLUMED_WRAPPER_C_BEGIN
+plumed plumed_v2c(void* v) {
+ assert(plumed_check_pimpl((plumed_implementation*)v));
+ plumed p;
+ p.p=v;
+ return p;
+}
+__PLUMED_WRAPPER_C_END
+
+#if __PLUMED_WRAPPER_FORTRAN /*{*/
+
+/*
+ Fortran wrappers
+ These are just like the global C wrappers. They are
+ just defined here and not declared since they
+ should not be used from c/c++ anyway.
+
+ We use a macro that does the following:
+ - declare a static function named NAME_static
+ - declare a number of functions named NAME_ etc, with all possible
+ fortran mangling schemes (zero, one, or two underscores, lower and upper case)
+ - define the NAME_static function.
+
+ The static function is used basically as an inline function in a C-compatible manner.
*/
- inline virtual ~Plumed();
-};
-/* All methods are inlined so as to avoid the compilation of an extra c++ file */
+#define __PLUMED_IMPLEMENT_FORTRAN(lower,upper,arg1,arg2) \
+ static void lower ## _static arg1; \
+ extern void lower arg1 {lower ## _static arg2;} \
+ extern void lower ##_ arg1 {lower ## _static arg2;} \
+ extern void lower ##__ arg1 {lower ## _static arg2;} \
+ extern void upper arg1 {lower ## _static arg2;} \
+ extern void upper ##_ arg1 {lower ## _static arg2;} \
+ extern void upper ##__ arg1 {lower ## _static arg2;} \
+ static void lower ## _static arg1
-inline
-bool Plumed::installed(){
- return plumed_installed();
+/* FORTRAN wrappers would only make sense as extern "C" */
+
+__PLUMED_WRAPPER_EXTERN_C_BEGIN
+
+__PLUMED_IMPLEMENT_FORTRAN(plumed_f_create,PLUMED_F_CREATE,(char*c),(c)) {
+ plumed_c2f(plumed_create(),c);
}
-inline
-Plumed::Plumed():
- main(plumed_create()),
- cloned(false)
-{}
+__PLUMED_IMPLEMENT_FORTRAN(plumed_f_create_dlopen,PLUMED_F_CREATE_DLOPEN,(char*path,char*c),(path,c)) {
+ plumed_c2f(plumed_create_dlopen(path),c);
+}
-inline
-Plumed::Plumed(const char*c):
- main(plumed_f2c(c)),
- cloned(true)
-{}
+__PLUMED_IMPLEMENT_FORTRAN(plumed_f_create_reference,PLUMED_F_CREATE_REFERENCE,(char* r,char*c),(r,c)) {
+ plumed_c2f(plumed_create_reference_f(r),c);
+}
-inline
-Plumed::Plumed(plumed p):
- main(p),
- cloned(true)
-{}
+__PLUMED_IMPLEMENT_FORTRAN(plumed_f_create_invalid,PLUMED_F_CREATE_INVALID,(char* c),(c)) {
+ plumed_c2f(plumed_create_invalid(),c);
+}
-inline
-Plumed::operator plumed()const{
- return main;
+__PLUMED_IMPLEMENT_FORTRAN(plumed_f_cmd,PLUMED_F_CMD,(char*c,char*key,void*val),(c,key,val)) {
+ plumed_cmd(plumed_f2c(c),key,val);
}
-inline
-void Plumed::toFortran(char*c)const{
- plumed_c2f(main,c);
+__PLUMED_IMPLEMENT_FORTRAN(plumed_f_finalize,PLUMED_F_FINALIZE,(char*c),(c)) {
+ plumed_finalize(plumed_f2c(c));
}
-inline
-void Plumed::cmd(const char*key,const void*val){
- plumed_cmd(main,key,val);
+__PLUMED_IMPLEMENT_FORTRAN(plumed_f_installed,PLUMED_F_INSTALLED,(int*i),(i)) {
+ assert(i);
+ *i=plumed_installed();
}
-inline
-Plumed::~Plumed(){
- if(!cloned)plumed_finalize(main);
+/* New in PLUMED 2.5 */
+__PLUMED_IMPLEMENT_FORTRAN(plumed_f_valid,PLUMED_F_VALID,(char*c,int*i),(c,i)) {
+ assert(i);
+ *i=plumed_valid(plumed_f2c(c));
}
-inline
-bool Plumed::ginitialized(){
- return plumed_ginitialized();
+__PLUMED_IMPLEMENT_FORTRAN(plumed_f_use_count,PLUMED_F_USE_COUNT,(char*c,int*i),(c,i)) {
+ assert(i);
+ *i=plumed_use_count(plumed_f2c(c));
}
-inline
-void Plumed::gcreate(){
+#if __PLUMED_WRAPPER_GLOBAL /*{*/
+
+__PLUMED_IMPLEMENT_FORTRAN(plumed_f_global,PLUMED_F_GLOBAL,(char*c),(c)) {
+ plumed_c2f(plumed_gmain,c);
+}
+
+__PLUMED_IMPLEMENT_FORTRAN(plumed_f_ginitialized,PLUMED_F_GINITIALIZED,(int*i),(i)) {
+ assert(i);
+ *i=plumed_ginitialized();
+}
+
+__PLUMED_IMPLEMENT_FORTRAN(plumed_f_gcreate,PLUMED_F_GCREATE,(void),()) {
plumed_gcreate();
}
-inline
-void Plumed::gcmd(const char* key,const void* val){
+__PLUMED_IMPLEMENT_FORTRAN(plumed_f_gcmd,PLUMED_F_GCMD,(char*key,void*val),(key,val)) {
plumed_gcmd(key,val);
}
-inline
-void Plumed::gfinalize(){
+__PLUMED_IMPLEMENT_FORTRAN(plumed_f_gfinalize,PLUMED_F_GFINALIZE,(void),()) {
plumed_gfinalize();
}
-inline
-Plumed Plumed::global(){
- return plumed_global();
+/* New in PLUMED 2.5 */
+__PLUMED_IMPLEMENT_FORTRAN(plumed_f_gvalid,PLUMED_F_GVALID,(int*i),(i)) {
+ assert(i);
+ *i=plumed_gvalid();
}
-}
+#endif /*}*/
-#endif
+__PLUMED_WRAPPER_EXTERN_C_END
+#endif /*}*/
+
+#endif /*}*/
+
+#endif /*}*/
+
+/* END OF DEFINITIONS */
+
+/* reset variable to allow it to be redefined upon re-inclusion */
+
+#undef __PLUMED_WRAPPER_IMPLEMENTATION_
-#endif
diff --git cmake/3rdPartyTools.cmake cmake/3rdPartyTools.cmake
index 7983be6f47..318e7feb41 100644
--- cmake/3rdPartyTools.cmake
+++ cmake/3rdPartyTools.cmake
@@ -406,23 +406,14 @@ endif()
if(NEED_plumed)
- # plumed can be loaded one of three ways: static linking, dynamic linking, or runtime linking using dlopen
- if(DEFINED PLUMED_ROOT)
- find_path(PLUMED_INSTALL_DIR NAMES lib/plumed/src/lib/Plumed.cmake PATHS ${PLUMED_ROOT} DOC "Directory plumed is installed to. Should contain lib/plumed/src/lib/Plumed.cmake")
- else()
- find_path(PLUMED_INSTALL_DIR NAMES lib/plumed/src/lib/Plumed.cmake DOC "Directory plumed is installed to. Should contain lib/plumed/src/lib/Plumed.cmake")
- endif()
-
-
- if(PLUMED_INSTALL_DIR)
- message(STATUS "Found PLUMED, linking to it at build time.")
-
+ # PLUMED changed its C API in version 2.5.
+ # We can only build-time-link to versions >=2.5, though
+ # runtime linking should work with all versions
+ find_package(PLUMED 2.5)
+ if(PLUMED_FOUND)
set_3rdparty(plumed EXTERNAL)
-
else()
-
set_3rdparty(plumed DISABLED)
-
endif()
endif()
@@ -914,30 +905,7 @@ endif()
# PLUMED
#------------------------------------------------------------------------------
if(plumed_EXTERNAL)
- include(${PLUMED_INSTALL_DIR}/lib/plumed/src/lib/Plumed.cmake)
-
- if(STATIC)
- set(PLUMED_LINKER_FLAGS "")
-
- # grab interface linker flags from variable
- foreach(FLAG ${PLUMED_STATIC_LOAD})
- if("${FLAG}" MATCHES "^-")
- list(APPEND PLUMED_LINKER_FLAGS ${FLAG})
- endif()
- endforeach()
-
- #build the multiple object files it installs (???) into a single archive
- add_library(plumed STATIC ${PLUMED_STATIC_DEPENDENCIES})
- target_link_libraries(plumed ${PLUMED_LINKER_FLAGS})
- set_property(TARGET plumed PROPERTY LINKER_LANGUAGE CXX) # CMake cannot figure this out since there are only object files
- install_libraries(plumed)
- else()
- import_library(plumed ${PLUMED_SHARED_DEPENDENCIES})
- endif()
-
set(PLUMED_RUNTIME_LINK FALSE)
-
-
else()
if(HAVE_LIBDL AND NEED_plumed)
message(STATUS "Cannot find PLUMED. You will still be able to load it at runtime. If you want to link it at build time, set PLUMED_ROOT to where you installed it.")
diff --git cmake/FindAPBS.cmake cmake/FindAPBS.cmake
index 9b49c6be25..e63ac19bd9 100644
--- cmake/FindAPBS.cmake
+++ cmake/FindAPBS.cmake
@@ -1,6 +1,6 @@
# - Find APBS
# Find the native APBS includes and library
-# This module defines
+# This module defines the following variables:
#
# APBS_LIBRARIES, the libraries needed to use APBS.
# APBS_FOUND, If false, do not try to use APBS.
diff --git cmake/FindPLUMED.cmake cmake/FindPLUMED.cmake
new file mode 100644
index 0000000000..6b1d789826
--- /dev/null
+++ cmake/FindPLUMED.cmake
@@ -0,0 +1,90 @@
+# - Find PLUMED
+#
+# This module finds the PLUMED molecular dynamics library on your system.
+#
+# Variables:
+# PLUMED_LIBRARIES - Libraries to link to use PLUMED as a shared library
+# PLUMED_INCLUDES - Path where PLUMED's headers can be found
+# PLUMED_FOUND - Whether PLUMED was found
+# PLUMED_VERSION - Version of plumed found, if it was found
+#
+# If PLUMED was found, this module also creates the following imported target:
+# plumed::plumed - Target for plumed's libraries
+
+# if the plumed executable is in the path, we can try to use it to find where plumed is installed
+get_filename_component(PLUMED_EXECUTABLE_PATH plumed PROGRAM)
+
+set(PLUMED_HINTS "" CACHE PATH "Directories where PLUMED might be installed" INTERNAL)
+
+if(EXISTS "${PLUMED_EXECUTABLE_PATH}" AND "${PLUMED_HINTS}" STREQUAL "")
+ execute_process(
+ COMMAND ${PLUMED_EXECUTABLE_PATH} info --configuration
+ RESULT_VARIABLE PLUMED_EXIT_CODE
+ OUTPUT_VARIABLE PLUMED_CONFIG_OUTPUT)
+
+ if(PLUMED_EXIT_CODE STREQUAL 0)
+ if("${PLUMED_CONFIG_OUTPUT}" MATCHES "prefix=(.+)")
+ set(PLUMED_HINTS "${CMAKE_MATCH_1}" CACHE PATH "Directories where PLUMED might be installed" INTERNAL FORCE)
+ endif()
+ endif()
+endif()
+
+# search for libraries
+find_library(PLUMED_KERNEL_LIBRARY
+ NAMES plumedKernel
+ DOC "Path to PLUMED kernel library"
+ HINTS ${PLUMED_HINTS})
+
+find_library(PLUMED_LIBRARY
+ NAMES plumed
+ DOC "Path to PLUMED library"
+ HINTS ${PLUMED_HINTS})
+
+set(PLUMED_LIBRARIES ${PLUMED_LIBRARY} ${PLUMED_KERNEL_LIBRARY})
+
+# search for headers
+find_path(PLUMED_INCLUDES
+ NAMES wrapper/Plumed.h
+ PATH_SUFFIXES plumed
+ DOC "Path where PLUMED's includes are. Should contain wrapper/Plumed.h"
+ HINTS ${PLUMED_HINTS})
+
+# find version number
+if(EXISTS ${PLUMED_INCLUDES}/config/version.h)
+ file(READ ${PLUMED_INCLUDES}/config/version.h PLUMED_VERSION_HEADER_CONTENT)
+ if("${PLUMED_VERSION_HEADER_CONTENT}" MATCHES "#define PLUMED_VERSION_LONG \"([0-9.]+)\"")
+ set(PLUMED_VERSION ${CMAKE_MATCH_1})
+ endif()
+endif()
+
+if(EXISTS "${PLUMED_LIBRARY}" AND EXISTS "${PLUMED_KERNEL_LIBRARY}")
+
+ # check functionality
+ # plumed_symbol_table_reexport is the function called by the wrapper to get funciton pointers from the library
+ try_link_library(PLUMED_WORKS
+ NAME plumed
+ LANGUAGE C
+ FUNCTION plumed_symbol_table_reexport
+ LIBRARIES ${PLUMED_LIBRARIES})
+endif()
+
+
+find_package_handle_standard_args(PLUMED
+ REQUIRED_VARS PLUMED_LIBRARY PLUMED_KERNEL_LIBRARY PLUMED_INCLUDES PLUMED_WORKS
+ VERSION_VAR PLUMED_VERSION)
+
+# create imported target
+if(PLUMED_FOUND)
+ add_library(plumed::plumed_lib UNKNOWN IMPORTED)
+ set_property(TARGET plumed::plumed_lib PROPERTY IMPORTED_LOCATION ${PLUMED_LIBRARY})
+ set_property(TARGET plumed::plumed_lib PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${PLUMED_INCLUDES})
+
+ add_library(plumed::kernel_lib UNKNOWN IMPORTED)
+ set_property(TARGET plumed::kernel_lib PROPERTY IMPORTED_LOCATION ${PLUMED_KERNEL_LIBRARY})
+ set_property(TARGET plumed::kernel_lib PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${PLUMED_INCLUDES})
+
+ # add combined target
+ add_library(plumed::plumed INTERFACE IMPORTED)
+ set_property(TARGET plumed::plumed PROPERTY INTERFACE_LINK_LIBRARIES plumed::plumed_lib plumed::kernel_lib)
+
+endif()
\ No newline at end of file