33#
44# https://github.com/sethrj/cmake-git-version
55#
6- # Copyright 2021 UT-Battelle, LLC and Seth R Johnson
6+ # Copyright 2021-2023 UT-Battelle, LLC
77#
8- # Licensed under the Apache License, Version 2.0 (the "License");
9- # you may not use this file except in compliance with the License.
10- # You may obtain a copy of the License at
8+ # Licensed under the Apache License, Version 2.0 (the "License");
9+ # you may not use this file except in compliance with the License.
10+ # You may obtain a copy of the License at
1111#
12- # http://www.apache.org/licenses/LICENSE-2.0
12+ # http://www.apache.org/licenses/LICENSE-2.0
1313#
14- # Unless required by applicable law or agreed to in writing, software
15- # distributed under the License is distributed on an "AS IS" BASIS,
16- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17- # See the License for the specific language governing permissions and
18- # limitations under the License.
14+ # Unless required by applicable law or agreed to in writing, software
15+ # distributed under the License is distributed on an "AS IS" BASIS,
16+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+ # See the License for the specific language governing permissions and
18+ # limitations under the License.
1919#[=======================================================================[.rst:
2020
2121CgvFindVersion
@@ -31,13 +31,15 @@ CgvFindVersion
3131 ``<projname>``
3232 Name of the project.
3333
34- This command sets the following variables in the parent package::
34+ This command sets the numeric (usable in CMake version comparisons) and
35+ extended (useful for exact versioning) version variables in the parent
36+ package::
3537
3638 ${projname}_VERSION
3739 ${projname}_VERSION_STRING
3840
39- It takes the project name and version file path as optional arguments to
40- support using it before the CMake ``project`` command.
41+ It takes the project name as an optional argument so that it may be used
42+ * before* calling the CMake ``project`` command.
4143
4244 The project version string uses an approximation to SemVer strings, appearing
4345 as v0.1.2 if the version is actually a tagged release, or v0.1.3+abcdef if
@@ -47,10 +49,13 @@ CgvFindVersion
4749 it's impossible to determine the version from the tag, so a warning will be
4850 issued and the version will be set to 0.0.0.
4951
50- The exact regex used to match the version tag is::
52+ The default regex used to match the numeric version and full version string
53+ from the git tag is::
5154
5255 v([0-9.]+)(-dev[0-9.]+)?
5356
57+ but you can override the regex by setting the ``CGV_TAG_REGEX`` variable
58+ before calling ``cgv_find_version``.
5459
5560 .. note:: In order for this script to work properly with archived git
5661 repositories (generated with ``git-archive`` or GitHub's release tarball
@@ -64,108 +69,198 @@ if(CMAKE_SCRIPT_MODE_FILE)
6469 cmake_minimum_required (VERSION 3.8)
6570endif ()
6671
67- function (cgv_find_version)
68- set (projname "${ARGV0} " )
69- if (NOT projname)
70- set (projname "${CMAKE_PROJECT_NAME} " )
71- if (NOT projname)
72- message (FATAL_ERROR "Project name is not defined" )
73- endif ()
72+ #-----------------------------------------------------------------------------#
73+
74+ function (_cgv_store_version string suffix hash)
75+ if (NOT string )
76+ message (WARNING "The version metadata for ${CGV_PROJECT} could not "
77+ "be determined: installed version number may be incorrect" )
7478 endif ()
79+ set (_CACHED_VERSION "${string} " "${suffix} " "${hash} " )
80+ # Note: extra 'unset' is necessary if using CMake presets with
81+ # ${CGV_PROJECT}_GIT_DESCRIBE="", even with INTERNAL/FORCE
82+ unset (${CGV_CACHE_VAR} CACHE )
83+ set (${CGV_CACHE_VAR} "${_CACHED_VERSION} " CACHE INTERNAL
84+ "Version string and hash for ${CGV_PROJECT} " )
85+ endfunction ()
86+
87+ #-----------------------------------------------------------------------------#
7588
89+ function (_cgv_try_archive_md)
7690 # Get a possible Git version generated using git-archive (see the
7791 # .gitattributes file)
92+ set (_ARCHIVE_DESCR "$Format:%$" )
7893 set (_ARCHIVE_TAG "$Format:%D$" )
7994 set (_ARCHIVE_HASH "$Format:%h$" )
95+ if (_ARCHIVE_HASH MATCHES "Format:%h" )
96+ # Not a git archive
97+ return ()
98+ endif ()
8099
81- set (_TAG_REGEX "v([0-9.]+)(-dev[0-9.]+)?" )
82- set (_HASH_REGEX "([0-9a-f]+)" )
83-
84- if (_ARCHIVE_HASH MATCHES "%h" )
85- # Not a "git archive": use live git information
86- set (_CACHE_VAR "${projname} _GIT_DESCRIBE" )
87- set (_CACHED_VERSION "${${_CACHE_VAR} }" )
88- if (NOT _CACHED_VERSION)
89- # Building from a git checkout rather than a distribution
90- if (NOT GIT_EXECUTABLE)
91- find_package (Git QUIET REQUIRED)
92- endif ()
93- execute_process (
94- COMMAND "${GIT_EXECUTABLE} " "describe" "--tags" "--match" "v*"
95- WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR} "
96- ERROR_VARIABLE _GIT_ERR
97- OUTPUT_VARIABLE _VERSION_STRING
98- RESULT_VARIABLE _GIT_RESULT
99- OUTPUT_STRIP_TRAILING_WHITESPACE
100- )
101- if (_GIT_RESULT)
102- message (AUTHOR_WARNING "No git tags in ${projname} matched 'v*': "
103- "${_GIT_ERR} " )
104- elseif (NOT _VERSION_STRING)
105- message (WARNING "Failed to get ${projname} version from git: "
106- "git describe returned an empty string" )
107- else ()
108- # Process description tag: e.g. v0.4.0-2-gc4af497 or v0.4.0
109- # or v2.0.0-dev2
110- string (REGEX MATCH "^${_TAG_REGEX} (-[0-9]+-g${_HASH_REGEX} )?" _MATCH
111- "${_VERSION_STRING} "
112- )
113- if (_MATCH)
114- set (_VERSION_STRING "${CMAKE_MATCH_1} " )
115- set (_VERSION_STRING_SUFFIX "${CMAKE_MATCH_2} " )
116- if (CMAKE_MATCH_3)
117- # *not* a tagged release
118- set (_VERSION_HASH "${CMAKE_MATCH_4} " )
119- endif ()
120- endif ()
121- endif ()
122- if (NOT _VERSION_STRING)
123- execute_process (
124- COMMAND "${GIT_EXECUTABLE} " "log" "-1" "--format=%h" "HEAD"
125- WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR} "
126- OUTPUT_VARIABLE _VERSION_HASH
127- OUTPUT_STRIP_TRAILING_WHITESPACE
128- )
129- endif ()
130- set (_CACHED_VERSION "${_VERSION_STRING} " "${_VERSION_STRING_SUFFIX} " "${_VERSION_HASH} " )
131- set ("${_CACHE_VAR} " "${_CACHED_VERSION} " CACHE INTERNAL
132- "Version string and hash for ${projname} " )
133- endif ()
134- list (GET _CACHED_VERSION 0 _VERSION_STRING)
135- list (GET _CACHED_VERSION 1 _VERSION_STRING_SUFFIX)
136- list (GET _CACHED_VERSION 2 _VERSION_HASH)
100+ string (REGEX MATCH "tag: *${CGV_TAG_REGEX} " _MATCH "${_ARCHIVE_TAG} " )
101+ if (_MATCH)
102+ _cgv_store_version("${CMAKE_MATCH_1} " "${CMAKE_MATCH_2} " "" )
137103 else ()
138- string (REGEX MATCH "tag: *${_TAG_REGEX} " _MATCH "${_ARCHIVE_TAG} " )
104+ message (WARNING "Could not match a version tag for "
105+ "git description '${_ARCHIVE_TAG} ': perhaps this archive was not "
106+ "exported from a tagged commit?" )
107+ string (REGEX MATCH " *([0-9a-f]+)" _MATCH "${_ARCHIVE_HASH} " )
139108 if (_MATCH)
140- set (_VERSION_STRING "${CMAKE_MATCH_1} " )
141- set (_VERSION_STRING_SUFFIX "${CMAKE_MATCH_2} " )
109+ _cgv_store_version("" "" "${CMAKE_MATCH_1} " )
110+ endif ()
111+ endif ()
112+ endfunction ()
113+
114+ #-----------------------------------------------------------------------------#
115+
116+ function (_cgv_try_git_describe)
117+ # First time calling "git describe"
118+ if (NOT Git_FOUND)
119+ find_package (Git QUIET )
120+ if (NOT Git_FOUND)
121+ message (WARNING "Could not find Git, needed to find the version tag" )
122+ return ()
123+ endif ()
124+ endif ()
125+
126+ # Load git description
127+ execute_process (
128+ COMMAND "${GIT_EXECUTABLE} " "describe" "--tags" "--match" "v*"
129+ WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR} "
130+ ERROR_VARIABLE _GIT_ERR
131+ OUTPUT_VARIABLE _VERSION_STRING
132+ RESULT_VARIABLE _GIT_RESULT
133+ OUTPUT_STRIP_TRAILING_WHITESPACE
134+ )
135+ if (_GIT_RESULT)
136+ message (WARNING "No git tags in ${CGV_PROJECT} matched 'v*': "
137+ "${_GIT_ERR} " )
138+ return ()
139+ elseif (NOT _VERSION_STRING)
140+ message (WARNING "Failed to get ${CGV_PROJECT} version from git: "
141+ "git describe returned an empty string" )
142+ return ()
143+ endif ()
144+
145+ # Process description tag: e.g. v0.4.0-2-gc4af497 or v0.4.0
146+ # or v2.0.0-dev2
147+ set (_DESCR_REGEX "^${CGV_TAG_REGEX} (-([0-9]+)-g([0-9a-f]+))?" )
148+ string (REGEX MATCH "${_DESCR_REGEX} " _MATCH "${_VERSION_STRING} " )
149+ if (NOT _MATCH)
150+ message (WARNING "Failed to parse description '${_VERSION_STRING} ' "
151+ "with regex '${_DESCR_REGEX} '"
152+ )
153+ return ()
154+ endif ()
155+
156+ if (NOT CMAKE_MATCH_3)
157+ # This is a tagged release!
158+ _cgv_store_version("${CMAKE_MATCH_1} " "${CMAKE_MATCH_2} " "" )
159+ else ()
160+ if (CMAKE_MATCH_2)
161+ set (_suffix ${CMAKE_MATCH_2} .${CMAKE_MATCH_4} )
142162 else ()
143- message (AUTHOR_WARNING "Could not match a version tag for "
144- "git description '${_ARCHIVE_TAG} ': perhaps this archive was not "
145- "exported from a tagged commit?" )
146- string (REGEX MATCH " *${_HASH_REGEX} " _MATCH "${_ARCHIVE_HASH} " )
147- if (_MATCH)
148- set (_VERSION_HASH "${CMAKE_MATCH_1} " )
163+ set (_suffix -${CMAKE_MATCH_4} )
164+ endif ()
165+ # Qualify the version number and save the hash
166+ _cgv_store_version(
167+ "${CMAKE_MATCH_1} " # [0-9.]+
168+ "${_suffix} " # (-dev[0-9.]*)? \. ([0-9]+)
169+ "${CMAKE_MATCH_5} " ([0-9a-f]+)
170+ )
171+ endif ()
172+ endfunction ()
173+
174+ #-----------------------------------------------------------------------------#
175+
176+ function (_cgv_try_git_hash)
177+ if (NOT GIT_EXECUTABLE)
178+ return ()
179+ endif ()
180+ # Fall back to just getting the hash
181+ execute_process (
182+ COMMAND "${GIT_EXECUTABLE} " "log" "-1" "--format=%h" "HEAD"
183+ WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR} "
184+ OUTPUT_VARIABLE _VERSION_HASH
185+ RESULT_VARIABLE _GIT_RESULT
186+ OUTPUT_STRIP_TRAILING_WHITESPACE
187+ )
188+ if (_GIT_RESULT)
189+ message (WARNING "Failed to get current commit hash from git: "
190+ "${_GIT_ERR} " )
191+ return ()
192+ endif ()
193+ _cgv_store_version("" "" "${_VERSION_HASH} " )
194+ endfunction ()
195+
196+ #-----------------------------------------------------------------------------#
197+
198+ function (cgv_find_version)
199+ # Set CGV_ variables that are used in embedded macros/functions
200+ if (ARGC GREATER 0)
201+ set (CGV_PROJECT "${ARGV0} " )
202+ elseif (NOT CGV_PROJECT)
203+ if (NOT CMAKE_PROJECT_NAME )
204+ message (FATAL_ERROR "Project name is not defined" )
205+ endif ()
206+ set (CGV_PROJECT "${CMAKE_PROJECT_NAME} " )
207+ endif ()
208+
209+ if (NOT CGV_TAG_REGEX)
210+ set (CGV_TAG_REGEX "v([0-9.]+)(-[a-z]+[0-9.]*)?" )
211+ endif ()
212+
213+ set (CGV_CACHE_VAR "${CGV_PROJECT} _GIT_DESCRIBE" )
214+
215+ # Successively try archive metadata, git description, or just git hash
216+ if (NOT ${CGV_CACHE_VAR} )
217+ _cgv_try_archive_md()
218+ if (NOT ${CGV_CACHE_VAR} )
219+ _cgv_try_git_describe()
220+ if (NOT ${CGV_CACHE_VAR} )
221+ _cgv_try_git_hash()
222+ if (NOT ${CGV_CACHE_VAR} )
223+ set (${CGV_CACHE_VAR} "" "-unknown" "" )
224+ endif ()
149225 endif ()
150226 endif ()
151227 endif ()
152228
229+ # Unpack stored version
230+ set (_CACHED_VERSION "${${CGV_CACHE_VAR} }" )
231+ list (GET _CACHED_VERSION 0 _VERSION_STRING)
232+ list (GET _CACHED_VERSION 1 _VERSION_STRING_SUFFIX)
233+ list (GET _CACHED_VERSION 2 _VERSION_HASH)
234+
153235 if (NOT _VERSION_STRING)
154236 set (_VERSION_STRING "0.0.0" )
155237 endif ()
156238
157239 if (_VERSION_HASH)
158- set (_FULL_VERSION_STRING "v ${_VERSION_STRING}${_VERSION_STRING_SUFFIX} +${_VERSION_HASH} " )
240+ set (_FULL_VERSION_STRING "${_VERSION_STRING}${_VERSION_STRING_SUFFIX} +${_VERSION_HASH} " )
159241 else ()
160- set (_FULL_VERSION_STRING "v ${_VERSION_STRING}${_VERSION_STRING_SUFFIX} " )
242+ set (_FULL_VERSION_STRING "${_VERSION_STRING}${_VERSION_STRING_SUFFIX} " )
161243 endif ()
162244
163- set (${projname} _VERSION "${_VERSION_STRING} " PARENT_SCOPE)
164- set (${projname} _VERSION_STRING "${_FULL_VERSION_STRING} " PARENT_SCOPE)
245+ # Set version number and descriptive version in parent scope
246+ set (${CGV_PROJECT} _VERSION "${_VERSION_STRING} " PARENT_SCOPE)
247+ set (${CGV_PROJECT} _VERSION_STRING "${_FULL_VERSION_STRING} " PARENT_SCOPE)
165248endfunction ()
166249
250+ #-----------------------------------------------------------------------------#
251+
167252if (CMAKE_SCRIPT_MODE_FILE )
168253 cgv_find_version(TEMP)
169- message ("VERSION=\" ${TEMP_VERSION} \" " )
170- message ("VERSION_STRING=\" ${TEMP_VERSION_STRING} \" " )
254+ if (DEFINED ONLY)
255+ # Print only the given variable, presumably VERSION or VERSION_STRING
256+ # (will print to stderr)
257+ set (VERSION "${TEMP_VERSION} " )
258+ set (VERSION_STRING "${TEMP_VERSION_STRING} " )
259+ message ("${${ONLY} }" )
260+ else ()
261+ message ("VERSION=\" ${TEMP_VERSION} \" " )
262+ message ("VERSION_STRING=\" ${TEMP_VERSION_STRING} \" " )
263+ endif ()
171264endif ()
265+
266+ # cmake-git-version 1.1.1
0 commit comments