How to add_custom_command() for the CMake build process itself?
Asked Answered
H

1

1

Is there any way to do the equivalent of add_custom_command (run an external script when a certain file changes), but for something that should be run during CMake script execution itself? (That is, for dependency graph generation.)

We have our source code files split up into multiple sub-libraries, and there are configuration files which list which source file goes with which library. (The format of these configuration files are fixed by another tool we use.) Currently, we run a custom external script which parses those configuration files and writes new files, which are then loaded by the CMake build process to give the list of filenames to be passed to add_library(). This means that each time a source file is added/removed, we need to remember to re-run the prebuild command, before re-running CMake, and then re-launching the build command.

I know that CMake can recognize that it needs to re-run itself, so I'm hoping that we can get CMake to 1) recognize that the configuration files are changed 2) rerun the configfile parser 3) load the new file list 4) use the new file list to regenerate the dependency tree 5) finally launch the actual build/compilation process with the new files included. ... and all this from the standard build command, without having to manually run the external configfile parser or manually re-run the CMake command, and without needless execution when the configfile hasn't changed.

In searching, I did find this question, where using configure_file() is suggested, but that doesn't address how to invoke the external configfile parser script.

Hajj answered 19/9, 2015 at 16:43 Comment(3)
configure_file() is the right choice to retrigger the configuration process. And execute_process() is used to run commands during the configuration step.Fostoria
@Fostoria Could you elaborate? I'm not quite seeing how to string the configure_file()/execute_process()/add_library() calls together to get a working rebuild.Hajj
To elaborate I needed a little more text than a comment would accept. So I added everything - including a code snippet - as an answer. Hope it helps to show how to get this working in CMake.Fostoria
F
3

Turning my comment into an answer

configure_file() is the right choice to retrigger the configuration process. And execute_process() is used to run commands during the configuration step.

Here is an abstract CMake snippet of the steps in your description:

function(my_add_library_from_cfg _target _cfg_file)
    # Retrigger configuration process each time config file changes
    get_filename_component(_cfg_name "${_cfg_file}" NAME)
    configure_file("${_cfg_file}" "${_cfg_name}.tmp")

    # Generating sources and file list
    execute_process(
        COMMAND ${CMAKE_COMMAND} -E echo "#define FOO" 
        OUTPUT_FILE foo.c
    )
    execute_process(
        COMMAND ${CMAKE_COMMAND} -E echo "foo.c"
        OUTPUT_FILE files.lst
    )

    # Reading file list and add library
    file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/files.lst" _sources_lst)
    add_library(${_target} ${_sources_lst} "${_cfg_file}")
endfunction(my_add_library_from_cfg)
  • configure_file() will retrigger CMake each time the given .cfg file changes
    • if you actually use the .cfg file as a command line parameter in execute_process() you should use the generated .tmp version in the current binary directory
  • execute_process() can do a lot of things
    • I used it to echo to stdout and write the output to files
    • the default WORKING_DIRECTORY here is the current binary directory
  • file() reads in the list of source files
    • full paths each, newline separated
  • I have written the generated files by purpose to the binary output directory
    • it makes a clean build easier, just delete the whole binary output directory
    • and CMake has build-in support for this; it will search for source files without absolute path first in the current source and then in current binary directory
  • And I didn't use the GENERATED source file property
    • because that would only be needed if the sources were generated by a previous build step
    • and CMake itself won't recognize anymore when actually a file from source file list would be missing
Fostoria answered 19/9, 2015 at 19:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.