CMake imported shared library links with relative path, breaks install

Viewed 755

I have a vendor library which needs to be included with my project's installer, I'm installing it with INSTALL(FILES ...). The library is stored along with the source, the problem is that the linked path (shown by readelf) is relative and that prefix doesn't get removed during installation, so instead of the dynamic linker searching for hhlib.so its looking for ../hhlib-linux-64bit/hhlib.so.

How can I get a working installed binary? Can I get the install step or CPack to remove this relative path to the library?

I've reduced the problem down to a simple example:

.
├── build
├── CMakeLists.txt
├── hhlib-linux-64bit
│   ├── hhlib.h
│   └── hhlib.so
└── use_hydroharp.c
cmake_minimum_required (VERSION 3.19)

# These sets have no effect on the issue

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

enable_language(C)
# Find the header files
find_path(HydroHarp_INCLUDEDIR
    NAMES hhlib.h
    PATHS "${CMAKE_CURRENT_SOURCE_DIR}/hhlib-linux-64bit"
    )
# Find the shared library
find_library(HydroHarp_LIBRARY
    NAMES hhlib.so
    HINTS "${CMAKE_CURRENT_SOURCE_DIR}/hhlib-linux-64bit"
    )

if(HydroHarp_INCLUDEDIR AND HydroHarp_LIBRARY)
    message("Found HyroHarp library")
    # Get the containing folder for the library
    get_filename_component(HydroHarp_LIBDIR ${HydroHarp_LIBRARY} DIRECTORY)
    
    # Import the library
    add_library(HydroHarp SHARED IMPORTED)

    set_target_properties(HydroHarp PROPERTIES
        INTERFACE_INCLUDE_DIRECTORIES ${HydroHarp_INCLUDEDIR}
        IMPORTED_LOCATION ${HydroHarp_LIBRARY}
    )
    # copy  the library when installing
    install(FILES ${HydroHarp_LIBRARY} TYPE LIB)

else()
    message(WARNING "Failed to find HydroHarp")
endif()

project(extlink)
add_executable(${PROJECT_NAME} use_hydroharp.c)
target_link_libraries(${PROJECT_NAME} PRIVATE HydroHarp)

# install the library
install(TARGETS ${PROJECT_NAME}
    RUNTIME DESTINATION bin
    )

set(CPACK_GENERATOR DEB CACHE INTERNAL "")

SET(CPACK_PACKAGE_CONTACT "asdaksd@kjhk.com")
SET(CPACK_PACKAGE_VENDOR "asdfasd")

include(CPack)

Built with:

build$ cmake .. && make package

The program references the shared library with a relative path (which is fine for the build tree but not needed due to the RUNPATH):

build$ readelf -d extlink
Dynamic section at offset 0x2da8 contains 29 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [../hhlib-linux-64bit/hhlib.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000001d (RUNPATH)            Library runpath: [/code/hhlib-linux-64bit:]
 0x000000000000000c (INIT)               0x1000
...

but after make install it's still there and the RUNPATH has been removed:

build$ readelf -d /usr/bin/extlink
Dynamic section at offset 0x2da8 contains 28 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [../hhlib-linux-64bit/hhlib.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000c (INIT)               0x1000

I'm building on Ubuntu 20.04 with CMake 3.16.3 but also tested with the latest CMake version 3.19.4 At first I thought this issue provided a solution, but no combination of those RPATH variables fixes the problem.

1 Answers

After a nice, long scream into my favourite screaming pillow I had another think:

Adding the property IMPORTED_NO_SONAME removes the offending path but the linker fails to find it - even when the path is explicitly included with LINK_DIRECTORIES, why? Because the vendor library doesn't follow the naming convention!

Renaming the library to libhh.so and adding set_target_properties(HydroHarp PROPERTIES IMPORTED_NO_SONAME TRUE) fixes the issue. Don't ask me why.

The full working CMakeLists.txt:

cmake_minimum_required (VERSION 3.19)
enable_language(C)

# Find the header files
find_path(HydroHarp_INCLUDEDIR
    NAMES hhlib.h
    PATHS "${CMAKE_CURRENT_SOURCE_DIR}/hhlib-linux-64bit"
    )
# Find the shared library
find_library(HydroHarp_LIBRARY
    NAMES hh # <-- Note removed .so so standard extensions are searched
    HINTS "${CMAKE_CURRENT_SOURCE_DIR}/hhlib-linux-64bit"
    )

if(HydroHarp_INCLUDEDIR AND HydroHarp_LIBRARY)
    message("Found HyroHarp library")
    # Import the library
    add_library(HydroHarp SHARED IMPORTED)

    set_target_properties(HydroHarp PROPERTIES
        INTERFACE_INCLUDE_DIRECTORIES ${HydroHarp_INCLUDEDIR}
        IMPORTED_NO_SONAME TRUE # <-- This lib wasn't built with an SONAME
        IMPORTED_LOCATION ${HydroHarp_LIBRARY}
    )
    # copy  the library when installing
    install(FILES ${HydroHarp_LIBRARY} TYPE LIB)

else()
    message(WARNING "Failed to find HydroHarp")
endif()

project(extlink)
add_executable(${PROJECT_NAME} use_hydroharp.c)
target_link_libraries(${PROJECT_NAME} PRIVATE HydroHarp)

# install the library
install(TARGETS ${PROJECT_NAME}
    RUNTIME DESTINATION bin
    )

set(CPACK_GENERATOR DEB CACHE INTERNAL "")

SET(CPACK_PACKAGE_CONTACT "asdaksd@adssd.com")
SET(CPACK_PACKAGE_VENDOR "asdfasd")

include(CPack)
Related