Issue
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.
Answered By - Osyotr Answer Checked By - Terry (WPSolving Volunteer)