Remove cycle suppression
[gromacs.git] / cmake / gmxGenerateVersionInfo.cmake
blob9c64eb580c95588f6504df61123d2fce7e8947f7
2 # This file is part of the GROMACS molecular simulation package.
4 # Copyright (c) 2010,2011,2012,2013,2014, by the GROMACS development team, led by
5 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 # and including many others, as listed in the AUTHORS file in the
7 # top-level source directory and at http://www.gromacs.org.
9 # GROMACS is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU Lesser General Public License
11 # as published by the Free Software Foundation; either version 2.1
12 # of the License, or (at your option) any later version.
14 # GROMACS is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 # Lesser General Public License for more details.
19 # You should have received a copy of the GNU Lesser General Public
20 # License along with GROMACS; if not, see
21 # http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
24 # If you want to redistribute modifications to GROMACS, please
25 # consider that scientific software is very special. Version
26 # control is crucial - bugs must be traceable. We will be happy to
27 # consider code for inclusion in the official distribution, but
28 # derived work must not be called official GROMACS. Details are found
29 # in the README & COPYING files - if they are missing, get the
30 # official version at http://www.gromacs.org.
32 # To help us fund GROMACS development, we humbly ask that you cite
33 # the research papers on the package. Check out http://www.gromacs.org.
35 # Generate Gromacs development build version information.
37 # This script generates version information for a build from a development
38 # source tree based on git repository information.
39 # It is assumed that by default the script is run in cmake script mode.
40 # If *not* called in script mode but used in generating cache variables,
41 # GEN_VERSION_INFO_INTERNAL has to be set ON.
43 # The following variables have to be previously defined:
44 # GIT_EXECUTABLE         - path to git binary (must be >=1.5.3)
45 # PROJECT_VERSION        - hard-coded version string (generated info is appended)
46 # PROJECT_SOURCE_DIR     - top level source directory (which has to be in git)
47 # VERSION_CMAKEIN        - path to an input template file
48 # VERSION_OUT            - path to the output file
50 # Output:
51 # VERSION_OUT is configured from the input VERSION_CMAKEIN
52 # using the variables listed below.
54 # GMX_VERSION_STRING_FULL       - version string
55 # GMX_VERSION_FULL_HASH         - git hash of current local HEAD
56 # GMX_VERSION_CENTRAL_BASE_HASH - git hash of the first ancestor commit from the
57 #                                 main Gromacs repository
59 # Szilard Pall (pszilard@cbr.su.se)
60 # Teemu Murtola (teemu.murtola@gmail.com)
62 # Check input variables.
63 if("${PROJECT_VERSION}" STREQUAL "")
64     message(FATAL_ERROR "PROJECT_VERSION undefined!")
65 endif()
66 if (NOT EXISTS "${GIT_EXECUTABLE}")
67     message(FATAL_ERROR "Git executable is not set correctly")
68 endif()
69 if (NOT EXISTS "${PROJECT_SOURCE_DIR}/.git")
70     message(FATAL_ERROR "Project source directory ${PROJECT_SOURCE_DIR} not in git")
71 endif()
72 if ("${VERSION_CMAKEIN}" STREQUAL "")
73     message(FATAL_ERROR "Missing input parameter VERSION_CMAKEIN!")
74 endif()
75 if ("${VERSION_OUT}" STREQUAL "")
76     message(FATAL_ERROR "Missing input parameter VERSION_OUT!")
77 endif()
79 # refresh git index
80 execute_process(COMMAND ${GIT_EXECUTABLE} update-index -q --refresh
81     WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
82     TIMEOUT 5
83     OUTPUT_QUIET
84     ERROR_VARIABLE EXEC_ERR
85     OUTPUT_STRIP_TRAILING_WHITESPACE
88 # get the full hash of the current HEAD
89 execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
90     WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
91     OUTPUT_VARIABLE HEAD_HASH
92     ERROR_VARIABLE EXEC_ERR
93     OUTPUT_STRIP_TRAILING_WHITESPACE
95 set(GMX_VERSION_FULL_HASH ${HEAD_HASH})
97 # extract the shortened hash (7 char)
98 execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
99     WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
100     OUTPUT_VARIABLE HEAD_HASH_SHORT
101     ERROR_VARIABLE EXEC_ERR
102     OUTPUT_STRIP_TRAILING_WHITESPACE
105 # if there are local uncommitted changes, the build gets labeled "dirty"
106 execute_process(COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD
107     WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
108     OUTPUT_VARIABLE SRC_LOCAL_CHANGES
109     ERROR_VARIABLE EXEC_ERR
110     OUTPUT_STRIP_TRAILING_WHITESPACE
112 if(NOT "${SRC_LOCAL_CHANGES}" STREQUAL "")
113     set(DIRTY_STR "-dirty")
114     set(GMX_VERSION_FULL_HASH "${GMX_VERSION_FULL_HASH} (dirty)")
115 endif()
117 # get the date of the HEAD commit
118 execute_process(COMMAND ${GIT_EXECUTABLE} rev-list -n1 "--pretty=format:%ci" HEAD
119     WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
120     OUTPUT_VARIABLE HEAD_DATE
121     ERROR_VARIABLE EXEC_ERR
122     OUTPUT_STRIP_TRAILING_WHITESPACE
124 string(REGEX REPLACE "\n| " ";" HEAD_DATE "${HEAD_DATE}")
125 list(GET HEAD_DATE 2 HEAD_DATE)
126 string(REGEX REPLACE "-" "" HEAD_DATE "${HEAD_DATE}")
128 # compile the version string suffix
129 set(VERSION_STR_SUFFIX "${HEAD_DATE}-${HEAD_HASH_SHORT}${DIRTY_STR}")
131 # find the names of remotes that are located on the official gromacs
132 # git/gerrit servers
133 execute_process(COMMAND ${GIT_EXECUTABLE} config --get-regexp
134                 "remote\\..*\\.url" "\\.gromacs\\.org[:/].*gromacs(\\.git)?$"
135     WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
136     OUTPUT_VARIABLE GMX_REMOTES
137     ERROR_VARIABLE EXEC_ERR
138     OUTPUT_STRIP_TRAILING_WHITESPACE
141 # if there are remotes from the gromacs git servers, try to find ancestor
142 # commits of the current HEAD from this remote;
143 # otherwise, label the build "unknown"
144 if("${GMX_REMOTES}" STREQUAL "")
145     if (NOT DEFINED VERSION_NO_REMOTE_HASH)
146         set(VERSION_STR_SUFFIX "${VERSION_STR_SUFFIX}-unknown")
147     endif()
148     set(GMX_VERSION_CENTRAL_BASE_HASH "unknown")
149 else()
150     string(REPLACE "\n" ";" GMX_REMOTES ${GMX_REMOTES})
151     # construct a command pipeline that produces a reverse-time-ordered
152     # list of commits and their annotated names in GMX_REMOTES
153     # the max-count limit is there to put an upper bound on the execution time
154     set(BASEREVCOMMAND "COMMAND ${GIT_EXECUTABLE} rev-list --max-count=1000 HEAD")
155     foreach(REMOTE ${GMX_REMOTES})
156         string(REGEX REPLACE "remote\\.(.*)\\.url.*" "\\1" REMOTE ${REMOTE})
157         set(BASEREVCOMMAND "${BASEREVCOMMAND} COMMAND ${GIT_EXECUTABLE} name-rev --stdin --refs=refs/remotes/${REMOTE}/*")
158     endforeach(REMOTE)
159     # this is necessary for CMake to properly split the variable into
160     # parameters for execute_process().
161     string(REPLACE " " ";" BASEREVCOMMAND ${BASEREVCOMMAND})
162     # find the first ancestor in the list provided by rev-list (not
163     # necessarily the last though) which is in GMX_REMOTE, extract the
164     # hash and the number of commits HEAD is ahead with
165     execute_process(${BASEREVCOMMAND}
166         WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
167         OUTPUT_VARIABLE ANCESTOR_LIST
168     )
169     string(REGEX REPLACE "\n" ";" ANCESTOR_LIST "${ANCESTOR_LIST}")
171     set(AHEAD 0)
172     set(GMX_VERSION_CENTRAL_BASE_HASH "")
173     foreach(ANCESTOR ${ANCESTOR_LIST})
174         string(REPLACE "\n" "" HASH_AND_REVNAMES "${ANCESTOR}")
175         string(REPLACE " " ";" HASH_AND_REVNAMES "${HASH_AND_REVNAMES}")
176         list(LENGTH HASH_AND_REVNAMES COUNT)
177         # stop and set the hash if we have a hit, otherwise loop and count
178         # how far ahead is the local repo
179         if(COUNT GREATER 1)
180             LIST(GET HASH_AND_REVNAMES 0 GMX_VERSION_CENTRAL_BASE_HASH)
181             break()
182         endif()
183         math(EXPR AHEAD ${AHEAD}+1)
184     endforeach(ANCESTOR)
185     # mark the build "local" if didn't find any commits that are from
186     # remotes/${GMX_REMOTE}/*
187     if("${GMX_VERSION_CENTRAL_BASE_HASH}" STREQUAL "")
188         set(GMX_VERSION_CENTRAL_BASE_HASH "unknown")
189         set(VERSION_STR_SUFFIX "${VERSION_STR_SUFFIX}-local")
190     # don't print the remote hash if there are no local commits
191     elseif("${GMX_VERSION_CENTRAL_BASE_HASH}" STREQUAL "${HEAD_HASH}")
192         set(GMX_VERSION_CENTRAL_BASE_HASH "")
193     else()
194         set(GMX_VERSION_CENTRAL_BASE_HASH "${GMX_VERSION_CENTRAL_BASE_HASH} (${AHEAD} newer local commits)")
195     endif()
196 endif()
198 # Compile final version string.
199 set(GMX_VERSION_STRING_FULL "${PROJECT_VERSION}-${VERSION_STR_SUFFIX}")
201 # Generate the output file.
202 configure_file(${VERSION_CMAKEIN} ${VERSION_OUT})