Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rebuild configuration file when there are no CMake changes

Tags:

cmake

I have a project with a configuration file in it.

configure_file(version.h.in version/version.h)

The same code base is used for multiple build in a day, without cleaning between builds. The version.h file will be built the first time the build is run, but subsequent builds will not rebuild (and update the revision number) in the version.h.

Is there a way I can force CMake to always rebuild version.h regardless of changes, or better yet based on a change (or lack of change) in a subversion revision number?

like image 773
the_storyteller Avatar asked Nov 29 '25 15:11

the_storyteller


1 Answers

There are a few issues you need to overcome to have this work.

  • When cmake is run any version information you extract from subversion is baked into the generated build files, and so becomes static.
  • Cmake is only rerun if it detects the generated build files have become out of date (eg: if a CMakeLists.txt file is updated)
  • You can create a custom_target which will be run every time you build (from the docs: "The target has no output file and is ALWAYS CONSIDERED OUT OF DATE") which generates the file, but that will force you to rebuild your generated version file every time.

Here is an approach which overcomes all of the above hurdles:

First, create a library which will contain the compiled version information.

add_library(version STATIC ${CMAKE_CURRENT_BINARY_DIR}/version_gen.cc)

Now, add an artificial dependency between the library and a custom_target called gen_version

add_dependencies(version gen_version)

This will force gen_version to be run before building the version library.

Now create a custom_target called gen_version which will generate the version information:

add_custom_target(
    gen_version
    ALL
    COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/gen_version.cmake)

This custom target is added to the ALL target, and will be run every time you build. It will execute another cmake script called gen_version.cmake

This is the first trick. We get cmake to execute a subprocess and run a new cmake script on each build, in which the required version information is calculated anew each build.

The next trick is to call configure_file with a temporary output file, and only update the real version file if necessary. This prevents the need to recompile when the version doesn't change.

In the below example I show obtaining the version information from git - you can swap this for your subversion method.

gen_version.cmake:

# obtain the git version
execute_process(
    OUTPUT_VARIABLE   ${VERSION}
    COMMAND           git rev-parse --short HEAD
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
    )

# configure the version file, but output to a temporary location
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/version_gen.in
    ${CMAKE_CURRENT_BINARY_DIR}/version_gen.cc.tmp
    )

# compare with the real version file
execute_process(
    COMMAND
        ${CMAKE_COMMAND} -E compare_files
            ${CMAKE_CURRENT_BINARY_DIR}/version_gen.cc.tmp
            ${CMAKE_CURRENT_BINARY_DIR}/version_gen.cc
    RESULT_VARIABLE
        VERSION_NEEDS_UPDATING

    OUTPUT_QUIET
    ERROR_QUIET
)

# update the real version file if necessary
if(VERSION_NEEDS_UPDATING)
    execute_process(
        COMMAND
            ${CMAKE_COMMAND} -E copy
                ${CMAKE_CURRENT_BINARY_DIR}/version_gen.cc.tmp
                ${CMAKE_CURRENT_BINARY_DIR}/version_gen.cc
    )
endif()

set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/version_gen.cc
    PROPERTIES GENERATED TRUE)
like image 133
Steve Lorimer Avatar answered Dec 02 '25 04:12

Steve Lorimer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!