Reputation: 410
I am building a library that I bundle with a few tests and example programs. The project is able to honor the cmake property BUILD_SHARED_LIBS
, building a .so
if it's on and building a .a
file if it is off. The library depends on a few other dynamic libraries, which are supposed to be found using an environment variable, LIBLOC
(their convention, not mine).
When I build the dynamic version of the library, I am able to set up the install rpath so that the libraries are found correctly. E.g.:
add_library(lib ${SRC})
set_target_properties(lib INSTALL_RPATH $LIBLOC)
install(TARGETS lib LIBRARY DESTINATION lib)
And then in each test/example program's CMakeLists.txt:
add_executable(test ${SRC})
target_link_libraries(test lib)
set_target_properties(test INSTALL_RPATH $ORIGIN/../lib)
install(TARGETS test RUNTIME bin)
When BUILD_SHARED_LIBS
is on, the test program is happy:
$ lddtree bin/test
test => bin/test (interpreter => /lib64/ld-linux-x86-64.so.2)
liblib.so => /path/to/install/liblib.so
libdep.so => /path/to/dependency/libdep.so
We can find everything because the rpath in test is $ORIGIN/../lib
, which finds liblib.so
and then the rpath in liblib.so
is $LIBLOC
, which is set in my environment to /path/to/dependency
.
I would have expected that, when installing the static library, cmake would read the INSTALL_RPATH
property from my library and put it in the test program so that the rpath in test would be $ORIGIN/../lib;$LIBLOC
. Instead, $LIBLOC
does not end up in any rpath.
My current solution is dissatisfying: I condition my INSTALL_RPATH
on BUILD_SHARED_LIBS
in each example or test program, e.g.
if (BUILD_SHARED_LIBS)
set_target_properties(test INSTALL_RPATH "$ORIGIN/../lib")
else ()
set_target_properties(test INSTALL_RPATH "$LIBLOC")
endif ()
Now I have several targets, all of which have to be aware of their dependencies' dependencies. Plus a bunch of smelly if statements. Yuck!
Is there a nicer way in cmake to pass the install rpath "up" to the first ELF file produced when my libraries are compiled statically?
Upvotes: 9
Views: 1267
Reputation: 19956
The CMAKE_INSTALL_RPATH
variable may be set externally and will apply to all targets for which RPATH
is well defined (i.e. executables and shared libraries).
For libraries you author or vendor, you should install them into a consistent structure so that CMAKE_INSTALL_RPATH
may be set to $LIBLOC
or $ORIGIN/../lib
uniformly across all targets. For true dependencies, it is reasonable to expect the user to have them installed system-wide, have set LD_LIBRARY_PATH
, or use the find_dependency
macro in your CMake package config to locate the correct libraries.
Here's a snippet that might help you, if placed before any targets are created:
if (NOT DEFINED CMAKE_INSTALL_RPATH)
# or perhaps it's meant to be $env{LIBLOC}?
set(CMAKE_INSTALL_RPATH "$<IF:$<BOOL:${BUILD_SHARED_LIBS}>,$ORIGIN/../lib,$LIBLOC>")
endif ()
Upvotes: 1