Merge branch 'master' into rotation
[gromacs/adressmacs.git] / cmake / gmxGenerateVersionInfo.cmake
blobe1359cb968b54ec8262a1d34d8e5645ed4d0c5d1
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
19 # Output: 
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 
28
29 # Szilard Pall (pszilard@cbr.su.se) 
31 if(${PROJECT_VERSION} STREQUAL "")
32     message(FATAL_ERROR "PROJECT_VERSION undefined!")
33 endif()
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)
41 endif()
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")
46 endif()
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")
52     # refresh git index 
53     execute_process(COMMAND ${Git_EXECUTABLE} update-index -q --refresh
54         WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
55         TIMEOUT 5
56         OUTPUT_QUIET
57         ERROR_VARIABLE EXEC_ERR
58         OUTPUT_STRIP_TRAILING_WHITESPACE
59     ) 
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
67     )
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
77     )   
78     if(NOT ${SRC_LOCAL_CHANGES} STREQUAL "")
79         set(DIRTY_STR "-dirty")
80         set(GMX_GIT_HEAD_HASH "${GMX_GIT_HEAD_HASH} (dirty)")
81     endif()
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
92         )
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})
112     else()
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
119         )
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})
123     endif()
125     # compile the version string suffix
126     set(VERSION_STR_SUFFIX "${HEAD_DATE}-${HEAD_HASH_SHORT}${DIRTY_STR}") 
127     
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
135     )
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")        
141     else()         
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
149         )
150         string(REGEX REPLACE "\n" ";" ANCESTOR_LIST ${ANCESTOR_LIST})
152         set(AHEAD 0)
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
159             )
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)")
169                 break()
170             else()
171                 math(EXPR AHEAD ${AHEAD}+1)
172             endif()
173         endforeach(OBJ)
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") 
179         endif()
180     endif()
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}")
186 else()
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")
193 endif()
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)
205 else()
206     if(${VERSION_C_CMAKEIN} STREQUAL "")
207         message(FATAL_ERROR "Missing input parameter VERSION_C_CMAKEIN!")
208     endif()
209     if(${VERSION_C_OUT} STREQUAL "")
210         message(FATAL_ERROR "Missing input parameter VERSION_C_OUT!")
211     endif()
212     # generate version.c
213    configure_file(${VERSION_C_CMAKEIN} ${VERSION_C_OUT})    
214 endif()