···11+# - Returns a version string from Git
22+#
33+# These functions force a re-configure on each git commit so that you can
44+# trust the values of the variables in your build system.
55+#
66+# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
77+#
88+# Returns the refspec and sha hash of the current head revision
99+#
1010+# git_describe(<var> [<additional arguments to git describe> ...])
1111+#
1212+# Returns the results of git describe on the source tree, and adjusting
1313+# the output so that it tests false if an error occurs.
1414+#
1515+# git_describe_working_tree(<var> [<additional arguments to git describe> ...])
1616+#
1717+# Returns the results of git describe on the working tree (--dirty option),
1818+# and adjusting the output so that it tests false if an error occurs.
1919+#
2020+# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
2121+#
2222+# Returns the results of git describe --exact-match on the source tree,
2323+# and adjusting the output so that it tests false if there was no exact
2424+# matching tag.
2525+#
2626+# git_local_changes(<var>)
2727+#
2828+# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
2929+# Uses the return code of "git diff-index --quiet HEAD --".
3030+# Does not regard untracked files.
3131+#
3232+# Requires CMake 2.6 or newer (uses the 'function' command)
3333+#
3434+# Original Author:
3535+# 2009-2020 Ryan Pavlik <ryan.pavlik@gmail.com> <abiryan@ryand.net>
3636+# http://academic.cleardefinition.com
3737+#
3838+# Copyright 2009-2013, Iowa State University.
3939+# Copyright 2013-2020, Ryan Pavlik
4040+# Copyright 2013-2020, Contributors
4141+# SPDX-License-Identifier: BSL-1.0
4242+# Distributed under the Boost Software License, Version 1.0.
4343+# (See accompanying file LICENSE_1_0.txt or copy at
4444+# http://www.boost.org/LICENSE_1_0.txt)
4545+4646+if(__get_git_revision_description)
4747+ return()
4848+endif()
4949+set(__get_git_revision_description YES)
5050+5151+# We must run the following at "include" time, not at function call time,
5252+# to find the path to this module rather than the path to a calling list file
5353+get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
5454+5555+# Function _git_find_closest_git_dir finds the next closest .git directory
5656+# that is part of any directory in the path defined by _start_dir.
5757+# The result is returned in the parent scope variable whose name is passed
5858+# as variable _git_dir_var. If no .git directory can be found, the
5959+# function returns an empty string via _git_dir_var.
6060+#
6161+# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and
6262+# neither foo nor bar contain a file/directory .git. This wil return
6363+# C:/bla/.git
6464+#
6565+function(_git_find_closest_git_dir _start_dir _git_dir_var)
6666+ set(cur_dir "${_start_dir}")
6767+ set(git_dir "${_start_dir}/.git")
6868+ while(NOT EXISTS "${git_dir}")
6969+ # .git dir not found, search parent directories
7070+ set(git_previous_parent "${cur_dir}")
7171+ get_filename_component(cur_dir ${cur_dir} DIRECTORY)
7272+ if(cur_dir STREQUAL git_previous_parent)
7373+ # We have reached the root directory, we are not in git
7474+ set(${_git_dir_var}
7575+ ""
7676+ PARENT_SCOPE)
7777+ return()
7878+ endif()
7979+ set(git_dir "${cur_dir}/.git")
8080+ endwhile()
8181+ set(${_git_dir_var}
8282+ "${git_dir}"
8383+ PARENT_SCOPE)
8484+endfunction()
8585+8686+function(get_git_head_revision _refspecvar _hashvar)
8787+ _git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR)
8888+8989+ if(NOT "${GIT_DIR}" STREQUAL "")
9090+ file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}"
9191+ "${GIT_DIR}")
9292+ if("${_relative_to_source_dir}" MATCHES "[.][.]")
9393+ # We've gone above the CMake root dir.
9494+ set(GIT_DIR "")
9595+ endif()
9696+ endif()
9797+ if("${GIT_DIR}" STREQUAL "")
9898+ set(${_refspecvar}
9999+ "GITDIR-NOTFOUND"
100100+ PARENT_SCOPE)
101101+ set(${_hashvar}
102102+ "GITDIR-NOTFOUND"
103103+ PARENT_SCOPE)
104104+ return()
105105+ endif()
106106+107107+ # Check if the current source dir is a git submodule or a worktree.
108108+ # In both cases .git is a file instead of a directory.
109109+ #
110110+ if(NOT IS_DIRECTORY ${GIT_DIR})
111111+ # The following git command will return a non empty string that
112112+ # points to the super project working tree if the current
113113+ # source dir is inside a git submodule.
114114+ # Otherwise the command will return an empty string.
115115+ #
116116+ execute_process(
117117+ COMMAND "${GIT_EXECUTABLE}" rev-parse
118118+ --show-superproject-working-tree
119119+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
120120+ OUTPUT_VARIABLE out
121121+ ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
122122+ if(NOT "${out}" STREQUAL "")
123123+ # If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
124124+ file(READ ${GIT_DIR} submodule)
125125+ string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE
126126+ ${submodule})
127127+ string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
128128+ get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
129129+ get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}
130130+ ABSOLUTE)
131131+ set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
132132+ else()
133133+ # GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
134134+ file(READ ${GIT_DIR} worktree_ref)
135135+ # The .git directory contains a path to the worktree information directory
136136+ # inside the parent git repo of the worktree.
137137+ #
138138+ string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
139139+ ${worktree_ref})
140140+ string(STRIP ${git_worktree_dir} git_worktree_dir)
141141+ _git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR)
142142+ set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
143143+ endif()
144144+ else()
145145+ set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
146146+ endif()
147147+ set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
148148+ if(NOT EXISTS "${GIT_DATA}")
149149+ file(MAKE_DIRECTORY "${GIT_DATA}")
150150+ endif()
151151+152152+ if(NOT EXISTS "${HEAD_SOURCE_FILE}")
153153+ return()
154154+ endif()
155155+ set(HEAD_FILE "${GIT_DATA}/HEAD")
156156+ configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
157157+158158+ configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
159159+ "${GIT_DATA}/grabRef.cmake" @ONLY)
160160+ include("${GIT_DATA}/grabRef.cmake")
161161+162162+ set(${_refspecvar}
163163+ "${HEAD_REF}"
164164+ PARENT_SCOPE)
165165+ set(${_hashvar}
166166+ "${HEAD_HASH}"
167167+ PARENT_SCOPE)
168168+endfunction()
169169+170170+function(git_describe _var)
171171+ if(NOT GIT_FOUND)
172172+ find_package(Git QUIET)
173173+ endif()
174174+ get_git_head_revision(refspec hash)
175175+ if(NOT GIT_FOUND)
176176+ set(${_var}
177177+ "GIT-NOTFOUND"
178178+ PARENT_SCOPE)
179179+ return()
180180+ endif()
181181+ if(NOT hash)
182182+ set(${_var}
183183+ "HEAD-HASH-NOTFOUND"
184184+ PARENT_SCOPE)
185185+ return()
186186+ endif()
187187+188188+ # TODO sanitize
189189+ #if((${ARGN}" MATCHES "&&") OR
190190+ # (ARGN MATCHES "||") OR
191191+ # (ARGN MATCHES "\\;"))
192192+ # message("Please report the following error to the project!")
193193+ # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
194194+ #endif()
195195+196196+ #message(STATUS "Arguments to execute_process: ${ARGN}")
197197+198198+ execute_process(
199199+ COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN}
200200+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
201201+ RESULT_VARIABLE res
202202+ OUTPUT_VARIABLE out
203203+ ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
204204+ if(NOT res EQUAL 0)
205205+ set(out "${out}-${res}-NOTFOUND")
206206+ endif()
207207+208208+ set(${_var}
209209+ "${out}"
210210+ PARENT_SCOPE)
211211+endfunction()
212212+213213+function(git_describe_working_tree _var)
214214+ if(NOT GIT_FOUND)
215215+ find_package(Git QUIET)
216216+ endif()
217217+ if(NOT GIT_FOUND)
218218+ set(${_var}
219219+ "GIT-NOTFOUND"
220220+ PARENT_SCOPE)
221221+ return()
222222+ endif()
223223+224224+ execute_process(
225225+ COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN}
226226+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
227227+ RESULT_VARIABLE res
228228+ OUTPUT_VARIABLE out
229229+ ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
230230+ if(NOT res EQUAL 0)
231231+ set(out "${out}-${res}-NOTFOUND")
232232+ endif()
233233+234234+ set(${_var}
235235+ "${out}"
236236+ PARENT_SCOPE)
237237+endfunction()
238238+239239+function(git_get_exact_tag _var)
240240+ git_describe(out --exact-match ${ARGN})
241241+ set(${_var}
242242+ "${out}"
243243+ PARENT_SCOPE)
244244+endfunction()
245245+246246+function(git_local_changes _var)
247247+ if(NOT GIT_FOUND)
248248+ find_package(Git QUIET)
249249+ endif()
250250+ get_git_head_revision(refspec hash)
251251+ if(NOT GIT_FOUND)
252252+ set(${_var}
253253+ "GIT-NOTFOUND"
254254+ PARENT_SCOPE)
255255+ return()
256256+ endif()
257257+ if(NOT hash)
258258+ set(${_var}
259259+ "HEAD-HASH-NOTFOUND"
260260+ PARENT_SCOPE)
261261+ return()
262262+ endif()
263263+264264+ execute_process(
265265+ COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD --
266266+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
267267+ RESULT_VARIABLE res
268268+ OUTPUT_VARIABLE out
269269+ ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
270270+ if(res EQUAL 0)
271271+ set(${_var}
272272+ "CLEAN"
273273+ PARENT_SCOPE)
274274+ else()
275275+ set(${_var}
276276+ "DIRTY"
277277+ PARENT_SCOPE)
278278+ endif()
279279+endfunction()
+41
cmake/GetGitRevisionDescription.cmake.in
···11+#
22+# Internal file for GetGitRevisionDescription.cmake
33+#
44+# Requires CMake 2.6 or newer (uses the 'function' command)
55+#
66+# Original Author:
77+# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
88+# http://academic.cleardefinition.com
99+# Iowa State University HCI Graduate Program/VRAC
1010+#
1111+# Copyright Iowa State University 2009-2010.
1212+# Distributed under the Boost Software License, Version 1.0.
1313+# (See accompanying file LICENSE_1_0.txt or copy at
1414+# http://www.boost.org/LICENSE_1_0.txt)
1515+1616+set(HEAD_HASH)
1717+1818+file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
1919+2020+string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
2121+if(HEAD_CONTENTS MATCHES "ref")
2222+ # named branch
2323+ string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
2424+ if(EXISTS "@GIT_DIR@/${HEAD_REF}")
2525+ configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
2626+ else()
2727+ configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
2828+ file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
2929+ if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
3030+ set(HEAD_HASH "${CMAKE_MATCH_1}")
3131+ endif()
3232+ endif()
3333+else()
3434+ # detached HEAD
3535+ configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
3636+endif()
3737+3838+if(NOT HEAD_HASH)
3939+ file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
4040+ string(STRIP "${HEAD_HASH}" HEAD_HASH)
4141+endif()