[CMake] Putting the git commit hash in a cmake variable

Matt Schulte schultetwin1 at gmail.com
Wed Oct 10 17:05:09 EDT 2018


Hi all,

I'd like to set a CMake variable to the current git commit short hash.
This variable will be used as part of the version string for my
project (ex: "1.0.1+git.${SHORT_HASH}"). I can get at this short hash
by using execute_process and setting the resulting output to a
variable.

```cmake
execute_process(
    COMMAND
        git rev-parse --short HEAD
    RESULT_VARIABLE
        SHORT_HASH_RESULT
    OUTPUT_VARIABLE
        SHORT_HASH)
```

My issue is that cmake will only run execute_process once, during the
configure step. I need cmake to run this execute_process on every
build and, if the output has changed, reconfigure to make sure
SHORT_HASH is up to date.

I came up with one solution to this issue: During the configure step,
I can write the current short hash to a file named short_hash.txt. On
every build, I'll re-compute the short hash and verify that the
computed short hash is the same as what is in short_hash.txt. If its
not, I'll write the new short hash to short_hash.txt. I then make
short_hash.txt an input to configure_file. This will cause cmake to
validate SHORT_HASH is properly set, and re-configure if its not.

```cmake
execute_process(
    COMMAND
        git rev-parse --short HEAD
    RESULT_VARIABLE
        SHORT_HASH_RESULT
    OUTPUT_VARIABLE
        SHORT_HASH)

# If running in script mode (this runs on every build)
if (CMAKE_SCRIPT_MODE_FILE)
    if (EXISTS "${SHORT_HASH_FILE}")
        file(READ ${SHORT_HASH_FILE} READ_IN_SHORT_HASH)
    else()
        set(READ_IN_SHORT_HASH "")
    endif()

    if (NOT ("${READ_IN_SHORT_HASH}" STREQUAL "${SHORT_HASH}"))
        message(STATUS "Short hash is out of date")
        # This will update short_hash.txt, causing cmake to reconfigure
        file(WRITE ${SHORT_HASH_FILE} ${SHORT_HASH})
    endif()

# Else running as part of cmake configure
else()
    set(SHORT_HASH_FILE ${CMAKE_CURRENT_BINARY_DIR}/short_hash.txt)
    file(WRITE ${SHORT_HASH_FILE} ${SHORT_HASH})

    # The trick here is to make sure short_hash.txt is listed as a byproduct
    add_custom_target(
        git_short_hash
        BYPRODUCTS
            ${SHORT_HASH_FILE}
        COMMAND
            ${CMAKE_COMMAND}
            "-DSHORT_HASH_FILE=${SHORT_HASH_FILE}"
            "-P" "${CMAKE_CURRENT_LIST_FILE}"
        COMMENT
            "Re-checking short hash..."
        VERBATIM
        USES_TERMINAL)

    # This configure_file makes cmake reconfigure dependent on short_hash.txt
    configure_file(${SHORT_HASH_FILE} ${SHORT_HASH_FILE}.junk COPYONLY)

    message(STATUS "Short Hash: ${SHORT_HASH}")
endif()
```

This works great with cmake 3.12 and ninja 1.8.2! (I was really happy
with how well it worked. I tip my hat to the cmake developers for
this). However, it doesn't work with Makefiles, and causes ninja 1.7.2
to get stuck in an infinite loop. On CMake 3.10 this will cause ninja
1.8.2 to generate a warning about a loop.

Has anyone run into this issue before and have a better solution? Or
is trying to execute a command before cmake checks if it should
reconfigure a hack that should never be done?

Thanks for the help!
Matt


More information about the CMake mailing list