One of my current projects relies on Boost.Python, which requires a more recent version of Boost (1.64) than the one (1.54) provided by my Linux distribution (Ubuntu 14.04). My first guess was to remove Boost from my package manager and install its newer version from source... with dramatic consequences! At first, I only experienced a few glitches in ROS and some libraries built with the old version of Boost, but down the road I ran into serious runtime problems that forced me to revert to the system's Boost 1.54.
My second guess was to use a local version of Boost 1.64, compiled but not
installed system-wide and only used by the project that needs it. I knew this
is possible because the PID framework
does this. Without switching to a software source distribution manager, let's
see how to change only the
CMakeCache.txt configuration to switch from a
system-wide to a local Boost install.
Local changes to CMakeCache.txt¶
I'm assuming you already have your
CMakeLists.txt file written and
functional. For instance, you can follow these instructions to use
Boost.Python with CMake. We won't make any
change to the
CMakeLists.txt, so that your local Boost install will only
affect you and stay transparent for other project users.
To start with, go to your build directory and call
ccmake ., or
CMakeCache.txt in your text editor.
If you use the JRL CMake modules to find Boost
automatically, you will already have a number of
Boost_* CMake variables.
The first thing is to update them to your local path:
Boost_INCLUDE_DIR:PATH=/my/local/path/boost/1.64.0/include Boost_LIBRARY_DIR:PATH=/my/local/path/boost/1.64.0/lib Boost_PYTHON_LIBRARY_DEBUG:FILEPATH=/my/local/path/boost/1.64.0/lib/libboost_python.so Boost_PYTHON_LIBRARY_RELEASE:FILEPATH=/my/local/path/boost/1.64.0/lib/libboost_python.so
If compilation fails with Boost headers not found, add them manually by:
Boost_DIR variable will revert to
you run CMake again. This is not a problem.
Update linker flags¶
While Boost.Python will be linked with its full path, some libraries like
Boost.NumPy may still be linked by a mere
-lboost_numpy, in which case the
linker will fail to find the local shared object (.so) file. Let's add a
linker flag to help it here:
At this stage, your executable or library should compile and link. You can check that the files produced in your build folder (let's assume a .so here) links properly to your local Boost libraries:
$ ldd ./build/mylib.so linux-vdso.so.1 => (0x0000...) libboost_numpy.so.1.64.0 => /my/local/path/boost/1.64.0/lib/libboost_numpy.so.1.64.0 (0x0000...) libboost_python.so.1.64.0 => /my/local/path/boost/1.64.0/lib/libboost_python.so.1.64.0 (0x0000...)
However, you may notice that it is not the case with your installed files:
$ ldd /install/path/mylib.so linux-vdso.so.1 => (0x00007ffc8f5c7000) libboost_numpy.so.1.64.0 => not found libboost_python.so.1.64.0 => not found ...
This is caused by the different behaviors of CMake between build and install.
A Tale of two RPATHs¶
RPATH is a list of directories that is directly written into your
executable or shared object and tells the linker where to look for libraries.
It has precedence over the
LD_LIBRARY_PATH system-wide variable, as
explained in this page on CMake RPATH handling.
A dirty solution to the "not found" problem would be to add the local Boost
1.64 libraries to
LD_LIBRARY_PATH. But then, they would also be visible in
other projects trying to link to Boost, which can be problematic. We will
RPATH to avoid this and keep things local.
The behavior of CMake with respect to RPATH is controlled by two parameters:
// If set, runtime paths are not added when installing shared libraries, // but are added when building. CMAKE_SKIP_INSTALL_RPATH:BOOL=OFF // If set, runtime paths are not added when using shared libraries. CMAKE_SKIP_RPATH:BOOL=OFF
In our case, we need both of these values to be off. Plus, we want the linker to behave for the install the way it does for the build, i.e. using full paths to our local Boost libraries. This is specified by the following parameter:
// Use same RPATH at install and build CMAKE_INSTALL_RPATH_USE_LINK_PATH:BOOL=ON
Once this is set, run
make install again. You should see something like:
$ ldd /install/path/mylib.so linux-vdso.so.1 => (0x0000...) libboost_numpy.so.1.64.0 => /my/local/path/boost/1.64.0/lib/libboost_numpy.so.1.64.0 (0x0000...) libboost_python.so.1.64.0 => /my/local/path/boost/1.64.0/lib/libboost_python.so.1.64.0 (0x0000...)
On a concluding note¶
These instructions provide an ad hoc way of linking with local libraries
without affecting the
CMakeLists.txt of your project (used by other users
who don't want to see your local paths on their side). While CMake is the de
facto standard today, we are feeling its limitations in such scenarios. A
better solution here would be to switch to full-fledged CMake-based package
Thanks to Kevin Chappellet for suggesting local changes to the
CMakeCache.txt and to Robin Passama for walking me through the RPATH :)
There are no comments yet. Feel free to leave a reply using the form below.