Skip to content

Commit

Permalink
Refs #4204. Change the Mac to load symbols locally for Python.
Browse files Browse the repository at this point in the history
  • Loading branch information
martyngigg committed Dec 5, 2011
1 parent d457885 commit 4f70264
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 57 deletions.
9 changes: 7 additions & 2 deletions Code/Mantid/Framework/PythonAPI/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,14 @@ endforeach ( PYFILE )
###########################################################################

add_library ( PythonAPI ${SRC_FILES} ${INC_FILES} ${BOOST_SRC} ${PYTHON_INSTALL_FILES} )
if ( ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" )
if ( UNIX )
set ( DLOPEN_SRC src/dlopen.cpp )
add_library ( dlopen ${DLOPEN_SRC} )
if ( APPLE )
# and in .so on the Mac
set_target_properties ( dlopen PROPERTIES SUFFIX .so )
target_link_libraries ( dlopen ${PYTHON_LIBRARIES} )
endif()
add_dependencies( PythonAPI dlopen )
endif()

Expand Down Expand Up @@ -247,7 +252,7 @@ endif ()
###########################################################################

install ( TARGETS PythonAPI DESTINATION ${BIN_DIR} )
if ( ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" )
if ( UNIX )
install ( TARGETS dlopen DESTINATION ${BIN_DIR} )
endif ()
install ( FILES ${PY_FILES} DESTINATION ${BIN_DIR} )
Expand Down
100 changes: 54 additions & 46 deletions Code/Mantid/Framework/PythonAPI/MantidFramework.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,55 +34,63 @@
from MantidPythonAPI import *
from MantidPythonAPI import _binary_op, _equals_op
else:
if platform.system() == "Linux":
#
# The libMantidPythonAPI module is essentially statically linked
# to boost python. However, we need to ensure the Mantid libraries
# are loaded with the the RTLD_GLOBAL flag so that the singleton
# symbols are shared across the boundaries.
#
# We also need to coexist with the new-style interface meaning that
# the boost python registry must be kept private in each api
# so that multiple converters are not defined. This means that
# we cannot just pass the RTLD_GLOBAL flag here as this will
# cause the registry to be shared with the new api if it is
# loaded on top of this one. The only solution is to cherry
# pick the modules that are loaded with the RTLD symbol.
#
# Another nice issue is that the dl module is broken on 64-bit
# systems for Python 2.4 and ctypes doesn't exist there yet!
# All in all this meant a small custom module calling dlopen
# ourselves was the easiest way
import libdlopen
dlloader = libdlopen.loadlibrary
import subprocess

_bin = os.path.abspath(os.path.dirname(__file__))
def get_libpath(mainlib, dependency):
# The libMantidPythonAPI module is essentially statically linked
# to boost python. However, we need to ensure the Mantid libraries
# are loaded with the the RTLD_GLOBAL flag so that the singleton
# symbols are shared across the boundaries.
#
# We also need to coexist with the new-style interface meaning that
# the boost python registry must be kept private in each api
# so that multiple converters are not defined. This means that
# we cannot just pass the RTLD_GLOBAL flag here as this will
# cause the registry to be shared with the new api if it is
# loaded on top of this one. The only solution is to cherry
# pick the modules that are loaded with the RTLD symbol.
#
# Another nice issue is that the dl module is broken on 64-bit
# systems for Python 2.4 and ctypes doesn't exist there yet!
# All in all this meant a small custom module calling dlopen
# ourselves was the easiest way
import libdlopen
dlloader = libdlopen.loadlibrary
import subprocess

_bin = os.path.abspath(os.path.dirname(__file__))
def get_libpath(mainlib, dependency):
if platform.system() == 'Linux':
cmd = 'ldd %s | grep %s' % (mainlib, dependency)
subp = subprocess.Popen(cmd,stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,shell=True)
out = subp.communicate()[0]
# ldd produces a string that always has 4 columns. The full path
# is in the 3rd column
return out.split()[2]
# stdc++ has to be loaded first or exceptions don't get translated
# properly across bounadries
# NeXus has to be loaded as well as there seems to be an issue with
# the thread-local storage not being initialized properly unles
# it is loaded before other libraries.
ldpath = os.environ.get("LD_LIBRARY_PATH", "")
ldpath += ":" + _bin
os.environ["LD_LIBRARY_PATH"] = ldpath
pythonlib = os.path.join(_bin,'libMantidPythonAPI.so')
dlloader(get_libpath(pythonlib, 'stdc++'))
dlloader(get_libpath(pythonlib, 'libNeXus'))
dlloader(get_libpath(pythonlib, 'libMantidKernel'))
dlloader(get_libpath(pythonlib, 'libMantidGeometry'))
dlloader(get_libpath(pythonlib, 'libMantidAPI'))

part = 2
else:
cmd = 'otool -L %s | grep %s' % (mainlib, dependency)
part = 0
subp = subprocess.Popen(cmd,stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,shell=True)
out = subp.communicate()[0]
# ldd produces a string that always has 4 columns. The full path
# is in the 3rd column
return out.split()[part]
# stdc++ has to be loaded first or exceptions don't get translated
# properly across bounadries
# NeXus has to be loaded as well as there seems to be an issue with
# the thread-local storage not being initialized properly unles
# it is loaded before other libraries.
ldpath = os.environ.get("LD_LIBRARY_PATH", "")
ldpath += ":" + _bin
os.environ["LD_LIBRARY_PATH"] = ldpath
pythonlib = os.path.join(_bin,'libMantidPythonAPI.so')
dlloader(get_libpath(pythonlib, 'stdc++'))
dlloader(get_libpath(pythonlib, 'libNeXus'))
dlloader(get_libpath(pythonlib, 'libMantidKernel'))
dlloader(get_libpath(pythonlib, 'libMantidGeometry'))
dlloader(get_libpath(pythonlib, 'libMantidAPI'))

oldflags = sys.getdlopenflags()
if platform.system() == "Darwin":
import dl
sys.setdlopenflags(dl.RTLD_LOCAL|dl.RTLD_NOW)
from libMantidPythonAPI import *
from libMantidPythonAPI import _binary_op, _equals_op
sys.setdlopenflags(oldflags)
# --- End of library load ---


Expand Down
10 changes: 1 addition & 9 deletions Code/Mantid/Framework/PythonAPI/src/dlopen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ PyObject * loadLibrary(PyObject *, PyObject * args)
void* handle = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
if (!handle)
{
PyErr_SetString(PyExc_RuntimeError, "Failed to import library");
PyErr_SetString(PyExc_RuntimeError, dlerror());
return NULL;
}
Py_INCREF(Py_None);
Expand All @@ -38,11 +38,3 @@ extern "C" void initlibdlopen()
if (m == NULL) return;
}

//void init_module_libdlopen();


//BOOST_PYTHON_MODULE(dlopen)
//{
//
// boost::python::def("loadlibrary", &loadLibrary);
//}

0 comments on commit 4f70264

Please sign in to comment.