'How to correctly set rpath to shared library with CMake?

How can I link OpenNI (libOpenNI2.so) at run time to my C++ program? This question/answer is most relevant to my question. I followed it and prepared the following CMakeLists.txt but still it cannot link the .so file and generates an error /usr/bin/ld: cannot find -lOpenNI2

I use cmake .. && cmake --build . --config Release to compile the program.

I tried $ORIGIN, $$ORIGIN, \$ORIGIN and I noticed that ORIGIN is empty string.

What am I doing wrong?

cmake_minimum_required(VERSION 3.1)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)

project(rgbd)# project name

# to link OpenNI2 at runtime
SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
SET(CMAKE_INSTALL_RPATH "")

add_executable(rgbd rgbd.cpp)

message(STATUS ${ORIGIN})# display ORIGIN

set_target_properties(rgbd PROPERTIES LINK_FLAGS "-Wl,-rpath,$ORIGIN/../OpenNI-Linux-x64-2.3.0.66/Redist")

target_link_libraries(rgbd libOpenNI2.so)


Solution 1:[1]

The rpath is information that's only used at runtime to find the lib. The linker will not use it to determine the location of the location of libraries to link.

With cmake you could specify an absolute path for target_link_libraries here or add a link directory and let the linker figure out which file to use.

Path to lib

# not sure if this is the exact path; you may need to do some adjustments
target_link_libraries(rgbd "${CMAKE_CURRENT_SOURCE_DIR}/../OpenNI-Linux-x64-2.3.0.66/Redist/libOpenNI2.so")

Link directory

# again not sure, if the path is correct here
target_link_directories(rgdb PRIVATE ../OpenNI-Linux-x64-2.3.0.66/Redist)
target_link_libraries(rgbd PRIVATE OpenNI2)

If you're linking the lib to multiple targets, using an imported library may be a good idea, since it allows you to add info like include directories and additional dependencies to the lib.

add_library(OpenNI2_import SHARED IMPORTED GLOBAL)
set_target_properties(OpenNI2_import PROPERTIES
    IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../OpenNI-Linux-x64-2.3.0.66/Redist/libOpenNI2.so"
)

# include directories could be added
target_include_directories(OpenNI2_import INTERFACE
    "${CMAKE_CURRENT_SOURCE_DIR}/../OpenNI-Linux-x64-2.3.0.66/include" # probably not the correct path; use absolute paths here
)

# could add dependencies, if necessary
target_link_libraries(OpenNI2_import INTERFACE some_other_lib)

...

target_link_libraries(rgbd PRIVATE OpenNI2_import)

You may still need to adjust the rpath, but using \$ORIGIN/... should work to get "cmake" to put $ORIGIN/... in the rpath of the resulting binary.

Solution 2:[2]

The error you get isn't at runtime but at link time. ld cannot find the specified libOpenNI2.so because you haven't provided any search path to the linker.


You shouldn't have to do anything special as CMake will use build rpath by default (that gets removed during installation, but this is not a step that you've configured anyway).

This should be enough:

cmake_minimum_required(VERSION 3.13)
project(rgbd)

add_executable(${PROJECT_NAME} rgbd.cpp)
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_11)
target_link_directories(${PROJECT_NAME} PRIVATE ../OpenNI-Linux-x64-2.3.0.66/Redist)
target_link_libraries(${PROJECT_NAME} PRIVATE OpenNI2)
cd path/to/project
cmake -B build/Release -DCMAKE_BUILD_TYPE=Release
cmake --build build/Release
./build/Release/rgbd

Now if you're going to ship your executable, consider adding a correct installation step with install rpath handled:

cmake_policy(SET CMP0095 OLD) //CMake>=3.16 handles $ORIGIN escaping differently
set_target_properties(${PROJECT_NAME}
    PROPERTIES
        INSTALL_RPATH "\\\$ORIGIN/../lib"
)

include(GNUInstallDirs)
install(TARGETS ${PROJECT_NAME})
install(FILES ../OpenNI-Linux-x64-2.3.0.66/Redist/libOpenNI2.so TYPE LIB)
cmake -B build/Release -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$PWD/package
cmake --build build/Release --target install
./package/bin/rgbd

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2