I have a build which uses the unifdef
tool and hence is dependent on having the compile definitions for built targets available as input to this. Now that I was adding the compile definitions using genexes I’d like to learn a method to retrieve them and have the genexes evaluated. get_target_property
gives me them unevaluated.
Is there a canonical way (without reverting to just store all definitions in a list instead)?
By definition, generator expressions (“genexes”) are evaluated at generate time (hence their name), so you cannot access their evaluated value at configure time — it may not even be fully defined yet. You can of course send unevaluated genexes into a context which will eventually evaluate them, such as using them in the arguments of a command run via add_custom_command()
. Perhaps something like this:
add_custom_command(
OUTPUT result.ext
COMMAND some.exe --defines $<TARGET_PROPERTY:MyTarget,COMPILE_DEFINITIONS>
)
For more complex situations, you may also want to look at the genexes $<GENEX_EVAL>
and $<TARGET_GENEX_EVAL>
.
Thanks, I kind of managed to get it to work for unifdef
(which can accept a newline separated file with defines) with the following beauty:
file(GENERATE OUTPUT defs.txt CONTENT $<LIST:JOIN,$<LIST:TRANSFORM,$<TARGET_PROPERTY:my_tgt,INTERFACE_COMPILE_DEFINITIONS>,PREPEND,-D>,\n>)
But then I realized I need to pass on the definitions to Doxygen as well, which needs a space separated string. So I wonder if there is a way to have this stored in a variable instead of written to disk (and then read up again, and that is when it’s starting to get hard to justify)?
Variables don’t really exist at generate time, so you can’t get the value in a variable. Instead, a $<SPACE>
genex (which doesn’t exist yet, but an issue would help) may be useful here as the join string.
I stashed this problem away for a year but now I’m back to have my bloodpressure tested again.
So I now tried to just read the compile definitions up from the compile_commands.json
file. But then that file has not been created yet when I need it. I don’t know if it’s feasible to create a whole lot of dependencies on its existence when I should’t “have to”. I.e. I know the compile definitions at config time and so should cmake imo.
It feels like there could be a usecase for a config time GENEX. I.e the ones I’m setting now are all dependent on values known at this time (option()
) and therefore I would like to be able to read them back at this time too.
And then another workaround I thought about was just storing the definitions in a list. But when creating it I really missed a ternary operator.
Eg instead of the nasty repetition of
if(WITH_SOME_FEATURE)
list(APPEND mydefs SOME_FEATURE=1
else()
list(APPEND mydefs SOME_FEATURE=0
endif()
… one could do:
list(APPEND mydefs SOME_FEATURE=(WITH_SOME_FEATURE?1:0)
No dice eh?
After seeing you creating complicated GenExes with lists, I’m not sure if you have overseen the most simple ones: SOME_FEATURE=$<BOOL:${WITH_SOME_FEATURE}>
Nah, the genexes are not evaluated until build time so I get SOME_FEATURE=$<BOOL:OFF>;
in the list.