Search code examples
linuxbuilddependenciesdynamic-linkingrpath

Setting rpath for dependencies of dependencies?


I've got a Linux executable build going where I've set the rpath through the linker flags "-Wl,-rpath,./ -Wl,--disable-new-dtags", and I've verified through readelf -d that the RPATH is being set to ./

This works for direct dependencies, as my executable is able to find them when placed in the same directory. This isn't working for dependencies-of-dependencies though:

46763:     find library=libpulsecommon-13.99.so [0]; searching
46763:     search path=/usr/lib/x86_64-linux-gnu/pulseaudio/tls/x86_64/x86_64:/usr/lib/x86_64-linux-gnu/pulseaudio/tls/x86_64:/usr/lib/x86_64-linux-gnu/pulseaudio/tls/x86_64:/usr/lib/x86_64-linux-gnu/pulseaudio/tls:/usr/lib/x86_64-linux-gnu/pulseaudio/x86_64/x86_64:/usr/lib/x86_64-linux-gnu/pulseaudio/x86_64:/usr/lib/x86_64-linux-gnu/pulseaudio/x86_64:/usr/lib/x86_64-linux-gnu/pulseaudio        
(RUNPATH from file ./libpulse.so.0)

Here, libpulse is looking for libpulsecommon using its own runpath, which doesn't contain the immediate relative path. I had switched to using rpath instead of runpath because I saw it mentioned that rpath should propagate to dependencies (whereas runpath is "every binary handles itself"). This doesn't seem to be the case, though.

What's the proper way to set up a Linux executable so that any dependencies that I provide in the same directory will be found by it and its dependencies?


Solution

  • I ended up not doing anything at build time, and instead added a post-build step to my CMake where I run patchelf to change all the rpaths to $ORIGIN:

    if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
        add_custom_command(
                TARGET Client POST_BUILD
                    COMMAND find ${OUTPUT_DIR} -type f -maxdepth 1 -exec patchelf --set-rpath '\$\$ORIGIN' {} \\\;
        )
    endif()
    

    To be more complete for anyone reading around, the more-normal path is to have an install step where you put your files in the appropriate directories and make use of already-installed system shared libs. In my case an install step wouldn't be appropriate, so I'm adding custom commands after the build step to copy my dependencies into a directory with the executable and modify the rpath so they get loaded properly.