[BUG] Failed to print elements of a list one by one

Code

set(INCLUDE_DIRS $<TARGET_PROPERTY:${TARGET_NAME},INCLUDE_DIRECTORIES>)
foreach(PATH ${INCLUDE_DIRS})
    string(CONCAT OUT_TMP ${OUT_TMP} "${PATH}\n")
endforeach()

Expected Output

/path/a
/path/b
/path/c

Practical Output

/path/a;/path/b;/path/c

I don’t see how this works at all. I would expect this output:

$<TARGET_PROPERTY:value_of_target_name_variable,INCLUDE_DIRECTORIES>

Can you provide a full script which reproduces the behavior you’re describing?

use file(GENERATE ...)

macro(dump_target_includes TARGET_NAME)
    set(OUT_TMP "====dump_target_includes begin (${TARGET_NAME})====")

    set(INCLUDE_DIRS $<TARGET_PROPERTY:${TARGET_NAME},INCLUDE_DIRECTORIES>)
    set(INTERFACE_INCLUDE_DIRS $<TARGET_PROPERTY:${TARGET_NAME},INTERFACE_INCLUDE_DIRECTORIES>)

    string(CONCAT OUT_TMP ${OUT_TMP} "\n\n----INCLUDE_DIRECTORIES----")
    foreach(PATH ${INCLUDE_DIRS})
        string(CONCAT OUT_TMP ${OUT_TMP} "\n${PATH}")
    endforeach()

    string(CONCAT OUT_TMP ${OUT_TMP} "\n\n----INTERFACE_INCLUDE_DIRECTORIES----")
    foreach(PATH ${INTERFACE_INCLUDE_DIRS})
        string(CONCAT OUT_TMP ${OUT_TMP} "\n${PATH}")
    endforeach()

    string(CONCAT OUT_TMP ${OUT_TMP} "\n\n====dump_target_includes end (${TARGET_NAME})====")

    file(GENERATE OUTPUT test_debug_genex.log
                  CONTENT ${OUT_TMP})
endmacro() 

This is because you’re confusing generate-time logic with configure-time logic. Here’s a breakdown of what’s happening for a hypothetical target named foo:

# Plain message
set(OUT_TMP "====dump_target_includes begin (foo)====")

# Plain variable settings to strings. They *use* genex syntax, but they're just strings at this point.
set(INCLUDE_DIRS $<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>)
set(INTERFACE_INCLUDE_DIRS $<TARGET_PROPERTY:foo,INTERFACE_INCLUDE_DIRECTORIES>)

# You really just want this instead of what you have because otherwise you'll end up duplicating `OUT_TMP` content quadratically:
string(CONCAT OUT_TMP "\n\n----INCLUDE_DIRECTORIES----")

# Loop over `INCLUDE_DIRS` as a list. This list has one element, `$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>`
foreach(PATH ${INCLUDE_DIRS})
    # Appends `\n$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>` to `OUT_TMP`
    string(CONCAT OUT_TMP "\n${PATH}")
endforeach()

# Same as above
string(CONCAT OUT_TMP "\n\n----INTERFACE_INCLUDE_DIRECTORIES----")
foreach(PATH ${INTERFACE_INCLUDE_DIRS})
    string(CONCAT OUT_TMP "\n${PATH}")
endforeach()

string(CONCAT OUT_TMP "\n\n====dump_target_includes end (foo)====")

# Here, `OUT_TMP` contains this content:
[==[
====dump_target_includes begin (foo)====

----INCLUDE_DIRECTORIES----
$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>

----INTERFACE_INCLUDE_DIRECTORIES----
$<TARGET_PROPERTY:foo,INTERFACE_INCLUDE_DIRECTORIES>

====dump_target_includes end (foo)====
]==]
file(GENERATE OUTPUT test_debug_genex.log
     CONTENT ${OUT_TMP})

This final result of OUT_TMP doesn’t have anything about the configure-time foreach loops in them because the value of $<TARGET_PROPERTY> is not known at this time. What you want is to use $<JOIN:\n,$<TARGET_PROPERTY:…>> to intersperse \n characters in between each element.

1 Like

Yes
Thanks very much

BTW it should be $<JOIN:$<TARGET_PROPERTY:…>,\n>

macro(dump_target_includes TARGET_NAME)
    set(OUT_TMP "====dump_target_includes begin (${TARGET_NAME})====\n\n")

    set(INCLUDE_DIRS $<TARGET_PROPERTY:${TARGET_NAME},INCLUDE_DIRECTORIES>)
    set(INTERFACE_INCLUDE_DIRS $<TARGET_PROPERTY:${TARGET_NAME},INTERFACE_INCLUDE_DIRECTORIES>)

    string(CONCAT OUT_TMP ${OUT_TMP} "----INCLUDE_DIRECTORIES----\n")

    string(CONCAT OUT_TMP ${OUT_TMP} $<JOIN:$<TARGET_PROPERTY:${TARGET_NAME},INCLUDE_DIRECTORIES>,\n>\n\n)

    string(CONCAT OUT_TMP ${OUT_TMP} "----INTERFACE_INCLUDE_DIRECTORIES----\n")

    string(CONCAT OUT_TMP ${OUT_TMP} $<JOIN:$<TARGET_PROPERTY:${TARGET_NAME},INTERFACE_INCLUDE_DIRECTORIES>,\n>\n\n)

    string(CONCAT OUT_TMP ${OUT_TMP} "====dump_target_includes end (${TARGET_NAME})====")

    file(GENERATE OUTPUT test_debug_genex.log
                  CONTENT ${OUT_TMP})
endmacro()