Why is CMake designed so that it removes runtime path when installing

13,583

Solution 1

You may want to look into CMake's RPATH handling settings

This quote in particular seems relevant to your predicament:

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. When installing, it will clear the RPATH of these targets so they are installed with an empty RPATH.

You can set the RPATH that is set for installed binaries using the CMAKE_INSTALL_RPATH variable, for example:

SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")

and you can also disable the RPATH stripping during installation:

SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

Solution 2

I just want to answer question 1. The why this is done. Alex already posted a solution how to change this behaviour.

The reason is that when you build it you really want to use the libraries the build script saw on your machine. If you build a whole stack of libraries for your app you want no mistake that they aren't picked by the library. Therefore it makes sense to use the full rpath to the library. Also you never move your application around between compilation and when it's debugged and run.

But when installed the usual case in the unix world was to use the shared /usr/lib and /usr/local/lib directories. They are usually picked up (unless LD_LIBRARY_PATH is used) and thats normally what you want.

As you see by my wording, all this is a mess because it includes so many implicit decisions how you organize your build and your deployment. It is one of the reasons why the term 'DLL hell' once only popular on Windows moved over to Unix when it became more widely used. There is no technical solution because its not a technical problem (that part is solved). Its an organizational problem and CMake has to decide about the one flavour it supports on a platform by default. And IMHO they have choosen wisely.

Share:
13,583

Related videos on Youtube

Alaya
Author by

Alaya

Major in Microelectronics. know some Haskell/c++/perl

Updated on June 15, 2022

Comments

  • Alaya
    Alaya almost 2 years

    I built my shared library(I use a lib calculating the fibonacci number for example) myself and want to use it in my another c++ project built by CMake

    Let's say the shared library and headers located in /path/to/my/lib, the shared library libfib.so is in /path/to/my/lib/lib and the header fib.h is in /path/to/my/lib/include and my own project located in /path/to/my/project

    Here is my original CMakeLists.txt:

    cmake_minimum_required(VERSION 3.2)
    project(learn-lib)
    set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
    set(FIB_INCLUDE "${FIB_PREFIX}/include")
    set(FIB_LIB "${FIB_PREFIX}/lib")
    set(EXE mybin)
    include_directories(${FIB_INCLUDE})
    link_directories(${FIB_LIB})
    add_executable(${EXE} main.cpp)
    target_link_libraries(${EXE} fib)
    install(TARGETS ${EXE} RUNTIME DESTINATION bin)
    

    And I use this script to build and install my project:

    mkdir -p build_dir
    cd build_dir
    cmake -DFIB_PREFIX=/path/to/my/lib \
          -DCMAKE_INSTALL_PREFIX=/path/to/my/project \
          ..
    make
    make install
    cd ..
    

    Now, after running the install script, I got two executables, one in build_dir, one in the install location path/to/my/project/bin, when running the program in build_dir, everything is fine, but when running the installed program, I get:

    ./bin/mybin: error while loading shared libraries: libfib.so: cannot open shared object file: No such file or directory

    After some searching on google and stackoverflow, I knew it seems that CMake removed the runtime search path that is tied to the executable when building. I now know two ways to get it around:

    1. Add the library path where libfib.so locates to the environment variable LD_LIBRARY_PATH
    2. Add set_target_properties(${EXE} PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) into my CMakeLists.txt

    So, my questions are:

    1. Why is CMake designed so? When installing, why would it remove runtime path from executables instead of just copying the built executables to the install destination or whatever keeping the link path for the installed program?
    2. Which way is the best practice(or is there a best practice) to eliminate this problem? To set the environment or to add set_target_properties(...) into CMakeLists.txt ?
  • Alaya
    Alaya over 8 years
    I find that if I add SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) after add_executable(${EXE} main.cpp), cmake still would strip the runtime path, while set_target_properties(${EXE} PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) would always work regardless its position in CMakeLists.txt
  • Holger
    Holger over 2 years
    I have found the same as @Alaya on Mac OS. The RPATH handling in CMake seems off and the documentation not particularly helpful.
  • Dima Pasechnik
    Dima Pasechnik over 2 years
    CMake has made a mess out of it. Mind you, their docs on linking, rpath, etc, don't even mention ldconfig, and so CMake users are led up the garden path into believing that one has to put /usr/local/lib into LD_LIBRARY_PATH :-)
  • Lothar
    Lothar over 2 years
    No the problem is that linking is a mess on Unix and not taught in any programming class. It all works fine until deployment. So much now that there is a new job description now on the market defined as "Deployment Engineer" which is not DevOps.
  • Dima Pasechnik
    Dima Pasechnik over 2 years
    GNU autoconf, libtool et al. manages the job on Unix well enough, whereas cmake can't even get cmake --find-package right :P
  • Dima Pasechnik
    Dima Pasechnik over 2 years
    As if linking on Windoze is better - it's much worse if you ask me...
  • Louis Go
    Louis Go about 2 years
    CMAKE_INSTALL_RPATH_USE_LINK_PATH is a global cmake settings while INSTALL_RPATH_USE_LINK_PATH is per target. I think that's the difference @Alaya found.