Skip to content

Commit bf31264

Browse files
[Build] Updated VTR Versioning
The way VTR was setting its version information was slightly non-standard and was potentially causing issues when VTR was being built using sudo and then used by a non-sudoer. The reason this process is so complicated is because we want the versioning information to change if anything is modified in the repository or a new commit is created. Ryan Pavlik provides a CMake module to do exactly this, which is also used by the OpenROAD project. I updated our build process to use this CMake module. This also resolved an issue where VTR's version was printing v9.0.0; while our revision was showing v8.0.0. Now they both show v9.0.0.
1 parent 9d29ee2 commit bf31264

File tree

4 files changed

+377
-89
lines changed

4 files changed

+377
-89
lines changed

libs/libvtrutil/CMakeLists.txt

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -50,35 +50,49 @@ if (VTR_ENABLE_DEBUG_LOGGING)
5050
set(VTR_BUILD_INFO "${VTR_BUILD_INFO} debug_logging")
5151
endif()
5252

53-
# We always update the vtr_version.cpp file every time the project is built,
54-
# to ensure the git revision and dirty status are up to date.
55-
#
56-
# We need to do this in two stages:
57-
#
58-
# 1) We a custom target 'version' (which is always out of date) so it will always be run.
59-
# It touches the unprocessed version input file so it too will always be out of date.
60-
#
61-
# 2) The custom command depends on the touched version input file and generates the processed
62-
# version file, with updated values. The custom command uses the configure_version.cmake
63-
# script to generate the up-to-date vtr_version.cpp
64-
add_custom_target(version ALL
65-
COMMAND ${CMAKE_COMMAND} -E touch ${VTR_VERSION_FILE_IN})
66-
67-
add_custom_command(OUTPUT ${VTR_VERSION_FILE_OUT}
68-
COMMAND ${CMAKE_COMMAND}
69-
-D IN_FILE=${VTR_VERSION_FILE_IN}
70-
-D OUT_FILE=${VTR_VERSION_FILE_OUT}
71-
-D VTR_VERSION_MAJOR=${VTR_VERSION_MAJOR}
72-
-D VTR_VERSION_MINOR=${VTR_VERSION_MINOR}
73-
-D VTR_VERSION_PATCH=${VTR_VERSION_PATCH}
74-
-D VTR_VERSION_PRERELEASE=${VTR_VERSION_PRERELEASE}
75-
-D VTR_COMPILER_INFO=${VTR_COMPILER_INFO}
76-
-D VTR_BUILD_INFO=${VTR_BUILD_INFO}
77-
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/configure_version.cmake
78-
MAIN_DEPENDENCY ${VTR_VERSION_FILE_IN}
79-
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
80-
VERBATIM)
53+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
54+
include(GetGitRevisionDescription)
55+
56+
# Get the VCS revision.
57+
git_describe_working_tree(VTR_VCS_REVISION --tags --always --long)
58+
string(FIND ${VTR_VCS_REVISION} "NOTFOUND" GIT_DESCRIBE_VTR_REVISION_NOTFOUND)
59+
if (NOT ${GIT_DESCRIBE_VTR_REVISION_NOTFOUND} EQUAL -1)
60+
# Git describe failed, usually this means we
61+
# aren't in a git repo -- so don't set a VCS
62+
# revision
63+
set(VTR_VCS_REVISION "unknown")
64+
endif()
65+
66+
# Get the short VCS revision
67+
git_describe_working_tree(VTR_VCS_REVISION_SHORT --tags --always --long --exclude '*')
68+
string(FIND "${VTR_VCS_REVISION_SHORT}" "NOTFOUND" GIT_DESCRIBE_VTR_REVISION_SHORT_NOTFOUND)
69+
if (NOT ${GIT_DESCRIBE_VTR_REVISION_SHORT_NOTFOUND} EQUAL -1)
70+
# Git describe failed, usually this means we
71+
# aren't in a git repo -- so don't set a VCS
72+
# revision
73+
set(VTR_VCS_REVISION_SHORT "unknown")
74+
endif()
8175

76+
# Set the version according to semver.org
77+
set(VTR_VERSION "${VTR_VERSION_MAJOR}.${VTR_VERSION_MINOR}.${VTR_VERSION_PATCH}")
78+
if(VTR_VERSION_PRERELEASE)
79+
set(VTR_VERSION "${VTR_VERSION}-${VTR_VERSION_PRERELEASE}")
80+
endif()
81+
set(VTR_VERSION_SHORT ${VTR_VERSION})
82+
if(VTR_VCS_REVISION)
83+
set(VTR_VERSION "${VTR_VERSION}+${VTR_VCS_REVISION_SHORT}")
84+
endif()
85+
86+
# Other build meta-data
87+
string(TIMESTAMP VTR_BUILD_TIMESTAMP)
88+
set(VTR_BUILD_TIMESTAMP "${VTR_BUILD_TIMESTAMP}")
89+
set(VTR_BUILD_INFO "${VTR_BUILD_INFO}")
90+
91+
message(STATUS "VTR Version: ${VTR_VERSION}")
92+
message(STATUS "VTR Revision: ${VTR_VCS_REVISION}")
93+
message(STATUS "VTR Short Revision: ${VTR_VCS_REVISION_SHORT}")
94+
95+
configure_file(${VTR_VERSION_FILE_IN} ${VTR_VERSION_FILE_OUT})
8296

8397
#
8498
# Source files and library
@@ -97,9 +111,6 @@ add_library(libvtrutil STATIC
97111
target_include_directories(libvtrutil PUBLIC ${LIB_INCLUDE_DIRS})
98112
set_target_properties(libvtrutil PROPERTIES PREFIX "") #Avoid extra 'lib' prefix
99113

100-
#Ensure version is always up to date by requiring version to be run first
101-
add_dependencies(libvtrutil version)
102-
103114
#Specify link-time dependencies
104115
target_link_libraries(libvtrutil
105116
liblog)
Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
# - Returns a version string from Git
2+
#
3+
# These functions force a re-configure on each git commit so that you can
4+
# trust the values of the variables in your build system.
5+
#
6+
# get_git_head_revision(<refspecvar> <hashvar> [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR])
7+
#
8+
# Returns the refspec and sha hash of the current head revision
9+
#
10+
# git_describe(<var> [<additional arguments to git describe> ...])
11+
#
12+
# Returns the results of git describe on the source tree, and adjusting
13+
# the output so that it tests false if an error occurs.
14+
#
15+
# git_describe_working_tree(<var> [<additional arguments to git describe> ...])
16+
#
17+
# Returns the results of git describe on the working tree (--dirty option),
18+
# and adjusting the output so that it tests false if an error occurs.
19+
#
20+
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
21+
#
22+
# Returns the results of git describe --exact-match on the source tree,
23+
# and adjusting the output so that it tests false if there was no exact
24+
# matching tag.
25+
#
26+
# git_local_changes(<var>)
27+
#
28+
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
29+
# Uses the return code of "git diff-index --quiet HEAD --".
30+
# Does not regard untracked files.
31+
#
32+
# Requires CMake 2.6 or newer (uses the 'function' command)
33+
#
34+
# Original Author:
35+
# 2009-2020 Rylie Pavlik <[email protected]>
36+
# https://ryliepavlik.com/
37+
#
38+
# Copyright 2009-2013, Iowa State University.
39+
# Copyright 2013-2020, Rylie Pavlik
40+
# Copyright 2013-2020, Contributors
41+
#
42+
# SPDX-License-Identifier: BSL-1.0
43+
#
44+
# Distributed under the Boost Software License, Version 1.0.
45+
# (See accompanying file LICENSE_1_0.txt or copy at
46+
# http://www.boost.org/LICENSE_1_0.txt)
47+
48+
if(__get_git_revision_description)
49+
return()
50+
endif()
51+
set(__get_git_revision_description YES)
52+
53+
# We must run the following at "include" time, not at function call time,
54+
# to find the path to this module rather than the path to a calling list file
55+
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
56+
57+
# Function _git_find_closest_git_dir finds the next closest .git directory
58+
# that is part of any directory in the path defined by _start_dir.
59+
# The result is returned in the parent scope variable whose name is passed
60+
# as variable _git_dir_var. If no .git directory can be found, the
61+
# function returns an empty string via _git_dir_var.
62+
#
63+
# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and
64+
# neither foo nor bar contain a file/directory .git. This wil return
65+
# C:/bla/.git
66+
#
67+
function(_git_find_closest_git_dir _start_dir _git_dir_var)
68+
set(cur_dir "${_start_dir}")
69+
set(git_dir "${_start_dir}/.git")
70+
while(NOT EXISTS "${git_dir}")
71+
# .git dir not found, search parent directories
72+
set(git_previous_parent "${cur_dir}")
73+
get_filename_component(cur_dir "${cur_dir}" DIRECTORY)
74+
if(cur_dir STREQUAL git_previous_parent)
75+
# We have reached the root directory, we are not in git
76+
set(${_git_dir_var}
77+
""
78+
PARENT_SCOPE)
79+
return()
80+
endif()
81+
set(git_dir "${cur_dir}/.git")
82+
endwhile()
83+
set(${_git_dir_var}
84+
"${git_dir}"
85+
PARENT_SCOPE)
86+
endfunction()
87+
88+
function(get_git_head_revision _refspecvar _hashvar)
89+
_git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR)
90+
91+
if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR")
92+
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE)
93+
else()
94+
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE)
95+
endif()
96+
if(NOT "${GIT_DIR}" STREQUAL "")
97+
file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}"
98+
"${GIT_DIR}")
99+
if("${_relative_to_source_dir}" MATCHES "[.][.]"
100+
AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR)
101+
# We've gone above the CMake root dir.
102+
set(GIT_DIR "")
103+
endif()
104+
endif()
105+
if("${GIT_DIR}" STREQUAL "")
106+
set(${_refspecvar}
107+
"GITDIR-NOTFOUND"
108+
PARENT_SCOPE)
109+
set(${_hashvar}
110+
"GITDIR-NOTFOUND"
111+
PARENT_SCOPE)
112+
return()
113+
endif()
114+
115+
# Check if the current source dir is a git submodule or a worktree.
116+
# In both cases .git is a file instead of a directory.
117+
#
118+
if(NOT IS_DIRECTORY ${GIT_DIR})
119+
# The following git command will return a non empty string that
120+
# points to the super project working tree if the current
121+
# source dir is inside a git submodule.
122+
# Otherwise the command will return an empty string.
123+
#
124+
execute_process(
125+
COMMAND "${GIT_EXECUTABLE}" rev-parse
126+
--show-superproject-working-tree
127+
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
128+
OUTPUT_VARIABLE out
129+
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
130+
if(NOT "${out}" STREQUAL "")
131+
# If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
132+
file(READ ${GIT_DIR} submodule)
133+
string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE
134+
${submodule})
135+
string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
136+
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
137+
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}
138+
ABSOLUTE)
139+
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
140+
else()
141+
# GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
142+
file(READ ${GIT_DIR} worktree_ref)
143+
# The .git directory contains a path to the worktree information directory
144+
# inside the parent git repo of the worktree.
145+
#
146+
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
147+
${worktree_ref})
148+
string(STRIP ${git_worktree_dir} git_worktree_dir)
149+
_git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR)
150+
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
151+
endif()
152+
else()
153+
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
154+
endif()
155+
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
156+
if(NOT EXISTS "${GIT_DATA}")
157+
file(MAKE_DIRECTORY "${GIT_DATA}")
158+
endif()
159+
160+
if(NOT EXISTS "${HEAD_SOURCE_FILE}")
161+
return()
162+
endif()
163+
set(HEAD_FILE "${GIT_DATA}/HEAD")
164+
configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
165+
166+
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
167+
"${GIT_DATA}/grabRef.cmake" @ONLY)
168+
include("${GIT_DATA}/grabRef.cmake")
169+
170+
set(${_refspecvar}
171+
"${HEAD_REF}"
172+
PARENT_SCOPE)
173+
set(${_hashvar}
174+
"${HEAD_HASH}"
175+
PARENT_SCOPE)
176+
endfunction()
177+
178+
function(git_describe _var)
179+
if(NOT GIT_FOUND)
180+
find_package(Git QUIET)
181+
endif()
182+
get_git_head_revision(refspec hash)
183+
if(NOT GIT_FOUND)
184+
set(${_var}
185+
"GIT-NOTFOUND"
186+
PARENT_SCOPE)
187+
return()
188+
endif()
189+
if(NOT hash)
190+
set(${_var}
191+
"HEAD-HASH-NOTFOUND"
192+
PARENT_SCOPE)
193+
return()
194+
endif()
195+
196+
# TODO sanitize
197+
#if((${ARGN}" MATCHES "&&") OR
198+
# (ARGN MATCHES "||") OR
199+
# (ARGN MATCHES "\\;"))
200+
# message("Please report the following error to the project!")
201+
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
202+
#endif()
203+
204+
#message(STATUS "Arguments to execute_process: ${ARGN}")
205+
206+
execute_process(
207+
COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN}
208+
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
209+
RESULT_VARIABLE res
210+
OUTPUT_VARIABLE out
211+
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
212+
if(NOT res EQUAL 0)
213+
set(out "${out}-${res}-NOTFOUND")
214+
endif()
215+
216+
set(${_var}
217+
"${out}"
218+
PARENT_SCOPE)
219+
endfunction()
220+
221+
function(git_describe_working_tree _var)
222+
if(NOT GIT_FOUND)
223+
find_package(Git QUIET)
224+
endif()
225+
if(NOT GIT_FOUND)
226+
set(${_var}
227+
"GIT-NOTFOUND"
228+
PARENT_SCOPE)
229+
return()
230+
endif()
231+
232+
execute_process(
233+
COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN}
234+
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
235+
RESULT_VARIABLE res
236+
OUTPUT_VARIABLE out
237+
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
238+
if(NOT res EQUAL 0)
239+
set(out "${out}-${res}-NOTFOUND")
240+
endif()
241+
242+
set(${_var}
243+
"${out}"
244+
PARENT_SCOPE)
245+
endfunction()
246+
247+
function(git_get_exact_tag _var)
248+
git_describe(out --exact-match ${ARGN})
249+
set(${_var}
250+
"${out}"
251+
PARENT_SCOPE)
252+
endfunction()
253+
254+
function(git_local_changes _var)
255+
if(NOT GIT_FOUND)
256+
find_package(Git QUIET)
257+
endif()
258+
get_git_head_revision(refspec hash)
259+
if(NOT GIT_FOUND)
260+
set(${_var}
261+
"GIT-NOTFOUND"
262+
PARENT_SCOPE)
263+
return()
264+
endif()
265+
if(NOT hash)
266+
set(${_var}
267+
"HEAD-HASH-NOTFOUND"
268+
PARENT_SCOPE)
269+
return()
270+
endif()
271+
272+
execute_process(
273+
COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD --
274+
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
275+
RESULT_VARIABLE res
276+
OUTPUT_VARIABLE out
277+
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
278+
if(res EQUAL 0)
279+
set(${_var}
280+
"CLEAN"
281+
PARENT_SCOPE)
282+
else()
283+
set(${_var}
284+
"DIRTY"
285+
PARENT_SCOPE)
286+
endif()
287+
endfunction()

0 commit comments

Comments
 (0)