Reputation: 155
I am currently developing a software package, for which I'd like to provide the cmake package support (so users can find it with find_package(...)
). The Problem is, the package is found but FOO_INCLUDE_DIR
and FOO_LIBRARIES
is empty.
Within my package I have several modules, each with a CMakeLists file which installs the respective library and headers with:
install(TARGETS ${LIBRARY_NAME} EXPORT FooTargets
RUNTIME DESTINATION ${Foo_RUNTIME_INSTALL_DIR}
LIBRARY DESTINATION ${Foo_LIBRARY_INSTALL_DIR}
ARCHIVE DESTINATION ${Foo_ARCHIVE_INSTALL_DIR}
FRAMEWORK DESTINATION ${Foo_FRAMEWORK_INSTALL_DIR})
# Headers
install(
DIRECTORY include/${LIBRARY_NAME}
DESTINATION include/${PROJECT_NAME}
FILES_MATCHING
PATTERN "*.h"
PATTERN "*.hpp"
)
The headers for the library are included with target_include_directories like this:
target_include_directories(${LIBRARY_NAME} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> # for headers when building
$<INSTALL_INTERFACE:${Foo_INC_INSTALL_DIR}> # for client in install mode
)
I checked the folders and all libraries and headers are correctly installed. In my toplevel CMakeLists I export my targets with:
install(
EXPORT FooTargets
DESTINATION ${Foo_CMAKE_CONFIG_INSTALL_DIR}
FILE FooConfig.cmake
)
The config is where I assume it to be (usr/local/lib/cmake/Foo
). So everything seems to be correct. When I look into my FooConfig.cmake
it says:
# Create imported target realm_densifier_base
add_library(FooLib1 SHARED IMPORTED)
set_target_properties(FooLib1 PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "/usr/local/include/Foo"
INTERFACE_LINK_LIBRARIES "...several libraries..."
)
...which is absolutely correct and exactly what I expected. What part of the puzzle is missing? Is INTERFACE_INCLUDE_DIRECTORIES
and INTERFACE_LINK_LIBRARIES
not the correct flag to be set?
Thanks for the help and best regards,
Alex
Edit:
@Guillaume Racicot already cleared most things up, I only knew the "non target" way of adding headers to my project, that was with include_directories(Foo_INCLUDE_DIRS). However, in the target-world linking against my library Foo was enough. Another thing was that I messed up some directories in the target_include_directories(...)
command, so directories were wrong and therefore could not be found in my other project. Thanks for the help!
Upvotes: 1
Views: 1118
Reputation: 41760
Why would FOO_INCLUDE_DIR
or FOO_LIBRARIES
be set? This may be how old find modules worked, but not how config files work. Even newer find modules expose targets instead of directory variables.
When generating an XYZConfig.cmake
file, informations about targets will be exported, not informations on the directory.
With such exportation:
install(
EXPORT FooTargets
NAMESPACE Foo::
DESTINATION ${Foo_CMAKE_CONFIG_INSTALL_DIR}
FILE FooConfig.cmake
)
You would expect users of the package to use it like so:
find_package(Foo REQUIRED)
# or PUBLIC ------v
target_link_libraries(bar PRIVATE Foo::FooLib1)
If your package has multiple targets in the export set, then you can link to both or only one
target_link_libraries(bar PRIVATE Foo::FooLib1 Foo::FooLib2)
target_link_libraries(baz PUBLIC Foo::FooLib2) # link to lib2 only
When you link to an exported target like Foo::FooLib1
, its public interface will be transitively transmitted to its user. In the example above, bar
will inherit properties from the linked target.
So the INTERFACE_INCLUDE_DIRECTORIES
of Foo::FooLib1
and Foo::FooLib2
will be appended to bar
's INCLUDE_DIRECTORIES
. Same for LINK_LIBRARIES
.
For baz
, not only its INCLUDE_DIRECTORIES
will contain Foo::FooLib2
entries, but also its own INTERFACE_INCLUDE_DIRECTORIES
will transitively transmit the usage requirements of Foo::FooLib2
Upvotes: 2