[7oct2023] cmake header-only dependencies
Table of Contents
1. Update
My original investigation (below) mistaken.
It turns out I didn't understand that cmake error from target_link_libraries():
INTERFACE library can only be used with the INTERFACE keyword of target_link_libraries
applies to the depended-on library (3rd argument), not the depending library (1st argument).
Mistaken investigation below for posterity :)
2. Setup (before Update)
- NOTE: also asked on stack overflow here
- cmake version 3.25.3
Must introduce a header-only library like this:
add_library(foo INTERFACE)(instead of
add_library(foo SHARED)oradd_library(foo STATIC))Must specify include directories for a header-only library like this:
target_include_directories( foo INTERFACE $<INSTALL_INTERFACE:path/to/include> $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/path/to/include>)
cmake enforces this explicitly; gives error
target_include_directories may only set INTERFACE properties on INTERFACE targets
Must specify dependency on a header-only library like this:
target_link_libraries(bar INTERFACE foo))(instead of
target_link_libraries(bar PUBLIC foo))cmake enforces this explicitly; gives error
INTERFACE library can only be used with the INTERFACE keyword of target_link_libraries
Expected behavior: this is sufficient for compilation of
barto tell compiler about include paths forfoo:gcc -Ipath/to/foo bar.cpp
This expectation is satisfied for regular non-INTERFACE libraries.
3. Problem (before Update)
- compilation fails to supply include paths for depended-on
foowhen compiling depending-onbar, ifbaris a regular library - predicted cause:
- for an INTERFACE library, cmake uses property
INTERFACE_INCLUDE_DIRECTORIES; it does not populateINCLUDE_DIRECTORIES. target_link_librarieswhen applied to aSTATICorSHAREDtarget, picks up theINCLUDE_DIRECTORIESproperty for the depended-on target, while ignoring theINTERFACE_INCLUDE_DIRECTORIESproperty.
- for an INTERFACE library, cmake uses property
4. Workaround (before Update)
when depending on a header-only library, explictly incorporate depended-on
INTERFACE_INCLUDE_DIRECTORIEStoINCLUDE_DIRECTORIES:macro(dependency_headeronly target dep) target_link_libraries(${target} INTERFACE ${dep}) get_target_property(dependency_headeronly__tmp ${dep} INTERFACE_INCLUDE_DIRECTORIES) set_property( TARGET ${target} APPEND PROPERTY INCLUDE_DIRECTORIES ${dependency_headeronly__tmp}) endmacro()