Force IMPORTED target to use absolute path to .so file even when it is located in a subfolder of project root
Asked Answered
A

0

7

I have the following directory structure

.
├── 3rdparty
│   └── liba
│       ├── include
│       │   └── liba.hpp
│       └── lib
│           └── liba.so
├── cmake
│   └── FindLiba.cmake
├── CMakeLists.txt
└── source
    ├── CMakeLists.txt
    └── main.cpp

Here, liba is a commercial, closed-source third-party library. Unfortunately, the vendor of the library doesn't provide a CMake config for their library, so I wrote my own find module:

# cmake/FindLiba.cmake

# - Try to find liba
# Once done, this will define
#
#  Liba_FOUND - system has liba
#  Liba_INCLUDE_DIRS - the liba include directories
#  Liba_LIBRARIES - link these to use liba

# Include dir
find_path(Liba_INCLUDE_DIR
  NAMES liba.hpp
)

# Finally the library itself
find_library(Liba_LIBRARY
  NAMES a
)

include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set Liba_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args(Liba  DEFAULT_MSG
                                  Liba_LIBRARY Liba_INCLUDE_DIR)

mark_as_advanced(Liba_INCLUDE_DIR Liba_LIBRARY)

set(Liba_INCLUDE_DIRS ${Liba_INCLUDE_DIR})
set(Liba_LIBRARIES ${Liba_LIBRARY})

if (NOT TARGET Liba::Liba) 
    add_library(Liba::Liba SHARED IMPORTED) 
    set_target_properties(Liba::Liba PROPERTIES
        IMPORTED_LOCATION ${Liba_LIBRARIES} 
        INTERFACE_INCLUDE_DIRECTORIES ${Liba_INCLUDE_DIR}
    )
endif()

Since main.cpp makes use of this library, the CMakeLists.txt in the source folder looks like this:

find_package(Liba REQUIRED)

add_executable(main main.cpp)

# VERSION 1
target_link_libraries(main PRIVATE Liba::Liba)

# VERSION 2
target_link_libraries(main PRIVATE ${Liba_LIBRARIES})
target_include_directories(main PRIVATE ${Liba_INCLUDE_DIRS})

To build the entire thing I use cmake -Bbuild -H. -DCMAKE_PREFIX_PATH=${PWD}/3rdparty/liba && cmake --build build.

The problem I have is the following: With version 1, the compiled binary build/source/main links to ../3rdparty/liba/liba.so, as can be seen in the output of ldd:

ldd build/source/main
    [...]
    ../3rdparty/liba/lib/liba.so => not found
    [...]

With version 2, main links against liba.so without the relative path, but the rpath seems to be set such that it can still be found:

ldd build/source/main
    [...]
    liba.so => /home/manuel/development/demo/3rdparty/liba/lib/liba.so (0x00007f2a4c3f3000)
    [...]

The second version is preferable, as with version 1 the executable can be run only when the current working directory is build, cmake, 3rdparty or source, otherwise the shared library can't be found. In particular, I can't just run ./build/source/main after the project is built.

Interestingly enough, this seems only to be an issue because liba is located within the project subtree. When I move liba outside of the project directory and adjust the CMAKE_PREFIX_PATH accordingly, it also works fine. But I'd like to keep it where it currently is just so that is is part of the git repository and versioned with the main.cpp that uses it.

Is there a way to configure the IMPORTED target Liba in such a way that just adding it to the target_link_libraries causes CMake to behave the same way as it does when adding ${Liba_LIBRARIES} instead?

Algicide answered 17/2, 2018 at 23:21 Comment(2)
I hit this issue, and worked around it by defining a dummy STATIC library instead of importing the library. I then set the INTERFACE_LINK_LIBRARYIES of that dummy target to include the full path to the library I wanted to link against.Merat
FYI: cmake.org/cmake/help/v3.14/prop_tgt/IMPORTED_NO_SONAME.htmlEnvoi

© 2022 - 2024 — McMap. All rights reserved.