skip to Main Content

So I am working on a project that is intended to run on a remote server. I develop the program on a local pc, compile it, then upload it to the remote server. Both the local pc and the remote server are run on CentOS 7.7.

The program is developed using the CLion IDE, configured with CMake. The program depends a few shared libraries, which are supposed to link to the executable according to what I wrote in CMake. At my local PC, I can compile and run the program perfectly. However, after I scp the whole directory of the project to the remote server, the executable fails to run. It cannot find any of the “.so” files, according to what ldd says.

This is my CMakeList.txt, with every path being relative path, instead of absolute path.

cmake_minimum_required(VERSION 3.15)
project(YS_Test)

set(CMAKE_CXX_STANDARD 11)

set(SOURCE_PATH_ src)

file(GLOB SOURCE_FILES_ ${SOURCE_PATH_}/*.*)

set(PROJECT_LIBS_ libTapQuoteAPI.so libTapTradeAPI.so libTapDataCollectAPI.so)

include_directories(api/include)
link_directories(api/lib/linux)

add_executable(YS_Test ${SOURCE_FILES_})

target_link_libraries(YS_Test ${PROJECT_LIBS_})

Please do not tell me to set LD_LIBRARY_PATH to fix my issue. The program worked fine on my local pc without LD_LIBRARY_PATH, so I expect it to run on the remote server without LD_LIBRARY_PATH. I would like to know what is really going on here, instead of a work around. Thanks!

2

Answers


  1. If I understand your problem correctly, you want to ship your compiled YS_Test program along with some dependencies and have it run on a remote server. By default an executable will only look in the directories configured in /etc/ld.so, which will not include the deploy path.

    Note: Typically you do not deploy your entire build directory but only the compiled artifacts and dependencies. For this answer I will assume you deploy the binary and its dependencies to the same directory.

    You have two options:

    • Require users of your program to set LD_LIBRARY_PATH, either by themselves or by a wrapper script. This variable will instruct the dynamic linker to look in the specified directories as well. Even if you do not like this solution, it is by far the most common approach.
    • Add -Wl,-rpath='$ORIGIN' to your linker options. This will add a DT_RUNPATH attribute to the executable’s dynamic section. As you are using CMake you can also set this using BUILD_RPATH and/or INSTALL_RPATH target properties.
      The ld.so manpage describes this attribute as follows:

      If a shared object dependency does not contain a slash, then it is
      searched for in the following order:

      • Using the directories specified in the DT_RUNPATH dynamic section
        attribute of the binary if present.

      The $ORIGIN part expands to the directory containing the program or shared
      object.

    If you really insist on shipping your build directory (eg during development), you can take a look at the CMake BUILD_RPATH_USE_ORIGIN property (and its usual global counterpart CMAKE_BUILD_RPATH_USE_ORIGIN), this will embed relative paths into binaries instead of absolute paths.

    Login or Signup to reply.
  2. As you don’t want a workaround (@Botje has given you two already), I will try an explanation instead. In your development machine, if you use this command:

    ldd YS_Test
    

    You will see all the shared libraries used by your program, with their corresponding paths. The libTapQuoteAPI.so libTapTradeAPI.so libTapDataCollectAPI.so are found at your ‘api/lib/linux’ directory, but resolved with full absolute paths. If you do the same at your server, some shared objects can’t be resolved because they aren’t at the same location.

    If you use one of these commands (not sure which are available in Centos):

    chrpath --list YS_Test
    

    or

    patchelf --print-rpath YS_Test
    

    You will see the RPATH or RUNPATH tags embedded in your program. This is the path used by the Linux linker to locate dependencies that are outside the standard ld locations. You may find extended explanations on Internet about this, like this one or the Wikipedia article.

    Breaking my promise, I give you a third workaround: use patchelf or chrpath at your server after scp to change the embedded RPATH tag, pointing it relative to $ORIGIN (which represents the program location).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search