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 # this should at some point become VERSION_LESS
51 if(EXISTS ${Git_EXECUTABLE} AND NOT Git_VERSION STRLESS "1.5.1")
53 execute_process(COMMAND ${Git_EXECUTABLE} update-index -q --refresh
54 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
57 ERROR_VARIABLE EXEC_ERR
58 OUTPUT_STRIP_TRAILING_WHITESPACE
61 # get the full hash of the current HEAD
62 execute_process(COMMAND ${Git_EXECUTABLE} rev-parse HEAD
63 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
64 OUTPUT_VARIABLE GMX_GIT_HEAD_HASH
65 ERROR_VARIABLE EXEC_ERR
66 OUTPUT_STRIP_TRAILING_WHITESPACE
68 # extract the shortened hash (7 char)
69 string(SUBSTRING ${GMX_GIT_HEAD_HASH} 0 5 HEAD_HASH_SHORT)
71 # if there are local uncommitted changes, the build gets labeled "dirty"
72 execute_process(COMMAND ${Git_EXECUTABLE} diff-index --name-only HEAD
73 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
74 OUTPUT_VARIABLE SRC_LOCAL_CHANGES
75 ERROR_VARIABLE EXEC_ERR
76 OUTPUT_STRIP_TRAILING_WHITESPACE
78 if(NOT ${SRC_LOCAL_CHANGES} STREQUAL "")
79 set(DIRTY_STR "-dirty")
80 set(GMX_GIT_HEAD_HASH "${GMX_GIT_HEAD_HASH} (dirty)")
83 # if git is older then 1.5.3 we need to extract the RFC2822 style date
84 # and massage it, otherwise the ISO 8601 format is more trusworthy
85 # this should at some point become VERSION_LESS
86 if (NOT Git_VERSION STREQUAL "" AND Git_VERSION STRLESS "1.5.3")
87 execute_process(COMMAND ${Git_EXECUTABLE} rev-list -n1 "--pretty=format:%cD" HEAD
88 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
89 OUTPUT_VARIABLE HEAD_DATE
90 ERROR_VARIABLE EXEC_ERR
91 OUTPUT_STRIP_TRAILING_WHITESPACE
93 # date format: day, D Mmm YYYY -> YYYY-MM-DD
94 # if the day is single sigit need to insert a "0"
95 string(REGEX REPLACE ".*(, )([0-9] )(.*)" "\\10\\2\\3"
96 HEAD_DATE ${HEAD_DATE})
97 string(REGEX REPLACE ".*, ([0-9][0-9]) ([A-Z][a-z]+) ([0-9]+).*" "\\3\\2\\1"
98 HEAD_DATE ${HEAD_DATE})
99 string(TOUPPER ${HEAD_DATE} HEAD_DATE)
100 string(REGEX REPLACE "JAN" "01" HEAD_DATE ${HEAD_DATE})
101 string(REGEX REPLACE "FEB" "02" HEAD_DATE ${HEAD_DATE})
102 string(REGEX REPLACE "MAR" "03" HEAD_DATE ${HEAD_DATE})
103 string(REGEX REPLACE "APR" "04" HEAD_DATE ${HEAD_DATE})
104 string(REGEX REPLACE "MAY" "05" HEAD_DATE ${HEAD_DATE})
105 string(REGEX REPLACE "JUN" "06" HEAD_DATE ${HEAD_DATE})
106 string(REGEX REPLACE "JUL" "07" HEAD_DATE ${HEAD_DATE})
107 string(REGEX REPLACE "AUG" "08" HEAD_DATE ${HEAD_DATE})
108 string(REGEX REPLACE "SEP" "09" HEAD_DATE ${HEAD_DATE})
109 string(REGEX REPLACE "OCT" "10" HEAD_DATE ${HEAD_DATE})
110 string(REGEX REPLACE "NOV" "11" HEAD_DATE ${HEAD_DATE})
111 string(REGEX REPLACE "DEC" "12" HEAD_DATE ${HEAD_DATE})
113 # get the date of the HEAD commit
114 execute_process(COMMAND ${Git_EXECUTABLE} rev-list -n1 "--pretty=format:%ci" HEAD
115 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
116 OUTPUT_VARIABLE HEAD_DATE
117 ERROR_VARIABLE EXEC_ERR
118 OUTPUT_STRIP_TRAILING_WHITESPACE
120 string(REGEX REPLACE "\n| " ";" HEAD_DATE ${HEAD_DATE})
121 list(GET HEAD_DATE 2 HEAD_DATE)
122 string(REGEX REPLACE "-" "" HEAD_DATE ${HEAD_DATE})
125 # compile the version string suffix
126 set(VERSION_STR_SUFFIX "${HEAD_DATE}-${HEAD_HASH_SHORT}${DIRTY_STR}")
128 # find the name of the remote which is located on the official gromacs git server
129 execute_process(COMMAND ${Git_EXECUTABLE} config --get-regexp
130 "remote\\..*\\.url" "git\\.gromacs\\.org[:|/]gromacs"
131 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
132 OUTPUT_VARIABLE GMX_REMOTE
133 ERROR_VARIABLE EXEC_ERR
134 OUTPUT_STRIP_TRAILING_WHITESPACE
136 # if there's a remote from the gromacs git, try to find ancestor commits of the
137 # current HEAD from this remote; otherwise, label the buld "unknown"
138 if(GMX_REMOTE STREQUAL "")
139 set(VERSION_STR_SUFFIX "${VERSION_STR_SUFFIX}-unknown")
140 set(GMX_GIT_REMOTE_HASH "unknown")
142 string(REGEX REPLACE "remote\\.(.*)\\.url.*" "\\1" GMX_REMOTE ${GMX_REMOTE})
143 # find the first ancestor in the list provided by rev-list (not
144 # necessarily the last though) which is in GMX_REMOTE, extract the
145 # hash and the number of commits HEAD is ahead with
146 execute_process(COMMAND ${Git_EXECUTABLE} rev-list --max-count=100 HEAD
147 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
148 OUTPUT_VARIABLE ANCESTOR_LIST
150 string(REGEX REPLACE "\n" ";" ANCESTOR_LIST ${ANCESTOR_LIST})
153 set(GMX_GIT_REMOTE_HASH "")
154 foreach(OBJ ${ANCESTOR_LIST})
155 execute_process(COMMAND ${Git_EXECUTABLE} name-rev --refs=refs/remotes/${GMX_REMOTE}/* ${OBJ}
156 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
157 OUTPUT_VARIABLE HASH_AND_REVNAME
158 OUTPUT_STRIP_TRAILING_WHITESPACE
160 string(REGEX REPLACE "\n" "" HASH_AND_REVNAME ${HASH_AND_REVNAME})
161 string(REGEX REPLACE " " ";" HASH_AND_REVNAME ${HASH_AND_REVNAME})
162 list(GET HASH_AND_REVNAME 0 GMX_GIT_REMOTE_HASH)
163 list(GET HASH_AND_REVNAME 1 REVNAME)
164 # stop and set the hash if we have a hit, otherwise loop and count
165 # how far ahead is the local repo
166 if(${REVNAME} MATCHES "remotes/${GMX_REMOTE}/.*")
167 set(GMX_GIT_REMOTE_HASH
168 "${GMX_GIT_REMOTE_HASH} (${AHEAD} newer local commits)")
171 math(EXPR AHEAD ${AHEAD}+1)
174 # mark the build "local" if didn't find any commits that are from
175 # remotes/${GMX_REMOTE}/*
176 if(${GMX_GIT_REMOTE_HASH} STREQUAL "")
177 set(GMX_GIT_REMOTE_HASH "unknown")
178 set(VERSION_STR_SUFFIX "${VERSION_STR_SUFFIX}-local")
182 # compile final version string, if there is already a -dev suffix in VER
183 # remove everything after this and replace it with the generated suffix
184 string(REGEX REPLACE "(.*)-dev.*" "\\1" VER ${VER})
185 set(GMX_PROJECT_VERSION_STR "${VER}-dev-${VERSION_STR_SUFFIX}")
187 # the version has to be defined - if not we're not using version.h/.c and set
188 # the GIT related information to "unknown"
189 message(WARNING " Source tree seems to be a repository, but no compatible git is available, using hard-coded version string")
190 set(GMX_PROJECT_VERSION_STR "${PROJECT_VERSION}")
191 set(GMX_GIT_HEAD_HASH "unknown")
192 set(GMX_GIT_REMOTE_HASH "unknown")
195 # if we're generating cache variables set these
196 # otherwise it's assumed that it's called in script mode to generate version.c
197 if(GEN_VERSION_INFO_INTERNAL)
198 set(GMX_PROJECT_VERSION_STR ${GMX_PROJECT_VERSION_STR}
199 CACHE STRING "Gromacs version string" FORCE)
200 set(GMX_GIT_HEAD_HASH ${GMX_GIT_HEAD_HASH}${DIRTY_STR}
201 CACHE STRING "Current git HEAD commit object" FORCE)
202 set(GMX_GIT_REMOTE_HASH ${GMX_GIT_REMOTE_HASH}
203 CACHE STRING "Commmit object of the nearest ancestor present in the Gromacs git repository" FORCE)
204 mark_as_advanced(GMX_GIT_HEAD_HASH GMX_GIT_REMOTE_HASH)
206 if(${VERSION_C_CMAKEIN} STREQUAL "")
207 message(FATAL_ERROR "Missing input parameter VERSION_C_CMAKEIN!")
209 if(${VERSION_C_OUT} STREQUAL "")
210 message(FATAL_ERROR "Missing input parameter VERSION_C_OUT!")
213 configure_file(${VERSION_C_CMAKEIN} ${VERSION_C_OUT})