cmakepropertiestarget

why target properties are not populated from the properties of dependancies


CMake documentation states the following:

Usage requirements are propagated by reading the INTERFACE_ variants of target properties from dependencies and appending the values to the non-INTERFACE_ variants of the operand.

This seems to be wrong. Please see the minimal example below:

cmake_minimum_required(VERSION 3.31.3)

project(main)

add_library(lib OBJECT lib.cpp)
set_property(TARGET lib PROPERTY INTERFACE_COMPILE_DEFINITIONS "DEFS")

add_executable(main main.cpp)

target_link_libraries(main PUBLIC lib)


function(print_property)
    set(oneValueArgs TARGET PROPERTY)
    cmake_parse_arguments(PARSE_ARGV 0 arg "" "${oneValueArgs}" "")
    set(PROP "NONE")
    get_property(PROP TARGET ${arg_TARGET} PROPERTY ${arg_PROPERTY})
    message("${PROP}")
endfunction()

print_property(TARGET lib  PROPERTY INTERFACE_COMPILE_DEFINITIONS)
print_property(TARGET lib  PROPERTY COMPILE_DEFINITIONS)
print_property(TARGET main PROPERTY INTERFACE_COMPILE_DEFINITIONS)
print_property(TARGET main PROPERTY COMPILE_DEFINITIONS)

Upon configuration stage, only the first message prints something (the DEFS string), the rest of them prints nothing.

Question: shouldn't the COMPILE_DEFINITIONS of main be populated with DEFS, according to the quote in the beginning of the question. The question is kinda relevant for INTERFACE_COMPILE_DEFINITIONS of the main too.

Building stage goes fine - main.o is being built with -DDEFS, as expected.


Solution

  • Propagation of properties occurs at the very end of configuration process, at generation stage. With command get_target_property you cannot check the results of propagation - this command extracts value of the property immediately, when the propagation hasn't been performed yet. Instead, refer to the property via generator expression

    $<TARGET_PROPERTY:main,COMPILE_DEFINITIONS>
    

    and use one of the method for output its value. E.g.

    add_custom_target(mytarget ALL
      COMMAND ${CMAKE_COMMAND} -E echo 
      "Compile definitions for main: $<TARGET_PROPERTY:main,COMPILE_DEFINITIONS>"
    )
    

    (the output from custom target will be created when you build the project).


    The funny thing is that even the linkage in target_link_libraries call is deferred until the end of the configuration process. E.g. in that call you may use library targets, created after it:

    add_executable(main main.cpp)
    # Link with the library target which is not created yet.
    target_link_libraries(main PUBLIC lib)
    # Create the library target now.
    add_library(lib OBJECT lib.cpp)
    # And assign a property, which will be finally propagated to the executable.
    set_property(TARGET lib PROPERTY INTERFACE_COMPILE_DEFINITIONS "DEFS")