[CMake] Building a Version Header

Michael Hertling mhertling at online.de
Fri Jul 9 06:56:27 EDT 2010


On 07/08/2010 10:31 PM, Tyler Roscoe wrote:
> On Wed, Jul 07, 2010 at 10:43:15PM -0400, John Drescher wrote:
>> On Wed, Jul 7, 2010 at 9:44 PM, Clark Gaebel <cg.wowus.cg at gmail.com> wrote:
>>> I would like to generate file that looks something like this:
>>>
>>>    // version.h
>>>    #define VERSION "v0.1-345-ga77ede8"
>>
>> You want to do that with configure_file
> 
> The upside of this approach is that it's simple. The downside is that it
> is only run (and thus your version header is only updated) whenever
> CMake runs. It's possible for the source code to change without
> triggering a re-run of CMake.
> 
> Consequently, we use a custom command to call a python script at build
> time. The script writes out the header with the up-to-date version info.

Look at the following CMakeLists.txt:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(VERSIONHEADER C)
FIND_PACKAGE(Git)
FILE(WRITE ${CMAKE_BINARY_DIR}/main.c
"\#include \"version.h\"\nint main(void){return 0;}\n"
)
FILE(WRITE ${CMAKE_BINARY_DIR}/version.h.in
"\#define VERSION \"@VERSION@\"\n"
)
FILE(WRITE ${CMAKE_BINARY_DIR}/version.cmake
"EXECUTE_PROCESS(
     COMMAND ${GIT_EXECUTABLE} --version
     OUTPUT_VARIABLE VERSION
     OUTPUT_STRIP_TRAILING_WHITESPACE
 )
 CONFIGURE_FILE(\${SRC} \${DST} @ONLY)
")
INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR})
ADD_EXECUTABLE(main main.c)
ADD_CUSTOM_TARGET(
    version
    ${CMAKE_COMMAND} -D SRC=${CMAKE_BINARY_DIR}/version.h.in
                     -D DST=${CMAKE_BINARY_DIR}/version.h
                     -P ${CMAKE_BINARY_DIR}/version.cmake
)
ADD_DEPENDENCIES(main version)

At first, it generates main.c, version.h.in and version.cmake which you
would usually all have in your source directory, of course. The target
main is build from main.c including version.h, and the latter will be
generated by a custom target invoking the version.cmake script. This
script runs Git, collects the output and invokes CONFIGURE_FILE() to
transform the template version.h.in into the actual version.h header.
Here, Git's own version is substituted as a demonstration. Finally,
the main target must depend on the version target.

As the version target is always out of date it will be build each time
you (re)build main, but since CONFIGURE_FILE() obviously does not touch
the output file as long as it won't change, version.h isn't timestamped,
so it doesn't trigger the rebuild of the main target. Thus, you may have
an arbitrary number of dependencies on version.h, and none of them will
trigger a rebuild of anything unless version.h actually changes. To see
this more explicitly, replace "COMMAND ${GIT_EXECUTABLE} --version" by
"COMMAND date \"+%M\"" in version.cmake, and watch the main target not
being rebuilt until the minute hand's next leap. This is a very nice
feature and, IMO, the most economic way to provide a version header
which is checked - but not necessarily regenerated - before each
build. Furthermore, no external tool is needed to achieve this.

Regards,

Michael


More information about the CMake mailing list