How to idiomatically add include path flags inside add_custom_command?

This is pattern I’ve had to use multiple times and I keep thinking that the “correct” way to do it should be something like:

add_custom_command(
  # ...
  COMMAND ${CMAKE_COMMAND} -E env my_compiler some_file "-I$<JOIN:${MY_INCLUDE_DIRS}, -I>"
  # ...
)

But this does not work because CMake escapes whitespace between flags. The obvious alternative would be getting rid of the quotes around the generator expression but that causes it to not be expanded at all in build.ninja (or similar)!

Is there really no way to achieve this without “manual” string operations?

There is an example showing precisely this in the genex documentation. The example builds it up in several steps, but here are the two final forms it offers:

Using $<JOIN>:

# The $<BOOL:...> check prevents adding anything if the property is empty,
# assuming the property value cannot be one of CMake's false constants.
set(prop "$<TARGET_PROPERTY:tgt,INCLUDE_DIRECTORIES>")
add_custom_target(run_some_tool
  COMMAND some_tool "$<$<BOOL:${prop}>:-I$<JOIN:${prop},;-I>>"
  COMMAND_EXPAND_LISTS
  VERBATIM
)

Using $<LIST>:

add_custom_target(run_some_tool
  COMMAND some_tool "$<LIST:TRANSFORM,$<TARGET_PROPERTY:tgt,INCLUDE_DIRECTORIES>,PREPEND,-I>"
  COMMAND_EXPAND_LISTS
  VERBATIM
)

Thanks @Petr! With the linked section I think I’ve now finally understood this, I should probably read the whole page…