Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to trigger a CMake reconfigure when the output of a command changes

Tags:

git

cmake

I'm looking to trigger a CMake configure to occur when the output of a command changes; Specifically I am looking at trying to make CMake configure when the output of git describe --always --dirty has change from the previous time CMake was configured.

Most of this problem can be solved by watching the HEAD file and resolving the symref inside to refs/heads/[branch] and linking these with configure_file(...) however this doesn't pick up on when the tree is in a dirty state (I.E. when there are uncommitted modifications). In this instance git describe --always --dirty will append the -dirty suffix to the output.

When this occurs there are no changes to the git files, only that git has noticed differences from the stored state so I can't configure_file(...) on any files here to get cmake to notice the change and reconfigure.

So I'm looking to find if there is a way to get cmake to run the git command notice the difference in output and trigger a reconfigure, almost need something akin to a pre-reconfigure-check stage.

Not sure if this is possible of if anyone has any ideas how else this behaviour can be achieved?

like image 822
rblk Avatar asked Oct 31 '22 00:10

rblk


1 Answers

The Problem

The problem here is that the "pre-reconfigure-check stage" is handled by your build environment. CMake is only called when some of its input files are changed (because CMake has generated rules for your build environment to keep track if those files being changed).

For this discussion let's assume you have something like:

execute_process(
    COMMAND ${GIT_EXECUTABLE} describe --always --dirty
    OUTPUT_VARIABLE _git_file_list
    OUTPUT_STRIP_TRAILING_WHITESPACE
)

configure_file(version.h.in version.h)

No Build-In Reconfigure when External Command Output Changes

I don't think something like "checking the output of external command as pre-reconfigure step" is possible without an additional script that you make part of your build process.

You could force CMake to reconfigure every time e.g. by calling make rebuild_cache before your actual build or by adding e.g. add_custom_command(TARGET MyExe POST_BUILD ${CMAKE_COMMAND} -E remove ${CMAKE_CURRENT_BINARY_DIR}/version.h), but calling the configuration process every time is very time consuming thing to do.

Solution

In my projects I have moved something like the code above into it's own WriteVersionInfo.cmake script:

set(_version_cpp_full_path "${CMAKE_CURRENT_BINARY_DIR}/version.cpp")
set(_version_obj_full_path "${_version_cpp_full_path}${CMAKE_CXX_OUTPUT_EXTENSION}")

string(REPLACE " " ";" _compiler_flags_list ${CMAKE_CXX_FLAGS})

# Create a dummy output to satisfy dependency check
if (NOT EXISTS ${_version_obj_full_path})
    file(WRITE ${_version_obj_full_path} "")
endif()

add_custom_command(
    TARGET MyExe
    PRE_LINK 
    COMMAND ${CMAKE_COMMAND} -D GIT_EXECUTABLE=${GIT_EXECUTABLE} 
                             -D _version_cpp_name=${_version_cpp_full_path} 
                             -P ${CMAKE_CURRENT_SOURCE_DIR}/WriteVersionInfo.cmake
    COMMAND ${CMAKE_CXX_COMPILER} ${_compiler_flags_list} 
                                  -o ${_version_obj_full_path} 
                                  -c ${_version_cpp_full_path}
    VERBATIM
)

target_link_libraries(
    MyExe
    ${_version_obj_full_path}
)

Here I'm directly writing to a .cpp file and directly pass it to the compiler as a PRE_LINK step. Please note that the above approach is not working for library targets (because there is no pre-link step).

References

  • CMake: Building a Version Header
like image 129
Florian Avatar answered Nov 15 '22 05:11

Florian