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
alternatively open CMakeCache.txt
in your text editor.
Boost paths¶
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:
CMAKE_CXX_FLAGS:STRING=-I/my/local/path/boost/1.64.0/include
Possibly the Boost_DIR
variable will revert to Boost_DIR-NOTFOUND
after
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 -L
linker flag to help it here:
CMAKE_SHARED_LINKER_FLAGS:STRING=-L/my/local/path/boost/1.64.0/lib
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
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. A
better solution here would be to switch to full-fledged CMake-based package
manager.
Credits¶
Thanks to Kevin Chappellet for suggesting local changes to the
CMakeCache.txt
and to Robin Passama for walking me through the RPATH :)
Discussion ¶
Feel free to post a comment by e-mail using the form below. Your e-mail address will not be disclosed.