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 for breakfast. And yes, the long term solution for me here will be to switch to PID altogether ;)
In the meanwhile, 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 alternatively open CMakeCache.txt in your text editor.
Boost library path
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
Possibly the Boost_DIR variable will revert to Boost_DIR-NOTFOUND after you run the makefile again. This is not a problem.
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 rather set 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. The long term solution here is to switch to broader, dependency-handling frameworks such as PID.
Credits: thanks to Kevin Chappellet for suggesting local changes to the CMakeCache.txt and to Robin Passama for walking me through the RPATH :)