Hello, I would like to have my project use the current output from git describe
as the prerelease component of its SemVer version.
I have a solution that seems to work in all but one corner case. I’m hoping to find a way to resolve the corner case OR to find an alternative workable approach.
I’ve created a git repo to illustrate the issue and facilitate the discussion
https://github.com/ellio167/cmake-and-git-describe. Here is the main CMakeLists.txt
file showing a minimal form of my current solution.
cmake_minimum_required(VERSION 3.4)
project(MAIN VERSION 0.2.0 LANGUAGES C)
# FC: means "for conciseness"
find_package(Git) # FC: assume found
# FC: assume that ${CMAKE_SOURCE_DIR} is git repo toplevel dir
# set configuration to depend on _depend_file; then touch depend with every invocation of make
set(_git_describe_sentinel "git-describe-sentinel")
set(_depend_file "${CMAKE_CURRENT_BINARY_DIR}/${_git_describe_sentinel}-file")
execute_process(COMMAND ${CMAKE_COMMAND} -E touch "${_depend_file}")
set_property(DIRECTORY "${CURRENT_SOURCE_DIR}" APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${_depend_file}")
add_custom_target(${_git_describe_sentinel}-target ALL COMMAND ${CMAKE_COMMAND} -E touch "${_depend_file}")
# FC: assume the git index is refreshed
execute_process(
COMMAND ${GIT_EXECUTABLE} -C "${CMAKE_SOURCE_DIR}" describe --dirty --always
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE _git_describe
)
set(PROJECT_VERSION_STRING "${PROJECT_VERSION}+${_git_describe}")
add_executable(main "")
add_subdirectory(include)
add_subdirectory(src)
The corner case occurs because when configuration finishes the first time the sentinel file is older than the Makefile. So, when make is called the first time configuration is not triggered. If the git repo working directory is changed (files edited, new commits added, etc.) between the initial configuration and the first execution of make
, then incorrect git describe
results will be used for the build.
Here is a sequence of commands to reproduce the issue:
% git clone https://github.com/ellio167/cmake-and-git-describe.git
<...>
% cd cmake-and-git-describe.git
% mkdir build
% cd build
% git -C ../ describe --dirty --always
v0.2.0-2-g705268e
% cmake ../
<...>
% printf "/* add comment to main.c */\n" >> ../src/main.c # repo is now "dirty"
% make
<...>
% ./main # but main was build without the "-dirty" indicator
version is: 0.2.0
version string is: 0.2.0+v0.2.0-2-g705268e
% make # now configuration is triggered and correct behavior is obtained
<...>
% ./main
version is: 0.2.0
version string is: 0.2.0+v0.2.0-2-g705268e-dirty
%
One potential solution would be to not create the sentinel file as part of the initial configuration. However, if it does not exist then CMake prunes it from the CMAKE_CONFIGURE_DEPENDS
list at the end of the configuration step. So, this does not seem possible (without a change to CMake behavior).
Any help/suggestions would be much appreciated!