1

For using find_package( for another library that I am using (it is not supporting CMake), I have developed something like this (I am using gcc10 on CentOS 7 and CMake 3.20 with Ninja 1.10.2):

add_library(MyLib UNKNOWN IMPORTED)
target_include_directories(MyLib 
   INTERFACE "$ENV{MY_LIB}/include")

target_link_libraries(MyLib INTERFACE ${CMAKE_DL_LIBS})
set_property(TARGET MyLib PROPERTY
   IMPORTED_LOCATION "$ENV{MY_LIB}/lib/libmylib.so"
)

and in my project, I simply use find_package and link against it:

find_package(MyLib REQUIRED PATHS "${CMAKE_MODULE_PATH}" NO_DEFAULT_PATH)
target_link_libraries(myApp
   PUBLIC MyLib 
)

The strange behavior that I see with this code is that the linker puts the absolute path of libmylib.so in myApp target. In other words, if I copy/move my whole project into a new folder, it fails to load the library:

/data/projects/myApp/external/myLib/lib/libmylib.so: cannot open shared object file: No such file or directory

Can anyone tell me why the path to 'libmylib.so' is hard-coded?

Note: the LD_LIBRARY_PATH is already set and valid.

Update 1: If I run readelf -d myApp | head -20, I will see this result:

[user]$ readelf -d myApp | head -20

Dynamic section at offset 0x101588 contains 73 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libsth1.so]
 0x0000000000000001 (NEEDED)             Shared library: [libsth2.so]
 0x0000000000000001 (NEEDED)             Shared library: [/data/projects/myApp/external/myLib/lib/libmylib.so]

Update 2: I have tried to unset these two variables, but nothing changes:

set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(CMAKE_SKIP_RPATH TRUE)
TonySalimi
  • 8,257
  • 4
  • 33
  • 62
  • Because this was the place when it was build. And that way you can directly run it after building. You can add "/data/projects/myApp/external/myLib/lib/" to LD_LIBRARY_PATH and then your executeable will run. – Gunther Jan 17 '23 at 12:33
  • Or you can edit the RPATH or RUNPATH like this: # Make sure required .so files are found in the same folder as the shared library set_target_properties(${LIBNAME} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE #INSTALL_RPATH_USE_LINK_PATH TRUE INSTALL_RPATH "\$ORIGIN" ) +endif() – Gunther Jan 17 '23 at 12:36
  • @Gunther the LD_LIBRARY_PATH is already set, but it still goes to the place that it was built – TonySalimi Jan 17 '23 at 13:06
  • Please give us the output of "ldd myApp" – Gunther Jan 17 '23 at 13:10
  • Maybe helpful: https://stackoverflow.com/questions/2836330/is-there-a-programmatic-way-to-inspect-the-current-rpath-on-linux – Gunther Jan 17 '23 at 13:18
  • @Gunther the `ldd myApp` cannot find mylib.so, because it is trying to access it from the path it had during build phase. – TonySalimi Jan 17 '23 at 13:49
  • Look up `RPATH`. – Jesper Juhl Jul 21 '23 at 23:36

2 Answers2

2

There are multiple ways how to get your executeable to work:

(1) Edit LD_LIBRARY_PATH

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"PATH_TO_SO"

will allow the dynamic linker to find and link the shared object.

(2) Edit RPATH

# Make sure required .so files are found in the same folder as the shared library
set_target_properties(myApp PROPERTIES
   BUILD_WITH_INSTALL_RPATH TRUE
   #INSTALL_RPATH_USE_LINK_PATH TRUE
   INSTALL_RPATH "\$ORIGIN"
 )

I would prefer (2) if you want to move your app around in the file system.

Update explanation:

cmake tries to get your build to work. Internally it usually uses absolute paths. Generated cmake projects are not copyable to other places in the filesystem, but have to regenerated.

find_package() returns the absolute path to your library. Its the only assumption it can make. Just adding the library name without the full path could lead to using a similar named but wrong (incompatible, wrong version) shared object.

It is your task to prepare everything in your CMakeLists install section. Those rules should describe what to copy and how to prepare encompanied shared object libraries. Packaging systems like rpm or dhbuild depend on it.

I hope that is helpful.

Bye Gunther

Gunther
  • 374
  • 2
  • 10
  • How I can tell to CMake that do not use rpath for any linking libraries? Is there anyway to do that? – TonySalimi Jan 17 '23 at 13:08
  • 1
    @TonySalimi: "How I can tell to CMake that do not use rpath for any linking libraries?" - You may set CMAKE_SKIP_RPATH variable. This is described in the [wiki](https://gitlab.kitware.com/cmake/community/-/wikis/doc/cmake/RPATH-handling#no-rpath-at-all), where you may find more information about RPATH settings in CMake. – Tsyvarev Jan 17 '23 at 19:17
  • @Tsyvarev I have already used `CMAKE_SKIP_BUILD_RPATH ` but it is not working. What is the difference between these two? any ideas? – TonySalimi Jan 18 '23 at 09:38
  • `CMAKE_SKIP_BUILD_RPATH` skips RPATH in the build tree, CMAKE_SKIP_RPATH skips RPATH in the both build tree and in the install tree. These variables affect only on the targets, which are defined **later**. That is `set(CMAKE_SKIP_RPATH ON)` + `add_executable(myApp)` works but `add_executable(myApp)` + `set(CMAKE_SKIP_RPATH ON)` doesn't work. – Tsyvarev Jan 18 '23 at 11:00
  • @Tsyvarev setting the variables to OFF even before add_executable does not work for me. – TonySalimi Jan 21 '23 at 23:53
  • These variables should be set to `ON`, not to `OFF`. – Tsyvarev Jan 22 '23 at 08:37
1

I can`t comment so I will write it here.

Pls, check if SONAME is present in your shared library. Details are here: Why does CMake links external library by relative path?

After fixing SONAME my binary was added to the executable without an absolute path to it.