1 # Generate Gromacs development build version information.
3 # The script generates version information for a build from a development
4 # source tree based on git repository information.
5 # It is assumed that by default the script is run in cmake script mode.
6 # If *not* called in script mode but used in generating cache variables,
7 # GEN_VERSION_INFO_INTERNAL has to be set ON.
9 # The following variables have to be previously defined:
10 # Git_EXECUTABLE - path to git binary
11 # Git_VERSION - git version (if not defined it's assumed that >=1.5.3)
12 # PROJECT_VERSION - hard-coded version string, should have the following structure:
13 # VERSION[-dev-SUFFIX] where the VERSION can have any form and the suffix
14 # is optional but should start with -dev
15 # PROJECT_SOURCE_DIR - top level source directory (which has to be in git)
16 # VERSION_C_CMAKEIN - path to the version.c.cmakein file
17 # VERSION_C_OUT - path to the version.c output file
20 # i) Script mode: version.c configured from the input version.c.cmakein using
21 # the variables listed below.
22 # ii) Cache variable mode: the varables below are set in cache.
24 # GMX_PROJECT_VERSION_STR - version string
25 # GMX_GIT_HEAD_HASH - git hash of current local HEAD
26 # GMX_GIT_REMOTE_HASH - git hash of the first ancestor commit from the
27 # main Gromacs repository
29 # Szilard Pall (pszilard@cbr.su.se)
31 if(${PROJECT_VERSION} STREQUAL "")
32 message(FATAL_ERROR "PROJECT_VERSION undefined!")
34 set(VER ${PROJECT_VERSION})
36 # if we're generating variables for cache unset the variables
37 if(GEN_VERSION_INFO_INTERNAL)
38 set(GMX_PROJECT_VERSION_STR)
39 set(GMX_GIT_HEAD_HASH)
40 set(GMX_GIT_REMOTE_HASH)
43 # bail if the source tree is not in a git repository
44 if(NOT EXISTS "${PROJECT_SOURCE_DIR}/.git")
45 message(FATAL_ERROR " Project source directory ${PROJECT_SOURCE_DIR} not in git")
48 # if git executable xists and it's compatible version
49 # build the development version string
50 if(EXISTS ${Git_EXECUTABLE} AND NOT Git_VERSION VERSION_LESS "1.5.1")
52 execute_process(COMMAND ${Git_EXECUTABLE} update-index -q --refresh
53 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
56 ERROR_VARIABLE EXEC_ERR
57 OUTPUT_STRIP_TRAILING_WHITESPACE
60 # get the full hash of the current HEAD
61 execute_process(COMMAND ${Git_EXECUTABLE} rev-parse HEAD
62 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
63 OUTPUT_VARIABLE GMX_GIT_HEAD_HASH
64 ERROR_VARIABLE EXEC_ERR
65 OUTPUT_STRIP_TRAILING_WHITESPACE
67 # extract the shortened hash (7 char)
68 string(SUBSTRING ${GMX_GIT_HEAD_HASH} 0 5 HEAD_HASH_SHORT)
70 # if there are local uncommitted changes, the build gets labeled "dirty"
71 execute_process(COMMAND ${Git_EXECUTABLE} diff-index --name-only HEAD
72 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
73 OUTPUT_VARIABLE SRC_LOCAL_CHANGES
74 ERROR_VARIABLE EXEC_ERR
75 OUTPUT_STRIP_TRAILING_WHITESPACE
77 if(NOT ${SRC_LOCAL_CHANGES} STREQUAL "")
78 set(DIRTY_STR "-dirty")
79 set(GMX_GIT_HEAD_HASH "${GMX_GIT_HEAD_HASH} (dirty)")
82 # if git is older then 1.5.3 we need to extract the RFC2822 style date
83 # and massage it, otherwise the ISO 8601 format is more trusworthy
84 if (NOT Git_VERSION STREQUAL "" AND Git_VERSION VERSION_LESS "1.5.3")
85 execute_process(COMMAND ${Git_EXECUTABLE} rev-list -n1 "--pretty=format:%cD" HEAD
86 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
87 OUTPUT_VARIABLE HEAD_DATE
88 ERROR_VARIABLE EXEC_ERR
89 OUTPUT_STRIP_TRAILING_WHITESPACE
91 # date format: day, D Mmm YYYY -> YYYY-MM-DD
92 # if the day is single sigit need to insert a "0"
93 string(REGEX REPLACE ".*(, )([0-9] )(.*)" "\\10\\2\\3"
94 HEAD_DATE ${HEAD_DATE})
95 string(REGEX REPLACE ".*, ([0-9][0-9]) ([A-Z][a-z]+) ([0-9]+).*" "\\3\\2\\1"
96 HEAD_DATE ${HEAD_DATE})
97 string(TOUPPER ${HEAD_DATE} HEAD_DATE)
98 string(REGEX REPLACE "JAN" "01" HEAD_DATE ${HEAD_DATE})
99 string(REGEX REPLACE "FEB" "02" HEAD_DATE ${HEAD_DATE})
100 string(REGEX REPLACE "MAR" "03" HEAD_DATE ${HEAD_DATE})
101 string(REGEX REPLACE "APR" "04" HEAD_DATE ${HEAD_DATE})
102 string(REGEX REPLACE "MAY" "05" HEAD_DATE ${HEAD_DATE})
103 string(REGEX REPLACE "JUN" "06" HEAD_DATE ${HEAD_DATE})
104 string(REGEX REPLACE "JUL" "07" HEAD_DATE ${HEAD_DATE})
105 string(REGEX REPLACE "AUG" "08" HEAD_DATE ${HEAD_DATE})
106 string(REGEX REPLACE "SEP" "09" HEAD_DATE ${HEAD_DATE})
107 string(REGEX REPLACE "OCT" "10" HEAD_DATE ${HEAD_DATE})
108 string(REGEX REPLACE "NOV" "11" HEAD_DATE ${HEAD_DATE})
109 string(REGEX REPLACE "DEC" "12" HEAD_DATE ${HEAD_DATE})
111 # get the date of the HEAD commit
112 execute_process(COMMAND ${Git_EXECUTABLE} rev-list -n1 "--pretty=format:%ci" HEAD
113 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
114 OUTPUT_VARIABLE HEAD_DATE
115 ERROR_VARIABLE EXEC_ERR
116 OUTPUT_STRIP_TRAILING_WHITESPACE
118 string(REGEX REPLACE "\n| " ";" HEAD_DATE ${HEAD_DATE})
119 list(GET HEAD_DATE 2 HEAD_DATE)
120 string(REGEX REPLACE "-" "" HEAD_DATE ${HEAD_DATE})
123 # compile the version string suffix
124 set(VERSION_STR_SUFFIX "${HEAD_DATE}-${HEAD_HASH_SHORT}${DIRTY_STR}")
126 # find the name of the remote which is located on the official gromacs git server
127 execute_process(COMMAND ${Git_EXECUTABLE} config --get-regexp
128 "remote\\..*\\.url" "git\\.gromacs\\.org[:|/]gromacs"
129 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
130 OUTPUT_VARIABLE GMX_REMOTE
131 ERROR_VARIABLE EXEC_ERR
132 OUTPUT_STRIP_TRAILING_WHITESPACE
134 # if there's a remote from the gromacs git, try to find ancestor commits of the
135 # current HEAD from this remote; otherwise, label the buld "unknown"
136 if(GMX_REMOTE STREQUAL "")
137 set(VERSION_STR_SUFFIX "${VERSION_STR_SUFFIX}-unknown")
138 set(GMX_GIT_REMOTE_HASH "unknown")
140 string(REGEX REPLACE "remote\\.(.*)\\.url.*" "\\1" GMX_REMOTE ${GMX_REMOTE})
141 # find the first ancestor in the list provided by rev-list (not
142 # necessarily the last though) which is in GMX_REMOTE, extract the
143 # hash and the number of commits HEAD is ahead with
144 execute_process(COMMAND ${Git_EXECUTABLE} rev-list --max-count=100 HEAD
145 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
146 OUTPUT_VARIABLE ANCESTOR_LIST
148 string(REGEX REPLACE "\n" ";" ANCESTOR_LIST ${ANCESTOR_LIST})
151 set(GMX_GIT_REMOTE_HASH "")
152 foreach(OBJ ${ANCESTOR_LIST})
153 execute_process(COMMAND ${Git_EXECUTABLE} name-rev --refs=refs/remotes/${GMX_REMOTE}/* ${OBJ}
154 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
155 OUTPUT_VARIABLE HASH_AND_REVNAME
156 OUTPUT_STRIP_TRAILING_WHITESPACE
158 string(REGEX REPLACE "\n" "" HASH_AND_REVNAME ${HASH_AND_REVNAME})
159 string(REGEX REPLACE " " ";" HASH_AND_REVNAME ${HASH_AND_REVNAME})
160 list(GET HASH_AND_REVNAME 0 GMX_GIT_REMOTE_HASH)
161 list(GET HASH_AND_REVNAME 1 REVNAME)
162 # stop and set the hash if we have a hit, otherwise loop and count
163 # how far ahead is the local repo
164 if(${REVNAME} MATCHES "remotes/${GMX_REMOTE}/.*")
165 set(GMX_GIT_REMOTE_HASH
166 "${GMX_GIT_REMOTE_HASH} (${AHEAD} newer local commits)")
169 math(EXPR AHEAD ${AHEAD}+1)
172 # mark the build "local" if didn't find any commits that are from
173 # remotes/${GMX_REMOTE}/*
174 if(${GMX_GIT_REMOTE_HASH} STREQUAL "")
175 set(GMX_GIT_REMOTE_HASH "unknown")
176 set(VERSION_STR_SUFFIX "${VERSION_STR_SUFFIX}-local")
180 # compile final version string, if there is already a -dev suffix in VER
181 # remove everything after this and replace it with the generated suffix
182 string(REGEX REPLACE "(.*)-dev.*" "\\1" VER ${VER})
183 set(GMX_PROJECT_VERSION_STR "${VER}-dev-${VERSION_STR_SUFFIX}")
185 # the version has to be defined - if not we're not using version.h/.c and set
186 # the GIT related information to "unknown"
187 message(WARNING " Source tree seems to be a repository, but no compatible git is available, using hard-coded version string")
188 set(GMX_PROJECT_VERSION_STR "${PROJECT_VERSION}")
189 set(GMX_GIT_HEAD_HASH "unknown")
190 set(GMX_GIT_REMOTE_HASH "unknown")
193 # if we're generating cache variables set these
194 # otherwise it's assumed that it's called in script mode to generate version.c
195 if(GEN_VERSION_INFO_INTERNAL)
196 set(GMX_PROJECT_VERSION_STR ${GMX_PROJECT_VERSION_STR}
197 CACHE STRING "Gromacs version string" FORCE)
198 set(GMX_GIT_HEAD_HASH ${GMX_GIT_HEAD_HASH}${DIRTY_STR}
199 CACHE STRING "Current git HEAD commit object" FORCE)
200 set(GMX_GIT_REMOTE_HASH ${GMX_GIT_REMOTE_HASH}
201 CACHE STRING "Commmit object of the nearest ancestor present in the Gromacs git repository" FORCE)
202 mark_as_advanced(GMX_GIT_HEAD_HASH GMX_GIT_REMOTE_HASH)
204 if(${VERSION_C_CMAKEIN} STREQUAL "")
205 message(FATAL_ERROR "Missing input parameter VERSION_C_CMAKEIN!")
207 if(${VERSION_C_OUT} STREQUAL "")
208 message(FATAL_ERROR "Missing input parameter VERSION_C_OUT!")
211 configure_file(${VERSION_C_CMAKEIN} ${VERSION_C_OUT})