Request for Enhancement: instantiating add_custom_commands() for each item in a generator expression that evaluates to a list.
In my comment on here: #24893 (comment 1362552) , where I copy-paste some CMake script code out of my work CMake scripts, I demonstrate a use-case for the ability to evaluate the equivalent of
foreach(ITEM $<GENERATOR_EXPRESSION_EVALUATING_TO_LIST>)
add_custom_command(blahblah uses ${ITEM} in one or more parameters)
endforeach()
As far as I can tell this is a capability that cmake currenty lacks. The workaround being to construct a script that takes the generator expression's result as an argument, then calling that script.
This has a few downsides:
- If the output, byproduct, or dependencies of the script are derived from the items of the generator expression, then the logic that the script implements has to be duplicated also in the cmake code, which may not actually be possible, in order to allow cmake to understand the dependency relationships.
- In most cases, the items in the list are not simultaneously dependent on each dependency, nor do they all act as dependencies for all outputs, which means if any of the dependencies become out dated ALL of the items in the list must be re-run through the custom command.
- The actual underlying build system doesn't know that the script is actually just doing things in a forloop, so there's a loss of parallelism, and a loss of understanding of how many build jobs remain.
We have the ability to get properties of targets, e.g. INCLUDE_DIRECTORIES
, or SOURCES
, using e.g. $<TARGET_PROPERTY:tgt,INCLUDE_DIRECTORIES>
but the result of this query can only be used as a blob (e.g. one script passed all the items at once). You can't, for example, say
function(do_the_helpful_thing TARGETNAME)
add_custom_command(GENERATER_EXPRESSION_SUBSTITUTE $<TARGET_PROPERTY:${TARGETNAME},SOURCES>
DEPENDS $$$GENERATER_EXPRESSION_SUBSTITUTE
OUTPUT $$$GENERATER_EXPRESSION_SUBSTITUTE_outputfile
COMMAND do_something_helpful $$$GENERATER_EXPRESSION_SUBSTITUTE $$$GENERATER_EXPRESSION_SUBSTITUTE_outputfile)
add_custom_target(do_the_helpful_thing_on_${TARGETNAME} DEPENDS $<TARGET_PROPERTY:${TARGETNAME},SOURCES>)
endfunction()
This means that in the generic sense, it's impossible to make a wrapper around add_executable, and add_library, and so on, which will set up a collection of supplemental targets and commands based on the sources and other properties of a target after configuration is finished. Instead, you must set up your targets, and then wait until the very end of the configuration (e.g. the bottom of your top-level cmake script) to do any setup that involves generically handling the items held in properties of the target. If you're in control of your target from start-to-stop, then this is possible (still not elegant, but possible). But if you're authoring a library that you expect others to consume by adding it to their own cmake build, it's impossible to guarantee. The cmake project that includes your library might, e.g.
- add/remove source files to/from your target
- add / remove compile options/defines
- add additional include directories
- change unity build settings
- change the precompiled header settings
so on and so forth.
As an add-on item:
It'd be nice to have the ability to skip the generation (as in, it's not even in the resulting ninja/makefile) of an add_custom_command
based on whether or not a generator expression evaluates to true/false, or is an empty list. Like the above, this allows for generic behavior to be defined in a wrapper around add_executable / add_library / add_custom_target, but then defer the evaluation to the end of configuration