cmake

Correct INTERFACE_LINK_LIBRARIES for IMPORTED library?


I am trying to write a FindFoo.cmake script to locate an external library called libfoo.so I want to use but the problem is that libfoo.so is linked against 2 external libraries more (let's call them libbar.so and libbaz.so) so when I try to link I always have undefined references.

This is what I tried:

FindFoo.cmake

find_path(Foo_INCLUDE_DIR NAMES foo.h)
mark_as_advanced(Foo_INCLUDE_DIR)

find_library(Foo_LIBRARY NAMES foo)
mark_as_advanced(Foo_LIBRARY)

if(Foo_INCLUDE_DIR AND Foo_LIBRARY)
  set(Foo_FOUND TRUE)

if(Foo_FOUND)
  add_library(Foo UNKNOWN IMPORTED)
  set_target_properties(Foo PROPERTIES
    IMPORTED_LOCATION                   "${Foo_LIBRARIES}"
    INTERFACE_INCLUDE_DIRECTORIES       "${Foo_INCLUDE_DIR}"
    INTERFACE_LINK_LIBRARIES            "${Foo_LIBRARIES};bar;baz"
  )
endif()

And then I link with:

CMakeLists.txt

find_package(Foo REQUIRED)
add_executable(Test test.cxx)
target_link_libraries(Test PUBLIC Foo)

The problem is that it only links to Foo and not also with bar and baz (despite the INTERFACE_LINK_LIBRARIES property) so a lot of undefined references are generated.

This is the only problem because changing manually linkage to the following makes the executable to be correctly linked:

target_link_libraries(Test
  PUBLIC Foo
  PUBLIC bar
  PUBLIC baz
)

But since I should not be doing this manually, what am I doing wrong?

Edit: As suggested in comments, I've tried also with

target_link_libraries(Foo INTERFACE bar baz)

But the problem persists, when anything linking to Foo, it ignores the foo's link dependencies.

Maybe the Foo definition is wrong so cmake is ignoring its properties? Or should I declare also bar and baz as external for cmake to consider also them?

Also tried setting external library as:

add_library(Foo SHARED IMPORTED)

CMake version: 3.30.5


Solution

  • Thanks to @Tsyvarev's comments I found the problem and got the solution I share here in case someone finds a similar error:

    Problems:

    1. Foo_LIBRARY var was empty so the target library was not created correctly
    2. The imported target was not GLOBAL so the scope of the target library was only the current file
    3. It was linking to Foo (and not the other dependencies) just by chance because libFoo.so exists in the system, this is why I thought it was ignoring the properties but what was happening is that the whole target was not existant, treating Foo like a plain library and not a target.

    Finally the solution that works to import a library and set its dependencies is:

    FindFoo.cmake

    # Look for the necessary header
    find_path(Foo_INCLUDE_DIR NAMES foo.h)
    mark_as_advanced(Foo_INCLUDE_DIR)
    
    # Look for the necessary library
    find_library(Foo_LIBRARY NAMES foo)
    mark_as_advanced(Foo_LIBRARY)
    
    # Extract version information from the header file
    if(Foo_INCLUDE_DIR AND Foo_LIBRARY)
        set(Foo_FOUND TRUE)
        set(Foo_LIBRARIES bar baz)
    endif()
    
    include(FindPackageHandleStandardArgs)
    find_package_handle_standard_args(Foo
        REQUIRED_VARS Foo_INCLUDE_DIR Foo_LIBRARY Foo_LIBRARIES
    )
    
    # Create the imported target
    if(Foo_FOUND)
        set(Foo_INCLUDE_DIRS ${Foo_INCLUDE_DIR}) #It might have more than one
        if(NOT TARGET Foo)
            add_library(Foo UNKNOWN IMPORTED GLOBAL)
            set_target_properties(Foo PROPERTIES
                IMPORTED_LOCATION                   "${Foo_LIBRARY}"
                INTERFACE_INCLUDE_DIRECTORIES       "${Foo_INCLUDE_DIRS}"
                INTERFACE_LINK_LIBRARIES            "${Foo_LIBRARIES}"
            )
        endif()
    endif()
    

    So with this configuration since now the target is GLOBAL every other CMakeFiles.txt can target Foo library with its dependencies with just: target_link_libraries(TARGET Foo) (replace TARGET with the desired target) if find_package(Foo) has been executed somewhere.

    Note: There is no need to execute find_package(Foo) before or after final target, it will work with any call order.