Generating a proprietary version list

Hi,

in a cmake project several sub directories have project()s with different proprietary version numbers. We are using a macro called by each affected CMakefile.txt like ARTEFACT_VERSION(“NAME” “1.2.3”). This writes a file artvers.txt with all the name=version entries by appending. To avoid duplicates on next run, there is a heuristic deleting the file first. It is important to see that currently the main project files that use this (indirectly) by add_subdirectory() do not handle any of that. Just by using at least one sub project that has a artvers.txt entry, the file currently gets created automatically.
It works, however, I cannot sort the entries, duplicate names lead to bad error behavior and the deletion mechanism does not feel to good.

But how to do it better/right?

I’m re-implementing the macro to not directly write to the file, but actually add to a global property (list). With a second marco the list is sorted and written by file(GENRATE). This works fine so far. My problem now is that I would need to call the second macro, the actual write, from every top level CMakefile.txt (and I may not even know all of them, there are quite a few, metrics talk about ~50.000 lines cmake files).

So I’m looking for a way to “register” a creation in first call of the ARTEFACT_VERSION() macro, but execute after all CMakefiles have been processed.

What I tried:
I cannot use file(GENRATE) with a variable, because apparently the variable is evaluated at call of file(GENERATE), not at time of actual generation (so it includes only the first artvers.txt entry). I cannot specify to use a global property in file(GENERATE). Then I tried custom_command()s (I have a hook available to make it run, I have a general target were I can add this as dependency), but only got some messy intermediate results; generating multiline files seems to make it ugly. Seems not to be the way either.

Now I wondering how to approach this correctly. There seems to be a mechanism where all this works, the @REPL@ mechanism, but I don’t know how to utilize that in my case.

I hope I explained well and someone can point me to the right direction.

Thanks for reading all this :slight_smile:

Check out cmake_language(DEFER ... CALL ...) (docs). You can use that to run something at a later point, including by specifying a directory scope in which the call should run. For example, the following would print a message at the end of the top level CMakeLists.txt:

cmake_language(DEFER
    DIRECTORY ${CMAKE_SOURCE_DIR}
    CALL message "This is the end of the top level CMakeLists.txt"
)

The command also supports options for associating an ID with the deferred command. You could potentially use that to only add the deferred command once, or you could just set a global property with a well known name (but make that name specific to your organisation to avoid clashes with other project’s names).

Thank you so much for pointing me to this nice feature!
(Unfortunately it is not available in the cmake-3.18 used by the project and apparently I cannot convince to update)