Hi,
I’m trying to get cmake to package my Linux executable (+ dependent libraries) as a deb package.
The executable should live in /opt/foo/bin
and the libraries it depends on should live in /opt/foo/lib
.
However, I’m having problems with the executable finding dependent/transitive libraries in /opt/foo/lib when the libraries are picked up from IMPORTED_RUNTIME_ARTIFACTS
.
I first tried setting the RUNPATH of the executable to point to /opt/foo/lib
:
cmake_minimum_required( VERSION 3.24 )
add_executable(myprogram myprogram.cpp)
target_link_libraries(myprogram PUBLIC libraryA)
set(CMAKE_INSTALL_PREFIX "/opt/foo" CACHE PATH "Default install path" FORCE)
set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
include(GNUInstallDirs)
# set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}") # I tried setting this but it doesn't seem to do anything?
install(TARGETS myprogram
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
CONFIGURATIONS Release
)
# Automatically pick up non system dependencies
install(IMPORTED_RUNTIME_ARTIFACTS myprogram
RUNTIME_DEPENDENCY_SET MyProgramDeps
)
install(RUNTIME_DEPENDENCY_SET MyProgramDeps
POST_EXCLUDE_REGEXES "^/lib" "^/usr/lib"
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
# Set runpath of my program to the libdir
set_target_properties(myprogram
PROPERTIES
INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}
)
set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)
include(CPack)
but I notice that all transitive dependencies do not get picked up when I try to launch myprogram
since this only sets the RUNPATH of the executable. (The libraries that libraryA
depends on, even though they are successfully placed in /opt/foo/lib
from install(RUNTIME_DEPENDENCY_SET ...)
)
In my case, the dependent libraries which are pulled into /opt/foo/lib
are libgtsam.so
and libgtsam-metis.so
.
I then tried to set the RPATH instead of RUNPATH of my program, as I read that when the RPATH of the executable is set, the dynamic linker will use that to find all transitive dependencies as well.
# append to previous code
target_link_options(myprogram PRIVATE -Wl,--disable-new-dtags)
But I then encountered this issue (c++ - Binary with RPATH not finding transitive dependencies if one of them has RUNPATH - Stack Overflow) where transitive libraries of a dependent libraries with a RUNPATH set cannot be found. When I try to launch my program, I see that libgtsam-metis.so
cannot be found, even though it exists in /opt/foo/lib
and the RPATH of myprogram
points there.
In this case, my libraryA
directly links to the library libgtsam.so
, but libgtsam.so
has its RUNPATH set to when I installed it on my build machine (/usr/local/GTSAM
). libgtsam.so
itself has a dependency on another library libgtsam-metis.so
(this is the transitive dependency that cannot be found, even though both were successfully picked up and placed in /opt/foo/lib
). When I inspect the libgtsam.so
library on the install machine: readelf -d /opt/foo/lib/libgtsam.so
I see that the runpath still points to /usr/local/GTSAM
(which does not exist on the install machine).
- In the end, I gave up on trying to set RPATH/RUNPATH and packaged a foo.conf file to
/etc/ld.so.conf.d
to point to/opt/foo/lib
but I think that’s a bad solution as it also exposes my bundled libraries to other programs on the install machine - is there a cleaner solution? - Is it possible to get cmake to overwrite the RUNPATH’s of all dependencies installed during
install(RUNTIME_DEPENDENCY_SET ...)
to whateverCMAKE_INSTALL_RPATH
is set to? I think such a solution would be the the nicest.
I was looking around and it may be possible usingCPACK_PRE_BUILD_SCRIPTS
+patchelf
, so that I don’t have to force an RPATH, and just ensure that every library/executable in my package has their RUNPATH point to/opt/foo/lib
Thank you!