# CPack Debian Packaging and RUNPATH/RPATH for dependencies picked up from IMPORTED\_RUNTIME\_ARTIFACTS

**URL:** <https://discourse.cmake.org/t/cpack-debian-packaging-and-runpath-rpath-for-dependencies-picked-up-from-imported-runtime-artifacts/8721>\
**Category:** Code\
**Tags:** os:linux, cpack:deb\
**Created:** [August 11, 2023, 9:22am UTC](https://discourse.cmake.org/t/cpack-debian-packaging-and-runpath-rpath-for-dependencies-picked-up-from-imported-runtime-artifacts/8721 "2023-08-11T09:22:55Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Joel](https://discourse.cmake.org/user_avatar/discourse.cmake.org/joel/32/1908_2.png) [@Joel](https://discourse.cmake.org/u/Joel)\
**Post date:** [August 11, 2023, 9:22am UTC](https://discourse.cmake.org/t/cpack-debian-packaging-and-runpath-rpath-for-dependencies-picked-up-from-imported-runtime-artifacts/8721/1 "2023-08-11T09:22:55Z")

</div>

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`:

```auto
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.

```auto
# 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](https://stackoverflow.com/questions/72547005/binary-with-rpath-not-finding-transitive-dependencies-if-one-of-them-has-runpath)) 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).

1. 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?
2. Is it possible to get cmake to overwrite the RUNPATH’s of all dependencies installed during `install(RUNTIME_DEPENDENCY_SET ...)` to whatever `CMAKE_INSTALL_RPATH` is set to? I think such a solution would be the the nicest.  
I was looking around and it may be possible using `CPACK_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!

---

<div class="post-metadata">

**Author:** ![Joel](https://discourse.cmake.org/user_avatar/discourse.cmake.org/joel/32/1908_2.png) [@Joel](https://discourse.cmake.org/u/Joel)\
**Post date:** [March 13, 2025, 3:32pm UTC](https://discourse.cmake.org/t/cpack-debian-packaging-and-runpath-rpath-for-dependencies-picked-up-from-imported-runtime-artifacts/8721/2 "2025-03-13T15:32:33Z")

</div>

I’ve solved this by using a pre build script to call patchelf

```auto
set(CPACK_PRE_BUILD_SCRIPTS "${CMAKE_CURRENT_LIST_DIR}/patchelf-packaging.cmake")

```

where `patchelf-packaging.cmake` looks like

```auto
set(INSTALL_FOLDER "${CPACK_TEMPORARY_INSTALL_DIRECTORY}")
file(GLOB_RECURSE MY_LIBS
    "${INSTALL_FOLDER}/*.so*" 
)

foreach(lib ${MY_LIBS})
    set(COMMAND_ARGS
        "/usr/bin/patchelf"
        "--set-rpath"
        "$ORIGIN/../lib"
        ${lib}
    )
    
    execute_process(COMMAND ${COMMAND_ARGS} RESULT_VARIABLE EXIT_CODE)
    if(NOT EXIT_CODE EQUAL 0)
        message(STATUS "Running ${COMMAND_ARGS} failed with exit code ${EXIT_CODE}.")
    endif()
endforeach()

```
