cmakeshared-librarieslibrary-pathrunpath

Why did RUNPATH get added to this executable?


I have the following simple CMake-based C project that builds one shared library target and one executable target, the former of which gets linked to the latter.

The project tree is organized thus:

$ tree ./
./
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    ├── app
    │   ├── CMakeLists.txt
    │   └── app.c
    └── mylib
        ├── CMakeLists.txt
        ├── mylib.c
        └── mylib.h

3 directories, 7 files

The associated CMakeLists.txt files are:

# ./CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(link_with_shared_library VERSION 1.0.0 LANGUAGES C)

add_subdirectory(src)
# ./src/CMakeLists.txt
add_subdirectory(mylib)
add_subdirectory(app)
# ./src/mylib/CMakeLists.txt
add_library(mylib SHARED mylib.c)
target_include_directories(mylib INTERFACE .)

if (MSVC)
  target_compile_definitions(mylib PRIVATE "MYLIB_EXPORT=__declspec(dllexport)")
  target_compile_definitions(mylib INTERFACE "MYLIB_EXPORT=__declspec(dllimport)")
else()
  target_compile_definitions(mylib PUBLIC "MYLIB_EXPORT=")
endif()
# ./src/app/CMakeLists.txt
add_executable(app app.c)
target_link_libraries(app PRIVATE mylib)

To prioritize information relevant to the question, I will add the source files at the bottom of this post, because I think they are not relevant to the question.

Unexpectedly, I noticed that when I ran the compiled executable, it was not necessary to set LD_LIBRARY_PATH, even though the compiled shared library on which the executable depends is not in ld.so's or linux-ld.so's default or configured search paths. I then discovered that the executable had its RUNPATH set:

$ objdump -x ./build/src/app/app | grep PATH
  RUNPATH              /home/user/dev/learning-cmake/multiplatform_linking_to_shared_libraries/build/src/mylib

My question is: why did RUNPATH get automagically set on the compiled executable?

I would venture a guess that it must be by virtue of the target_link_libraries(app PRIVATE mylib) statement in the src/app/CMakeLists.txt file, but I don't see/understand any verbiage at the CMake target_link_libraries documentation that mentions RUNPATH or conditions under which it is automagically added.


The source files:

// ./src/mylib/mylib.h
#ifndef MYLIB_H
#define MYLIB_H

typedef struct MYLIB_EXPORT MylibStruct {
  int i;
} MylibStruct;

MYLIB_EXPORT int mylib_func();

#endif
// ./src/mylib/mylib.c
#include "mylib.h"

int mylib_func() {
  return 42;
}
// ./src/app/app.c
#include <mylib.h>

int main(int argc, char* argv[]) {
  MylibStruct obj;
  obj.i = mylib_func();

  return 0;
}

Solution

  • This behavior is documented in BUILD_RPATH docs:

    By default, CMake sets the runtime path of binaries in the build tree to contain search paths it knows are needed to find the shared libraries they link.