# creating a macro that dynamically updates a custom target

**URL:** https://discourse.cmake.org/t/creating-a-macro-that-dynamically-updates-a-custom-target/8067
**Category:** Code
**Created:** [May 6, 2023, 12:33pm UTC](https://discourse.cmake.org/t/creating-a-macro-that-dynamically-updates-a-custom-target/8067 "2023-05-06T12:33:46Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![Brian](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/97f17d/32.png) [@Brian](https://discourse.cmake.org/u/Brian)
#### Post date: [May 6, 2023, 12:33pm UTC](https://discourse.cmake.org/t/creating-a-macro-that-dynamically-updates-a-custom-target/8067/1 "2023-05-06T12:33:46Z")

</div>

Hi All,

I’m trying to write a macro that creates a custom target using the source and headers from other targets.

from the build folder I would like to run for example

```auto
cmake ..
cmake --build . --target clang-format-dry-run

```

Add scattered through various folders I would like to add

```auto
add_library(<my target>) or add_executable(<my target>)
...
etc
...

# call macro 
ClangFormatTarget(<my target>)

```

This is what I currently have for the macro. I’m currently stuck trying to use $\<TARGET\_PROPERTY\>

```auto
macro(ClangFormatTarget TARGET)
    if( NOT (TARGET clang-format-dry-run))
        add_custom_target(clang-format-dry-run
            COMMAND ${CLANG_FORMAT_EXE} --dry-run --verbose -style=file --Werror $<TARGET_PROPERTY:clang-format-dry-run,SOURCES>
        )
    endif()

# get the source files from the target
    get_target_property(target_dir ${TARGET} SOURCE_DIR)
    get_target_property(target_source_files ${TARGET} SOURCES)
    get_target_property(target_header_files ${TARGET} PUBLIC_HEADER)

    if(target_source_files)
        foreach(file IN LISTS target_source_files)
            list(APPEND files_to_format ${target_dir}/${file})
        endforeach()
    endif()

    if(target_header_files)
        foreach(file IN LISTS target_header_files)
            list(APPEND files_to_format ${target_dir}/${file})
        endforeach()
    endif()

    foreach(file IN LISTS files_to_format)
        message(${TARGET} " file to format " ${file})
    endforeach()

# Append the new files to the existing target
    target_sources(clang-format-dry-run PRIVATE ${files_to_format})
endmacro()

```

The command it generates is as follows

```auto
/usr/bin/clang-format --dry-run --verbose -style=file --Werror /home/brian/code/SimpleLibrary/src/simple_library.cpp;/home/brian/code/SimpleLibrary/src/include/SimpleLibrary/simple_library.h;/home/brian/code/SimpleLibrary/tests/simple_library_tests.cpp;/home/brian/code/SimpleLibrary/build/src/CMakeFiles/clang-format-dry-run;/home/brian/code/SimpleLibrary/build/src/CMakeFiles/clang-format-dry-run.rule

```

The issue I’m having is that

1. I need the output of the generator expression to be a string of files separated with spaces instead of semicolons and
2. Why is it creating the last two list elements?

Cheers

Brian

---

<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: [May 8, 2023, 6:34pm UTC](https://discourse.cmake.org/t/creating-a-macro-that-dynamically-updates-a-custom-target/8067/2 "2023-05-08T18:34:04Z")

</div>

> [@Brian](#):
>
> I need the output of the generator expression to be a string of files separated with spaces instead of semicolons

You can use the `$<JOIN>` genex for that.

> [@Brian](#):
>
> Why is it creating the last two list elements?

The last two files are part of CMake’s internal dependency tracking for the generator. This looks like one of Makefiles generators due to that.

---

<div class="post-metadata">

### Author: ![Brian](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/97f17d/32.png) [@Brian](https://discourse.cmake.org/u/Brian)
#### Post date: [May 27, 2023, 8:16am UTC](https://discourse.cmake.org/t/creating-a-macro-that-dynamically-updates-a-custom-target/8067/3 "2023-05-27T08:16:10Z")

</div>

Thanks Ben,

To fix the problems I was having I first creating a new property to store the list of files rather than using the built in `SOURCES` property, this removed the extra list items.

Then I used the `COMMAND_EXPAND_LISTS` option in `add_custom_target` which fixed issues with semicolons and escaped whitespace characters.

I couldn’t figure out how to append to an existing property so I had to first get the current list and then append the new.

```auto
macro(ClangFormatTarget TARGET)
    if( NOT (TARGET clang-format-dry-run))
        add_custom_target(clang-format-dry-run
            COMMAND ${CLANG_FORMAT_EXE} --dry-run --verbose -style=file --Werror $<TARGET_PROPERTY:clang-format-dry-run,FILES_TO_CLANG_FORMAT>
            COMMAND_EXPAND_LISTS
        )
    endif()

    get_target_property(target_dir ${TARGET} SOURCE_DIR)
    get_target_property(target_source_files ${TARGET} SOURCES)
    get_target_property(target_header_files ${TARGET} PUBLIC_HEADER)

    if(target_source_files)
        foreach(file IN LISTS target_source_files)
            list(APPEND files_to_format ${target_dir}/${file})
        endforeach()
    endif()

    if(target_header_files)
        foreach(file IN LISTS target_header_files)
            list(APPEND files_to_format ${target_dir}/${file})
        endforeach()
    endif()

    foreach(file IN LISTS files_to_format)
        message(${TARGET} " file to format " ${file})
    endforeach()

    get_target_property(current_files clang-format-dry-run FILES_TO_CLANG_FORMAT)

    if(NOT current_files)
        set(current_files "")
    endif()

    foreach(file IN LISTS current_files)
        list(APPEND files_to_format ${file})
    endforeach()

    set_target_properties(clang-format-dry-run
        PROPERTIES
            FILES_TO_CLANG_FORMAT "${files_to_format}"
    )
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: [May 29, 2023, 1:56pm UTC](https://discourse.cmake.org/t/creating-a-macro-that-dynamically-updates-a-custom-target/8067/4 "2023-05-29T13:56:23Z")

</div>

> [@Brian](#):
>
> I couldn’t figure out how to append to an existing property so I had to first get the current list and then append the new.

`set_property(TARGET … APPEND)` is what you’re looking for.
