I believe I found the problem @janitor048 had with @richq's answer. Unfortunately, I don't have enough reputation to comment on his answer - maybe someone else can copy and paste.
@richq uses both a custom command and a custom target. The custom command is necessary to convince CMake that the header will be created, otherwise the CMake script could be executed as a command for the custom target. While a custom target will always be executed, a custom command won't if its output file already exists.
The workaround is to add a bogus dependency (an imaginary file) to the custom target, and tell CMake that the custom command creates that file. This is enough to ensure that the custom command is always executed. Fortunately, CMake doesn't actually check whether this file is created or not.
richq has:
# a custom target that is always built
add_custom_target(svnheader ALL
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/svnheader.h)
# creates svnheader.h using cmake script
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/svnheader.h
COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}
-P ${CMAKE_CURRENT_SOURCE_DIR}/getsvn.cmake)
This works for me:
# a custom target that is always built
add_custom_target(svnheader ALL
DEPENDS svn_header ) # svn_header is nothing more than a unique string
# creates svnheader.h using cmake script
add_custom_command(OUTPUT svn_header ${CMAKE_CURRENT_BINARY_DIR}/svnheader.h
COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}
-P ${CMAKE_CURRENT_SOURCE_DIR}/getsvn.cmake)
Also, if someone wishes to use Git, use this for the CMake script:
#create a pretty commit id using git
#uses 'git describe --tags', so tags are required in the repo
#create a tag with 'git tag <name>' and 'git push --tags'
find_package(Git)
if(GIT_FOUND)
execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags RESULT_VARIABLE res_var OUTPUT_VARIABLE GIT_COM_ID )
if( NOT ${res_var} EQUAL 0 )
set( GIT_COMMIT_ID "git commit id unknown")
message( WARNING "Git failed (not a repo, or no tags). Build will not contain git revision info." )
endif()
string( REPLACE "\n" "" GIT_COMMIT_ID ${GIT_COM_ID} )
else()
set( GIT_COMMIT_ID "unknown (git not found!)")
message( WARNING "Git not found. Build will not contain git revision info." )
endif()
set( vstring "//version_string.hpp - written by cmake. changes will be lost!\n"
"const char * VERSION_STRING = \"${GIT_COMMIT_ID}\"\;\n")
file(WRITE version_string.hpp.txt ${vstring} )
# copy the file to the final header only if the version changes
# reduces needless rebuilds
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
version_string.hpp.txt ${CMAKE_CURRENT_BINARY_DIR}/version_string.hpp)