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

**URL:** https://discourse.cmake.org/t/bug-failed-to-print-elements-of-a-list-one-by-one/4036
**Category:** Code
**Created:** [September 4, 2021, 8:34am UTC](https://discourse.cmake.org/t/bug-failed-to-print-elements-of-a-list-one-by-one/4036 "2021-09-04T08:34:45Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![Ronald](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/r/ea666f/32.png) [@Ronald](https://discourse.cmake.org/u/Ronald)
#### Post date: [September 4, 2021, 8:34am UTC](https://discourse.cmake.org/t/bug-failed-to-print-elements-of-a-list-one-by-one/4036/1 "2021-09-04T08:34:45Z")

</div>

## Code

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

```

## Expected Output

```shell
/path/a
/path/b
/path/c

```

## Practical Output

```shell
/path/a;/path/b;/path/c

```

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [September 4, 2021, 5:13pm UTC](https://discourse.cmake.org/t/bug-failed-to-print-elements-of-a-list-one-by-one/4036/2 "2021-09-04T17:13:50Z")

</div>

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

```auto
$<TARGET_PROPERTY:value_of_target_name_variable,INCLUDE_DIRECTORIES>

```

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

---

<div class="post-metadata">

### Author: ![Ronald](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/r/ea666f/32.png) [@Ronald](https://discourse.cmake.org/u/Ronald)
#### Post date: [September 4, 2021, 5:38pm UTC](https://discourse.cmake.org/t/bug-failed-to-print-elements-of-a-list-one-by-one/4036/3 "2021-09-04T17:38:35Z")

</div>

use `file(GENERATE ...)`

```cmake
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() 

```

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [September 4, 2021, 7:40pm UTC](https://discourse.cmake.org/t/bug-failed-to-print-elements-of-a-list-one-by-one/4036/4 "2021-09-04T19:40:39Z")

</div>

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`:

```cmake
# 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.

---

<div class="post-metadata">

### Author: ![Ronald](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/r/ea666f/32.png) [@Ronald](https://discourse.cmake.org/u/Ronald)
#### Post date: [September 5, 2021, 3:04am UTC](https://discourse.cmake.org/t/bug-failed-to-print-elements-of-a-list-one-by-one/4036/5 "2021-09-05T03:04:11Z")

</div>

> [@ben.boeckel](#):
>
> 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.

Yes  
Thanks very much

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

```cmake
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() 

```
