Parent of RPATH $ORIGIN - c++

I can set install rpath to be the working directory with the following command:
set(CMAKE_INSTALL_RPATH "$ORIGIN")
But is there a possibility to search for the shared libraries in the parent of the $ORIGIN?

Related

use mariadb-connector-cpp with cmake project

github repo. i am using c++20 with cmake on visual studio to program on wsl and getting error loading shared library. can't find file libmariadb.so.3.
I used the build instructions to build it for Debian & Ubuntu on wls and it was installed in these paths.
so in my cmake I included
find_package(mariadbcpp)
include_directories("/usr/local/include/mariadb")
link_directories("/usr/local/lib/mariadb")
target_link_libraries(${PROJECT_NAME} mariadbcpp)
when I run I get the following error
error while loading shared libraries: libmariadb.so.3: cannot open shared object file: No such file or directory
I tried running
sudo /sbin/ldconfig -v
and I also tried including this in my top level cmake
SET(CMAKE_SKIP_BUILD_RPATH FALSE)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
SET(CMAKE_INSTALL_RPATH "/usr/local/lib/mariadb")
to get it working you just need to add this to your cmake
include_directories("/usr/include/mariadb") #path to include folder
add_library(mariadbcpp STATIC IMPORTED)
set_property(TARGET mariadbcpp PROPERTY IMPORTED_LOCATION "/usr/lib/libmariadbcpp.so") #path to libmariadbcpp.so
then just include
#include <conncpp.hpp>
in source
to install I followed this Debian/Ubuntu and in step 10 the command to install libmariadbcpp.so.3 and lib/mariadb... should have been lib64/mariadb...
like so
sudo install lib64/mariadb/libmariadbcpp.so /usr/lib
sudo install lib64/mariadb/libmariadbcpp.so.3 /usr/lib
sudo install lib64/mariadb/plugin/* /usr/lib/mariadb/plugin

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)
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
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.

How to link a shared library with CMake with relative path

I want to link a third-party libLibrary.so and distribute it with my program. If user unzips my archive, he will get this folder structure:
game
libLibrary.so
game_executable
game_executable depends on ./libLibrary.so.
My project structure:
game
bin
libLibrary.so
lib
Library.h
src
game_executable.cpp
CMakeLists.txt
My CMakeLists.txt:
cmake_minimum_required(VERSION 3.7)
project(game)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/bin)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set(SOURCE_FILES src/game_executable.cpp)
include_directories(${CMAKE_SOURCE_DIR}/lib)
add_executable(game ${SOURCE_FILES})
target_link_libraries(${PROJECT_NAME} ${CMAKE_BINARY_DIR}/libLibrary.so)
However, what I get is my game_executable depends on the .../game/bin/libLibrary.so, not on the ./libLibrary.so that is in the folder with game_executable, making this totally unportable!
How can I make linking path relative instead of absolute?
From the documentation:
By default if you don't change any RPATH related settings, CMake will link the executables and shared libraries with full RPATH to all used libraries in the build tree.
This is the behaviour you are seeing.
However, there are a number of ways to change this to match the behaviour you require.
Some examples from the above linked docs:
# use, i.e. don't skip the full RPATH for the build tree
SET(CMAKE_SKIP_BUILD_RPATH FALSE)
# when building, don't use the install RPATH already
# (but later on when installing)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
# the RPATH to be used when installing
SET(CMAKE_INSTALL_RPATH "")
# don't add the automatically determined parts of the RPATH
# which point to directories outside the build tree to the install RPATH
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
Using the above you'll likely want to set CMAKE_INSTALL_RPATH and then distribute the installed binary.
If you want to distribute from the binary in your build tree, it is also possible to bypass CMake's rpath handling and modify the rpath directly using linker flags:
set_target_properties(game PROPERTIES LINK_FLAGS "-Wl,-rpath,./")
Most of the time you want to set the RPATH to $ORIGIN instead of ., because it refers to the executable's path instead while . refers to the current directory at runtime (which can be anything else).
I find it simple to edit LINK_FLAGS instead of INSTALL_RPATH target property, because CMakes already has a variable named ORIGIN (see CMake's documentation).
So that boils down to the following:
# Find shared libraries next to the executable
set_target_properties(target_name PROPERTIES
BUILD_WITH_INSTALL_RPATH FALSE
LINK_FLAGS "-Wl,-rpath,$ORIGIN/")
Talking about distribution the executable or shared library with dynamically linked libraries and CMake build system:
SET(CMAKE_BUILD_RPATH_USE_ORIGIN TRUE)
This var forces linking with relative path within the build tree, so in result the build directory can be movable.
If you use this command on linux machine
find <YOUR_TARGET_NAME> -type f -perm /a+x -exec ldd {} \; | grep so | sed -e '/^[^\t]/ d' | sed -e 's/\t//' | sed -e 's/.*=..//' | sed -e 's/ (0.*)//' | sort | uniq -c | sort -n
you will see the dot in the path, which indicates the relativity, example:
~/project/build/./lib/my_shared_lib.so
See more in CMake docs.
If you use target_link_directories then cmake will add it to the linker command as a manual rpath

Add external libraries to CMakeList.txt c++

I have my external library as shown in this picture that I create the symbolic links after:
and the headers related to the library in other file:
I'm working with ROS ubuntu and I need to add these libraries to my package to CmakeList.txt:
cmake_minimum_required(VERSION 2.4.6)
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)
rosbuild_init()
#set the default path for built executables to the "bin" directory
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
#set the default path for built libraries to the "lib" directory
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
#common commands for building c++ executables and libraries
#rosbuild_add_library(${PROJECT_NAME} src/example.cpp)
#target_link_libraries(${PROJECT_NAME} another_library)
#rosbuild_add_boost_directories()
#rosbuild_link_boost(${PROJECT_NAME} thread)
#rosbuild_add_executable(example examples/example.cpp)
#target_link_libraries(example ${PROJECT_NAME})
rosbuild_add_executable(kinectueye src/kinect_ueye.cpp)
So my question is how can I add these folders (I think the first one that I need to add I'm not sure) to my CmakeList.txt file so as I can use the classes and the methods in my program.
I would start with upgrade of CMAKE version.
You can use INCLUDE_DIRECTORIES for header location and LINK_DIRECTORIES + TARGET_LINK_LIBRARIES for libraries
INCLUDE_DIRECTORIES(your/header/dir)
LINK_DIRECTORIES(your/library/dir)
rosbuild_add_executable(kinectueye src/kinect_ueye.cpp)
TARGET_LINK_LIBRARIES(kinectueye lib1 lib2 lib2 ...)
note that lib1 is expanded to liblib1.so (on Linux), so use ln to create appropriate links in case you do not have them

Building of executable and shared library with cmake, runtimelinker does not find dll

I am working with gcc(cygwin), gnu make, windows 7 and cmake.
my cmake testprojekt has the following structure
rootdir
|-- App
| |-- app.cpp
| +-- CMakeLists.txt
|-- Lib
| |-- lib.cpp
| |-- CMakeLists.txt
|-- MakeFileProject
+ CMakeLists.txt
rootdir/App/app.cpp:
#include<string>
void printThemMessageToScreen(std::string input);//prototype
int main(int argc,char **argv){
printThemMessageToScreen("this will be displayed by our lib");
return 0;
}
rootdir/Lib/lib.cpp:
#include<iostream>
#include<string>
void printThemMessageToScreen(std::string input){
std::cout<<input;
}
rootdir/CMakeLists.txt:
cmake_minimum_required(VERSION 2.6)
project(TestProject)
add_subdirectory(App)
add_subdirectory(Lib)
rootdir/Lib/CMakeLists.txt:
add_library(Lib SHARED lib.cpp)
rootdir/App/CMakeLists.txt:
# Make sure the compiler can find include files from our Lib library.
include_directories (${LIB_SOURCE_DIR}/Lib)
# Make sure the linker can find the Lib library once it is built.
link_directories (${LIB_BINARY_DIR}/Lib)
# Add executable called "TestProjectExecutable" that is built from the source files
add_executable (TestProjectExecutable app.cpp)
# Link the executable to the lib library.
target_link_libraries (TestProjectExecutable Lib)
Now, when i run cmake and make, everything will get generated & built with no errors, but when i try to execute the binary, it will fail because the library which was generated could not be found.
BUT: when i copy the lib dll into the same directory like the app exe, it will get executed!
also: if i configure the library to be static, it will also execute.
how to tell the runtime linker where to look for my dll?
UPDATE:
Solution according to the Method proposed by User Vorren:
I opened up the registry editor, and navigated to the following Key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
, here i created a new key with the name of my Applikation:
in this case : TestProjectExecutable.exe
after that, the (default) value was set to the full path of TestProjectExecutable.exe including the filename and extension. Then i created another String Value called "Path" and set the value to the folder where the dll was located:
Your problem lies not with linker or compiler, but with the way Windows searches for DLL's.
The OS will use the following algorithm to locate the required DLL's:
Look in:
The directories listed in the Application-specific Path registry key;
The directory where the executable module for the current process is located;
The current directory;
The Windows system directory;
The Windows directory;
The directories listed in the PATH environment variable;
Thus you have two reasonable options if you don't want to clutter the OS directories with your app-specific dll:
Create an app-specific Path registry entry (I would go with this option);
Put your DLL in the same folder as your EXE;
Modify the PATH variable (but why would you do that, if you can go with option 1?);
A solution I prefer that hasn't really been mentioned, is build your shared-libs into the same directory as your executables. This tends to be a much simpler solution.
One way to do this with cmake is
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
Or you can also set output directories based on build flavours.
See how do I make cmake output into a 'bin' dir?
I discovered (what I believe to be) quite a nice way of handling this. It follows the approach of adding the .dll to the same directory as the .exe. You can do it in CMake like so:
if (WIN32)
# copy the .dll file to the same folder as the executable
add_custom_command(
TARGET <app-target> POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
$<TARGET_FILE_DIR:<lib-target>>
$<TARGET_FILE_DIR:<app-target>)
endif()
where app-target is the name of the application or library you're building (created through add_executable or add_library) and lib-target is the imported library brought in with find_package.
# full example
cmake_minimum_required(VERSION 3.14)
project(my-app-project VERSION 0.0.1 LANGUAGES CXX)
find_package(useful-library REQUIRED)
add_executable(my-application main.cpp)
target_link_libraries(my-application PUBLIC useful-library::useful-library)
if (WIN32)
# copy the .dll file to the same folder as the executable
add_custom_command(
TARGET my-application POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
$<TARGET_FILE_DIR:useful-library::useful-library>
$<TARGET_FILE_DIR:my-application>)
endif()
I tried the option 1 from accepted answer (by pdeschain).
I even created a cmake hook to register paths of linked libraries automatically
function (xtarget_link_libraries target libs) # same as target_link_libraries but with additional improvements to allow windows find the library at runtime
LIST(REMOVE_AT ARGV 0)
SET(LIBS ${ARGV}) # this is to pass list into this function
target_link_libraries(${target} ${LIBS}) # call standard routine
if(WIN32)
set(TFILE ".")
get_property(slibs TARGET ${target} PROPERTY all_libs) # recall libs linked before
set(LIBS ${slibs};${LIBS})
set_property(TARGET ${target} PROPERTY all_libs ${LIBS}) # save all libs
FOREACH(lib ${LIBS}) # compose a list of paths
set(TFILE "${TFILE};$<TARGET_LINKER_FILE_DIR:${lib}>")
ENDFOREACH()
#add reg key
add_custom_command(TARGET ${target} POST_BUILD COMMAND reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\${target}.exe" /v "Path" /d "${TFILE}" /f )
endif()
endfunction()
Can be used as xtarget_link_libraries(test lib1 lib2). The application will be able to find dynamic libraries at their absolute paths.
BUT, there is a big problem with this, that the App Paths mechanism https://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx#appPaths
does not allow to have different entries for say 'Debug/test.exe' and 'Release/test.exe'. So to me this is a poor option.
You may add the following line to fill the Default key as path to the program as suggested in the post.
add_custom_command(TARGET ${target} POST_BUILD COMMAND reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\${target}.exe" /ve /d "$<TARGET_FILE:${target}>" /f )
Now you can enjoy running test.exe from anywhere in the system... I guess my next try will be option
Create symbolic links to dlls with cmake.