# CMake-built executable is missing rpath for shared lib it uses

**URL:** <https://discourse.cmake.org/t/cmake-built-executable-is-missing-rpath-for-shared-lib-it-uses/15194>\
**Category:** Code\
**Created:** [September 24, 2025, 10:49am UTC](https://discourse.cmake.org/t/cmake-built-executable-is-missing-rpath-for-shared-lib-it-uses/15194 "2025-09-24T10:49:03Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![manuel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/67e7ee/32.png) [@manuel](https://discourse.cmake.org/u/manuel)\
**Post date:** [September 24, 2025, 10:49am UTC](https://discourse.cmake.org/t/cmake-built-executable-is-missing-rpath-for-shared-lib-it-uses/15194/1 "2025-09-24T10:49:03Z")

</div>

Greetings!

I’m writing an application that links against a shared library libaes.so. libaes.so is available here:

```auto
/usr/local/include/libaes/aes.hpp
/usr/local/include/libaes/message.hpp
/usr/local/include/libaes/octet_string.hpp
/usr/local/lib/libaes.so.1
/usr/local/lib/libaes.so
/usr/local/lib/pkgconfig/libaes.pc

```

CMake finds the pkg-config file and builds my project just fine. I can call into libaes.so from my code. But when running the built executable, it tells me it cannot find libaes.so. When providing the path using LD\_PRELOAD it works.

```auto
$ tests/secure-tcp-socket
tests/secure-tcp-socket: error while loading shared libraries: libaes.so.1: cannot open shared object file: No such file or directory

$ $ ldd tests/secure-tcp-socket
        linux-vdso.so.1 (0x00007ffc3bdde000)
        libaes.so.1 => not found
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fc6c8e00000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fc6c90f5000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc6c8c1f000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc6c8b3f000)

$ LD_PRELOAD=/usr/local/lib/libaes.so.1 tests/secure-tcp-socket
Server: Running on port 34461. Awaiting connections...
Client: Connecting to 127.0.0.1:34461...

```

What’s the canonical way of baking the path to libaes.so into the executable? I’m wondering if I made a mistake because CMake should know where to find libaes.so. I’d assume it would use this info if it could.

Being a new user, I cannot yet upload attachments, so please find the relevant CMakeLists.txt below.

Thanks in advance!

```auto
cmake_minimum_required( VERSION 3.13.4 )

## ========================= ###
## --- secure-tcp-socket --- ###
## ========================= ###

add_library( secure_tcp_socket STATIC )

set_target_properties( secure_tcp_socket
    PROPERTIES
    CXX_STANDARD 11
    PUBLIC_HEADER "inc/ecdh_handshaker.hpp;inc/secure-tcp-server.hpp;inc/secure-tcp-client.hpp" # for install()
)

# target_compile_definitions( secure_tcp_socket PUBLIC BOOST_ASIO_ENABLE_HANDLER_TRACKING )

find_package( PkgConfig REQUIRED )
pkg_check_modules( AES REQUIRED libaes )

target_include_directories( secure_tcp_socket
    PUBLIC inc
    PRIVATE ${AES_INCLUDE_DIRS} )

target_sources( secure_tcp_socket
    PRIVATE ecdh_handshaker.cpp
    PRIVATE secure-tcp-server.cpp
    PRIVATE secure-tcp-client.cpp )

# Available in Debian package `libboost-system-dev`.
find_package( Boost CONFIG REQUIRED
    COMPONENTS system )

set( THREADS_PREFER_PTHREAD_FLAG ON )
find_package( Threads REQUIRED )

target_link_libraries( secure_tcp_socket
PRIVATE Threads::Threads
PRIVATE Boost::headers
PRIVATE ${AES_LIBRARIES} )

## ============================== ###
## --- secure_tcp-socket_test --- ###
## ============================== ###

add_executable( secure_tcp_socket_test )

set_target_properties( secure_tcp_socket_test
    PROPERTIES
    CXX_STANDARD 11 )

target_sources( secure_tcp_socket_test
    PRIVATE test.cpp )

target_link_libraries( secure_tcp_socket_test
    PRIVATE secure_tcp_socket )

add_test( secure-tcp-socket-test secure_tcp_socket_test )

# Copy executable to root of build tree
add_custom_command(
    TARGET secure_tcp_socket_test POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy
            ${CMAKE_CURRENT_BINARY_DIR}/secure_tcp_socket_test
            ${CMAKE_BINARY_DIR}/tests/secure-tcp-socket )

```

---

<div class="post-metadata">

**Author:** ![retif](https://discourse.cmake.org/user_avatar/discourse.cmake.org/retif/32/1776_2.png) [@retif](https://discourse.cmake.org/u/retif)\
**Post date:** [September 24, 2025, 7:17pm UTC](https://discourse.cmake.org/t/cmake-built-executable-is-missing-rpath-for-shared-lib-it-uses/15194/2 "2025-09-24T19:17:27Z")

</div>

From what I know about that, it has to do with [BUILD\_RPATH](https://cmake.org/cmake/help/latest/prop_tgt/BUILD_RPATH.html#prop_tgt:BUILD_RPATH), since you are not using [install()](https://cmake.org/cmake/help/latest/command/install.html) and just copy the executable with `add_custom_command()` (_otherwise it would have been [INSTALL\_RPATH](https://cmake.org/cmake/help/latest/prop_tgt/INSTALL_RPATH.html)_).

You should be able to set it manually:

```cmake
set_target_properties(secure_tcp_socket_test
    PROPERTIES
        BUILD_RPATH "/usr/local/lib"
)

```

or instead this should work too, but it needs to be done before the target creation:

```cmake
list(APPEND CMAKE_BUILD_RPATH "/usr/local/lib")

```

I’m just guessing here, I’ve never tried/needed that myself.

---

<div class="post-metadata">

**Author:** ![manuel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/67e7ee/32.png) [@manuel](https://discourse.cmake.org/u/manuel)\
**Post date:** [September 24, 2025, 11:59pm UTC](https://discourse.cmake.org/t/cmake-built-executable-is-missing-rpath-for-shared-lib-it-uses/15194/3 "2025-09-24T23:59:33Z")

</div>

Thank you, @retif, that indeed fixes the problem!

Still, I was puzzled why this manual intervention is necessary. I used pkgconfig to include libpng in my build, to check wether it is suffering from the same problem. That is, if I manually need to set the path to libpng as RPATH as well. Turns out, no, it worked without problems. ldd listed the path just fine. So it seems there is some crucial difference between libpng and my libaes. After ruling out that the pkgconfig files trigger this change in behaviour, it figured it must be the install location: libpng installs in /usr/lib/x86\_64-linux-gnu, my libaes in /usr/local/lib.

So I reconfigured my project to install libaes in /usr/lib/x86\_64-linux-gnu as well and tada, everything works without problems.

```auto
/usr/include/libaes/aes.hpp
/usr/include/libaes/message.hpp
/usr/include/libaes/octet_string.hpp
/usr/lib/x86_64-linux-gnu/libaes.so.1
/usr/lib/x86_64-linux-gnu/libaes.so
/usr/lib/x86_64-linux-gnu/pkgconfig/libaes.pc

```

ldd lists the correct path and the executable runs without LD\_PRELOAD. Adapting CMakeLists.txt the way you suggested is not necessary.

```auto
$ ldd tests/secure-tcp-socket
        linux-vdso.so.1 (0x00007ffdc31e2000)
        libpng16.so.16 => /lib/x86_64-linux-gnu/libpng16.so.16 (0x00007f4be067a000)
        libaes.so.1 => /lib/x86_64-linux-gnu/libaes.so.1 (0x00007f4be066d000)
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f4be0400000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f4be064d000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4be021f000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f4be062c000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f4be013f000)
        libcrypto.so.3 => /lib/x86_64-linux-gnu/libcrypto.so.3 (0x00007f4bdfc00000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f4be0713000)

$ tests/secure-tcp-socket
Server: Running on port 34369. Awaiting connections...
Client: Connecting to 127.0.0.1:34369...

```

Just sharing this information in case someone finds this thread later on. I’m also curious if this is really how it’s supposed to work, because I can’t see any reason why you’d have to manually set the RPATH for shared libraries in /usr/local/lib, but not for those in /usr/lib.

---

<div class="post-metadata">

**Author:** ![retif](https://discourse.cmake.org/user_avatar/discourse.cmake.org/retif/32/1776_2.png) [@retif](https://discourse.cmake.org/u/retif)\
**Post date:** [September 25, 2025, 7:37am UTC](https://discourse.cmake.org/t/cmake-built-executable-is-missing-rpath-for-shared-lib-it-uses/15194/4 "2025-09-25T07:37:14Z")

</div>

> Still, I was puzzled why this manual intervention is necessary

I couldn’t find this in documentation (_although there is this [wiki entry](https://gitlab.kitware.com/cmake/community/-/wikis/doc/cmake/RPATH-handling#what-is-rpath)_), but it seems that only `/lib/` and `/usr/lib/` paths are added by default, so `/usr/local/lib/` is not there and requires manual adding.
