cmake_minimum_required(VERSION 3.0) project(CompatibleInterface) include(GenerateExportHeader) set(CMAKE_INCLUDE_CURRENT_DIR ON) add_library(iface1 INTERFACE) set_property(TARGET iface1 APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL BOOL_PROP1 BOOL_PROP2 BOOL_PROP3 BOOL_PROP4 BOOL_PROP5 ) set_property(TARGET iface1 APPEND PROPERTY COMPATIBLE_INTERFACE_STRING STRING_PROP1 STRING_PROP2 STRING_PROP3 STRING_PROP4 ) set_property(TARGET iface1 APPEND PROPERTY COMPATIBLE_INTERFACE_NUMBER_MIN NUMBER_MIN_PROP1 NUMBER_MIN_PROP2 NUMBER_MIN_PROP3 NUMBER_MIN_PROP4 NUMBER_MIN_PROP5 NUMBER_MIN_PROP6 ) set_property(TARGET iface1 APPEND PROPERTY COMPATIBLE_INTERFACE_NUMBER_MAX NUMBER_MAX_PROP1 NUMBER_MAX_PROP2 NUMBER_MAX_PROP3 NUMBER_MAX_PROP4 ) set(CMAKE_DEBUG_TARGET_PROPERTIES BOOL_PROP1 BOOL_PROP2 BOOL_PROP3 BOOL_PROP4 BOOL_PROP5 STRING_PROP1 STRING_PROP2 STRING_PROP3 STRING_PROP4 NUMBER_MIN_PROP1 NUMBER_MIN_PROP2 NUMBER_MIN_PROP3 NUMBER_MIN_PROP4 NUMBER_MIN_PROP5 NUMBER_MIN_PROP6 NUMBER_MAX_PROP1 NUMBER_MAX_PROP2 NUMBER_MAX_PROP3 NUMBER_MAX_PROP4 ) set_property(TARGET iface1 PROPERTY INTERFACE_BOOL_PROP1 ON) set_property(TARGET iface1 PROPERTY INTERFACE_BOOL_PROP2 ON) set_property(TARGET iface1 PROPERTY INTERFACE_BOOL_PROP5 ON) set_property(TARGET iface1 PROPERTY INTERFACE_STRING_PROP1 prop1) set_property(TARGET iface1 PROPERTY INTERFACE_STRING_PROP2 prop2) set_property(TARGET iface1 PROPERTY INTERFACE_STRING_PROP4 prop4) set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MIN_PROP1 100) set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MIN_PROP2 200) set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MIN_PROP3 0x10) set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MIN_PROP4 0x10) set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MIN_PROP5 5) set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MIN_PROP6 6) set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MAX_PROP1 100) set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MAX_PROP2 200) set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MAX_PROP3 3) set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MAX_PROP4 4) add_executable(CompatibleInterface main.cpp) target_link_libraries(CompatibleInterface iface1) add_library(foo STATIC foo.cpp) add_library(bar SHARED bar.cpp) set_property(TARGET foo APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL SOMEPROP) set_property(TARGET foo PROPERTY INTERFACE_SOMEPROP ON) # Use LINK_ONLY to suppress usage requirements and allow the check to pass. set_property(TARGET bar PROPERTY INTERFACE_LINK_LIBRARIES $) set_property(TARGET CompatibleInterface PROPERTY SOMEPROP OFF) target_link_libraries(CompatibleInterface bar) set_property(TARGET CompatibleInterface PROPERTY BOOL_PROP2 ON) set_property(TARGET CompatibleInterface PROPERTY BOOL_PROP3 ON) set_property(TARGET CompatibleInterface PROPERTY STRING_PROP2 prop2) set_property(TARGET CompatibleInterface PROPERTY STRING_PROP3 prop3) set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP1 50) set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP2 250) set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP3 0xa) set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP4 0x1A) set_property(TARGET CompatibleInterface PROPERTY NUMBER_MAX_PROP1 50) set_property(TARGET CompatibleInterface PROPERTY NUMBER_MAX_PROP2 250) target_compile_definitions(CompatibleInterface PRIVATE $<$>:BOOL_PROP1> $<$>:BOOL_PROP2> $<$>:BOOL_PROP3> $<$,prop1>:STRING_PROP1> $<$,prop2>:STRING_PROP2> $<$,prop3>:STRING_PROP3> $<$,50>:NUMBER_MIN_PROP1=50> $<$,200>:NUMBER_MIN_PROP2=200> $<$,0xA>:NUMBER_MIN_PROP3=0xA> $<$,0x10>:NUMBER_MIN_PROP4=0x10> $<$,5>:NUMBER_MIN_PROP5=5> $<$,100>:NUMBER_MAX_PROP1=100> $<$,250>:NUMBER_MAX_PROP2=250> $<$,3>:NUMBER_MAX_PROP3=3> # Static libraries compute COMPATIBLE_INTERFACE_ properties transitively. $<$>:STATIC1_BOOL_PROP1> $<$,prop1>:STATIC1_STRING_PROP1> $<$,3>:STATIC1_NUMBER_MAX_PROP3> $<$,5>:STATIC1_NUMBER_MIN_PROP5> # Object libraries do not compute COMPATIBLE_INTERFACE_ properties transitively. $<$,>>:OBJECT1_BOOL_PROP1> $<$,>>:OBJECT1_STRING_PROP1> $<$,>>:OBJECT1_NUMBER_MAX_PROP3> $<$,>>:OBJECT1_NUMBER_MIN_PROP5> # Interface libraries do not compute COMPATIBLE_INTERFACE_ properties transitively. $<$,>>:IFACE3_BOOL_PROP1> $<$,>>:IFACE3_STRING_PROP1> $<$,>>:IFACE3_NUMBER_MAX_PROP3> $<$,>>:IFACE3_NUMBER_MIN_PROP5> # Static libraries compute COMPATIBLE_INTERFACE_ properties transitively. $<$>:STATIC1_BOOL_PROP5> $<$,prop4>:STATIC1_STRING_PROP4> $<$,6>:STATIC1_NUMBER_MIN_PROP6> $<$,4>:STATIC1_NUMBER_MAX_PROP4> # Object libraries do not compute COMPATIBLE_INTERFACE_ properties transitively, # but can have properties set on them. $<$>:OBJECT1_BOOL_PROP5> $<$,prop4>:OBJECT1_STRING_PROP4> $<$,7>:OBJECT1_NUMBER_MIN_PROP6> $<$,1>:OBJECT1_NUMBER_MAX_PROP4> # Interface libraries do not compute COMPATIBLE_INTERFACE_ properties transitively, # but can have properties set on them. $<$>:IFACE3_BOOL_PROP5> $<$,prop4>:IFACE3_STRING_PROP4> $<$,7>:IFACE3_NUMBER_MIN_PROP6> $<$,1>:IFACE3_NUMBER_MAX_PROP4> ) add_library(iface2 SHARED iface2.cpp) generate_export_header(iface2) set_property(TARGET iface2 APPEND PROPERTY COMPATIBLE_INTERFACE_STRING Iface2_PROP ) # For the LINK_LIBRARIES and related properties, we should not evaluate # properties defined only in the interface - they should be implicitly zero set_property(TARGET iface2 APPEND PROPERTY LINK_INTERFACE_LIBRARIES $<$>:nonexistent> ) target_link_libraries(CompatibleInterface iface2 $<$>:nonexistent> ) # Test that this does not segfault: target_compile_definitions(CompatibleInterface PRIVATE $<$>:SOME_DEFINE> ) # The COMPATIBLE_INTERFACE_* properties are only read from dependencies # in the interface. Populating it on the CompatibleInterface target does # not have any effect on the interpretation of the INTERFACE variants # in dependencies. set_property(TARGET iface1 PROPERTY INTERFACE_NON_RELEVANT_PROP ON ) set_property(TARGET iface2 PROPERTY INTERFACE_NON_RELEVANT_PROP ON ) set_property(TARGET CompatibleInterface APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL NON_RELEVANT_PROP ) add_library(static1 STATIC foo.cpp) set_property(TARGET static1 PROPERTY BOOL_PROP5 ON) set_property(TARGET static1 PROPERTY STRING_PROP4 prop4) set_property(TARGET static1 PROPERTY NUMBER_MIN_PROP6 7) set_property(TARGET static1 PROPERTY NUMBER_MAX_PROP4 1) target_link_libraries(static1 PUBLIC iface1) add_library(object1 OBJECT foo.cpp) set_property(TARGET object1 PROPERTY BOOL_PROP5 ON) set_property(TARGET object1 PROPERTY STRING_PROP4 prop4) set_property(TARGET object1 PROPERTY NUMBER_MIN_PROP6 7) set_property(TARGET object1 PROPERTY NUMBER_MAX_PROP4 1) target_link_libraries(object1 PUBLIC iface1) add_library(iface3 INTERFACE) set_property(TARGET iface3 PROPERTY BOOL_PROP5 ON) set_property(TARGET iface3 PROPERTY STRING_PROP4 prop4) set_property(TARGET iface3 PROPERTY NUMBER_MIN_PROP6 7) set_property(TARGET iface3 PROPERTY NUMBER_MAX_PROP4 1) target_link_libraries(iface3 INTERFACE iface1) # Test COMPATIBLE_INTERFACE_* property evaluation outside of usage requirements. add_custom_target(check ALL VERBATIM COMMAND CompatibleInterface # expect actual "1" "$" "prop1" "$" "3" "$" "5" "$" "1" "$" "prop1" "$" "3" "$" "5" "$" "" "$" "" "$" "" "$" "" "$" "" "$" "" "$" "" "$" "" "$" "ON" "$" "prop4" "$" "6" "$" "4" "$" "ON" "$" "prop4" "$" "7" "$" "1" "$" "ON" "$" "prop4" "$" "7" "$" "1" "$" )