3.7 KiB
[2023] cmake handling of header-only dependencies
#
#
#
#
#
#
Problem
Update
My original investigation 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).
Setup
- 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.
Problem
- 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
Workaround
-
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()