How to create a custom target that only runs a command for a subset of configurations?

CMake 3.20 enables using generator expressions in the add_custom_command(OUTPUT) argument.

I am now trying to create a custom command that only runs a command for a subset of the available CMAKE_CONFIGURATION_TYPES. After a lot of trial and error I came up with an example that works for a single configuration:


# Works with warning when compiling in non-Debug
add_custom_command(
	COMMAND $<$<CONFIG:Debug>:${CMAKE_COMMAND}> $<$<CONFIG:Debug>:-E> $<$<CONFIG:Debug>:touch> $<$<CONFIG:Debug>:${CMAKE_BINARY_DIR}/A_Stamp_$<CONFIG>.stamp> 
	OUTPUT $<$<CONFIG:Debug>:${CMAKE_BINARY_DIR}/A_Stamp_$<CONFIG>.stamp>
)

add_custom_target(
	testConfigCommands
	DEPENDS $<$<CONFIG:Debug>:${CMAKE_BINARY_DIR}/A_Stamp_$<CONFIG>.stamp> 
)

I failed to create an example that works for multiple configurations. I tried something like:


add_custom_command(
	COMMAND $<$<IN_LIST:$<CONFIG>,Debug;Release>:${CMAKE_COMMAND}> $<$<IN_LIST:$<CONFIG>,Debug;Release>:-E> $<$<IN_LIST:$<CONFIG>,Debug;Release>:touch> $<$<IN_LIST:$<CONFIG>,Debug;Release>:${CMAKE_BINARY_DIR}/A_Stamp_$<CONFIG>.stamp>
	OUTPUT $<$<IN_LIST:$<CONFIG>,Debug;Release>:${CMAKE_BINARY_DIR}/A_Stamp_$<CONFIG>.stamp>
)

add_custom_target(
	testConfigCommands
	DEPENDS $<$<IN_LIST:$<CONFIG>,Debug;Release>:${CMAKE_BINARY_DIR}/A_Stamp_$<CONFIG>.stamp>
)

but this will fail with the error:

OUTPUT containing a “<” is not allowed.

I tried escaping the semicolon and other stuff but I keep hitting various errors that I have trouble deciphering. So in my desparation I came here and ask if anybody can post a similar example that creates the stamp-file only when selecting the Release or Debug configuration when using the Visual Studio generator. If that would work without a waring when building the target for a configruation that is not Release or Debug it would be perfect.

It would be even better if the target was only available for a subset of configurations.

First, generator expressions must be specified between quotes to avoid misinterpretation.
Second, genex $<CONFIG:> can take multiple configurations as argument.

So, a simplified command:

add_custom_command(COMMAND "$<$<CONFIG:Debug,Release>:${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/A_Stamp_$<CONFIG>.stamp>"
OUTPUT "$<$<CONFIG:Debug,Release>:${CMAKE_BINARY_DIR}/A_Stamp_$<CONFIG>.stamp>")
1 Like

Wow that was quick :smiley:. Thank you very much! I think my major error was to use a semicolon instead of a comma in the configuration lists.

First I used:


add_custom_command(
	COMMAND $<$<CONFIG:Debug,Release>:${CMAKE_COMMAND}> $<$<CONFIG:Debug,Release>:-E> $<$<CONFIG:Debug,Release>:touch> $<$<CONFIG:Debug,Release>:${CMAKE_BINARY_DIR}/A_Stamp_$<CONFIG>.stamp> 
	OUTPUT $<$<CONFIG:Debug,Release>:${CMAKE_BINARY_DIR}/A_Stamp_$<CONFIG>.stamp>
)

which worked. However if I use your example I get an syntax error when the command is run. I suspect that it has something to do with the separators in the path of the stamp file. I am not sure though.

You are right.
Unfortunately, add_custom_command() command has a subtle difference, from other commands, in how arguments are interpreted. So you have to specify each element of the COMMAND args with its own genex:

add_custom_command(COMMAND "$<$<CONFIG:Debug,Release>:${CMAKE_COMMAND}>" "$<$<CONFIG:Debug,Release>:-E>" "$<$<CONFIG:Debug,Release>:touch>" "$<$<CONFIG:Debug,Release>:${CMAKE_BINARY_DIR}/A_Stamp_$<CONFIG>.stamp>"
OUTPUT "$<$<CONFIG:Debug,Release>:${CMAKE_BINARY_DIR}/A_Stamp_$<CONFIG>.stamp>")
1 Like