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
Thanks to @Tsyvarev's comments I found the problem and got the solution I share here in case someone finds a similar error:
Problems:
Foo_LIBRARY
var was empty so the target library was not created correctlyGLOBAL
so the scope of the target library was only the current fileFinally 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.