From feb3fb9cf2ed4ef8b631d07e9b9b0d5c965938e4 Mon Sep 17 00:00:00 2001
From: Giovanni Bussi <giovanni.bussi@gmail.com>
Date: Mon, 12 Nov 2018 10:17:11 +0100
Subject: [PATCH] Made python wrapper self-contained

It does not link to library anymore, but just includes Plumed.h file.
It thus could be compiled with different compilers and flags wrt plumed.

Notice that as of PLUMED 2.5 Plumed.h also contains the full implementation
of the dynamic loader, so it is sufficient to define the proper cpp
flags in order to recompile the loader and avoiding the need to link
plumedWrapper.a.

This basically allows the python wrapper to be selfcontained and installable
before having installed plumed.
---
 python/Makefile                | 14 ++------------
 python/buildPythonInterface.py | 28 ++++++++++++++++------------
 python/cplumed.pxd             |  7 +++++--
 python/plumed.pyx              |  2 ++
 src/lib/Makefile               | 10 ++--------
 5 files changed, 27 insertions(+), 34 deletions(-)

diff --git a/python/Makefile b/python/Makefile
index e552d225d..072c148ad 100644
--- a/python/Makefile
+++ b/python/Makefile
@@ -16,22 +16,12 @@ else
 
 ifdef python_bin
 
-ifeq ($(SOEXT),dylib)
-PYTHON_EXTRA_LDFLAGS=-undefined dynamic_lookup
-else
-PYTHON_EXTRA_LDFLAGS=
-endif
-
 all:
 	@echo Building python interface for PLUMED 
-	LD_LIBRARY_PATH=$$PWD/../src/lib:$$LD_LIBRARY_PATH \
-	  CC="$(CC)" \
-          LDSHARED="$(LDSHARED) $(PYTHON_EXTRA_LDFLAGS)" \
-          CXX="$(CXX)" \
+	unset CXX && unset CC && unset CFLAGS && unset CXXFLAGS && unset LDSHARED && \
           program_name=plumed \
-          plumedexe=../src/lib/plumed \
           include_dir=../src/wrapper \
-          lib_dir=../src/lib \
+          default_kernel="$$PWD/../src/lib/libplumedKernel.$(SOEXT)" \
           $(python_bin) buildPythonInterface.py build_ext -i
 
 else
diff --git a/python/buildPythonInterface.py b/python/buildPythonInterface.py
index 191644038..ffb33307a 100644
--- a/python/buildPythonInterface.py
+++ b/python/buildPythonInterface.py
@@ -29,31 +29,35 @@ import numpy
 import subprocess
 import os
 
-# Function for checking if PLUMED is in path
-def is_exe(fpath):
-    return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+plumedname = os.getenv("program_name")
+if plumedname is None:
+    plumedname = "plumed"
 
-plumedexe=os.environ["plumedexe"]
+plumedversion = subprocess.check_output(['grep','-v','#','../VERSION']).decode("utf-8")
 
-plumedversion = subprocess.check_output([plumedexe, 'info', '--version']).decode("utf-8")
-print( "Version number for this plumed is " + plumedversion )
+print( "Module name " + plumedname )
+print( "Version number " + plumedversion )
 
-print( "Building interface using CC=" + os.environ["CC"] + " , CXX=" + os.environ["CXX"] + " and LDSHARED=" + os.environ["LDSHARED"] )
+extra_compile_args=['-D__PLUMED_HAS_DLOPEN','-D__PLUMED_WRAPPER_LINK_RUNTIME=1','-D__PLUMED_WRAPPER_CXX=1','-D__PLUMED_WRAPPER_IMPLEMENTATION=1','-D__PLUMED_WRAPPER_EXTERN=0'] 
+
+defaultkernel=os.getenv("default_kernel")
+if defaultkernel is not None:
+    extra_compile_args.append("-D__PLUMED_DEFAULT_KERNEL=" + os.path.abspath(defaultkernel))
+    print( "Hardcoded PLUMED_KERNEL " + os.path.abspath(defaultkernel))
 
 setup(
-  name='plumed',
+  name=plumedname,
   version=plumedversion,
   description='Python interface to PLUMED',
   author='Gareth A. Tribello',
   author_email='plumed-users@googlegroups.com',
   url='http://www.plumed.org',
   ext_modules = cythonize([
-                  Extension( name="plumed",
+                  Extension( name=plumedname,
                              sources=["plumed.pyx"],
-                             library_dirs=[os.environ["lib_dir"]],
-                             libraries=[os.environ["program_name"]],
                              language="c++",
-                             include_dirs=[os.environ["include_dir"], numpy.get_include()]
+                             include_dirs=[os.environ["include_dir"], numpy.get_include()],
+                             extra_compile_args=extra_compile_args
                            )
                           ])
 )
diff --git a/python/cplumed.pxd b/python/cplumed.pxd
index 5450a008d..513ec72be 100644
--- a/python/cplumed.pxd
+++ b/python/cplumed.pxd
@@ -23,10 +23,13 @@
 # This create cython wrappers to the main bits of the PLUMED libraray
 #
 
+from libcpp cimport bool
+
+# Some of these functions are noexcept.
+# We anyway use except + in case this changes later.
 cdef extern from "Plumed.h" namespace "PLMD":
      cdef cppclass Plumed:
          Plumed() except +
          void cmd(const char*key, const void*val) except +
          void cmd(const char*key) except +
-
-
+         bool valid() except +
diff --git a/python/plumed.pyx b/python/plumed.pyx
index 032764a2f..96b99f335 100644
--- a/python/plumed.pyx
+++ b/python/plumed.pyx
@@ -31,6 +31,8 @@ cimport numpy as np
 cdef class Plumed:
      cdef cplumed.Plumed c_plumed
      def __cinit__(self):
+         if not self.c_plumed.valid():
+              raise RuntimeError("PLUMED not available, check your PLUMED_KERNEL environment variable")
          cdef int pres = 8
          self.c_plumed.cmd( "setRealPrecision", <void*>&pres )
      def cmd_ndarray_real(self, ckey, val):
diff --git a/src/lib/Makefile b/src/lib/Makefile
index 3927668cb..9cb765941 100644
--- a/src/lib/Makefile
+++ b/src/lib/Makefile
@@ -17,8 +17,6 @@ ifneq ($(MAKECMDGOALS),clean)
 endif
 
 ifeq ($(SOEXT),dylib)
-# Extra flags required to properly compile the python interface
-  PYTHON_EXTRA_LDFLAGS:=-undefined dynamic_lookup
   SONAME_OPTION:=-Wl,-install_name
 else
   PYTHON_EXTRA_LDFLAGS:=
@@ -314,14 +312,10 @@ endif
 ifdef python_bin
 	cp -pr ../../python install 
 	cd install/python && rm -fr *.so plumed.cpp build && \
-	LD_LIBRARY_PATH=$$PWD/../..:$$LD_LIBRARY_PATH \
-	  CC="$(CC)" \
-          LDSHARED="$(LDSHARED) $(PYTHON_EXTRA_LDFLAGS)" \
-          CXX="$(CXX)" \
-          plumedexe="../../plumed" \
+          unset CXX && unset CC && unset CFLAGS && unset CXXFLAGS && unset LDSHARED && \
           program_name="$(program_name)" \
           include_dir=../../../wrapper \
-          lib_dir="$(DESTDIR)$(libdir)" \
+          default_kernel="$(libdir)/lib$(program_name)Kernel.$(SOEXT)" \
           $(python_bin) buildPythonInterface.py build_ext -i
 	cp -pr install/python "$(DESTDIR)$(libdir)/$(program_name)/" 
 endif
-- 
GitLab