Search code examples
cmakecmake-custom-command

CMake create custom target with dependency on generated file


In CMake, I want to create a custom target with a dependency on a generated file.

It would be along the lines of:

configure_file(conf.py.in conf.py)

add_custom_target(doc
  COMMAND ${SPHINX_EXECUTABLE} -b html ${SPHINX_SOURCE} ${SPHINX_BUILD}
  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
  COMMENT "Generating documentation with Sphinx"
  DEPENDS conf.py)

I.e. I would like to avoid unconditionally generating conf.py; I would rather have a custom target with a dependency on it and thereby limit when conf.py is generated.

How can I do this?

I don't quite understand how I can "integrate" configure_file() into the add_custom_target() (presumably the COMMAND or argument?), or make the latter "depend on" the former.


Solution

  • configure_file occurs during configuration.

    add_custom_target occurs during the build step.

    CMake is roughly broken up into 3 steps:

    • Configure (configure_file will run during this step.)
    • Generate
    • Build (add_custom_target will run during this step.)

    IE the file configure_file produces will be ready before add_custom_target by definition.

    I.e. I would like to avoid unconditionally generating conf.py; I would rather have a custom target with a dependency on it and thereby limit when conf.py is generated.

    Then your work is already done. Configure file will only run when the input file changes.

    From the CMake documentation: If the input file is modified the build system will re-run CMake to re-configure the file and generate the build system again. The generated file is modified and its timestamp updated on subsequent cmake runs only if its content is changed. - configure_file

    As a result you don't need to DEPEND on this file. It's guaranteed to exist before the build starts.

    # conf.py is now generated in the ${CMAKE_CURRENT_BINARY_DIR}
    # This is by default where configure_file places the output file
    configure_file(conf.py.in conf.py)
    
    # NOTE: By default commands are executed in ${CMAKE_CURRENT_BINARY_DIR}
    # So you don't need to specify working directory.
    add_custom_target(doc
      COMMAND ${SPHINX_EXECUTABLE} -b html ${SPHINX_SOURCE} ${SPHINX_BUILD}
      COMMENT "Generating documentation with Sphinx"
    )