In a Makefile this would be done with something like:
g++ -DGIT_SHA1="`git log -1 | head -n 1`" ...
This is very useful, because the binary knows exact commit SHA1 so it can dump it in case of segfault.
How can I achieve the same with CMake?
In a Makefile this would be done with something like:
g++ -DGIT_SHA1="`git log -1 | head -n 1`" ...
This is very useful, because the binary knows exact commit SHA1 so it can dump it in case of segfault.
How can I achieve the same with CMake?
It would be nice to have a solution that catches changes to the repository (from
git describe --dirty
), but only triggers recompilation if something about the git information has changed.Some of the existing solutions:
.git/logs/HEAD
. This only triggers recompilation when something in the repo changes, but misses the changes to get the '-dirty' state.-dirty
state, but triggers a recompilation all the time (based on the updated timestamp of the version information file)One fix to the third solution is to use the CMake 'copy_if_different' command, so the timestamp on the version information file only changes if the contents change.
The steps in the custom command are:
The code (borrowing heavily from kralyk's solution):
Here's my solution, which I think is reasonably short yet effective ;-)
First, a file is needed in the source tree (I name it
git-rev.h.in
), it should looks something like this:(Please never mind those macros, that's a little bit insane trick to make a string out of a raw value.) It is essential that this file has exactly one empty newline at the end so that value can be appended.
And now this code goes in respective
CMakeLists.txt
file:This command ensuers that the
git-rev.h.in
is copied in the build tree asgit-rev.h
and git revision is appended at its end.So all you need to do next is include
git-rev.h
in one of your files and do whatever you want with theGIT_REV
macro, which yields current git revision hash as a string value.The nice thing about this solution is that the
git-rev.h
is recreated each time you build the associated target, so you don't have to runcmake
over and over again.It also should be pretty portable - no non-portable external tools were used and even the bloody stupid windows cmd supports the
>
and>>
operators ;-)For a quick and dirty, possibly not portable way to get the git SHA-1 into a C or C++ project using CMake, I use this in CMakeLists.txt:
It assumes that
CMAKE_SOURCE_DIR
is part of a git repository, and that git is available on the system, and that an output redirection will be properly parsed by the shell.You can then make this target a dependency of any other target using
Each time
your_program
is built, the Makefile (or other build system, if this works on other build systems) will recreate git_revision.h in the source directory, with the contentsSo you can
#include git_revision.h
from some source code file and use it that way. Note that the header is created at literally every build, i.e. even if every other object file is up to date, it will still run this command to recreate git_revision.h. I figure that shouldn't be a huge problem because usually you don't rebuild the same git revision over and over again, but it's something to be aware of, and if it is a problem for you, then don't use this. (It's probably possible to hack up a workaround usingadd_custom_command
but I haven't needed it so far.)I can't help you with the CMake side, but with respect to Git side I would recommend taking a look how Linux kernel and Git project itself does it, via GIT-VERSION-GEN script, or how tig does it in its Makefile, by using
git describe
if there is git repository present, falling back to "version
" / "VERSION
" / "GIT-VERSION-FILE
" generated and present in tarballs, finally falling back to default value hardcoded in script (or Makefile).The first part (using
git describe
) requires that you tag releases using annotated (and possibly GPG signed) tags. Or usegit describe --tags
to use also lightweight tags.The following solution is based on the observation that Git updates the HEAD log whenever you
pull
orcommit
something. Note that e.g. Drew's suggestion above will update the Git information only if you rebuild the CMake cache manually after everycommit
.I use a CMake "custom command" that generates a one-line header file
${SRCDIR}/gitrevision.hh
where${SRCDIR}
is the root of your source tree. It will be re-made only when a new commit is made. Here is the necessary CMake magic with some comments:The contents of
gitrevision.hh
will look like this:If you want to change this then edit the
--pretty=format:
specification accordingly. E.g. using%H
instead of%h
will print the full SHA1 digest. See the Git manual for details.Making
gitrevision.hh
a fully-fledged C++ header file with include guards etc. is left as an exercise to the reader :-)I'd use sth. like this in my CMakeLists.txt: