Reorganize CMake version information management
[alexxy/gromacs.git] / cmake / gmxGenerateVersionInfo.cmake
index 8db1e10400d878cb679d0a653d8e271a7abe02e8..9c64eb580c95588f6504df61123d2fce7e8947f7 100644 (file)
 # PROJECT_SOURCE_DIR     - top level source directory (which has to be in git)
 # VERSION_CMAKEIN        - path to an input template file
 # VERSION_OUT            - path to the output file
-# VERSION_NO_REMOTE_HASH - if set, GMX_GIT_REMOTE_HASH is not generated
 #
 # Output:
-# i)  Script mode: VERSION_OUT is configured from the input VERSION_CMAKEIN
+# VERSION_OUT is configured from the input VERSION_CMAKEIN
 # using the variables listed below.
-# ii) Cache variable mode: the variables below are set in cache.
 #
-# GMX_PROJECT_VERSION_STR   - version string
-# GMX_GIT_HEAD_HASH         - git hash of current local HEAD
-# GMX_GIT_REMOTE_HASH       - git hash of the first ancestor commit from the
-#                             main Gromacs repository
+# GMX_VERSION_STRING_FULL       - version string
+# GMX_VERSION_FULL_HASH         - git hash of current local HEAD
+# GMX_VERSION_CENTRAL_BASE_HASH - git hash of the first ancestor commit from the
+#                                 main Gromacs repository
 #
 # Szilard Pall (pszilard@cbr.su.se)
 # Teemu Murtola (teemu.murtola@gmail.com)
 
+# Check input variables.
 if("${PROJECT_VERSION}" STREQUAL "")
     message(FATAL_ERROR "PROJECT_VERSION undefined!")
 endif()
-
-# if we're generating variables for cache unset the variables
-if(GEN_VERSION_INFO_INTERNAL)
-    set(GMX_PROJECT_VERSION_STR)
-    set(GMX_GIT_HEAD_HASH)
-    set(GMX_GIT_REMOTE_HASH)
+if (NOT EXISTS "${GIT_EXECUTABLE}")
+    message(FATAL_ERROR "Git executable is not set correctly")
 endif()
-
-# bail if the source tree is not in a git repository
-if(NOT EXISTS "${PROJECT_SOURCE_DIR}/.git")
+if (NOT EXISTS "${PROJECT_SOURCE_DIR}/.git")
     message(FATAL_ERROR "Project source directory ${PROJECT_SOURCE_DIR} not in git")
 endif()
+if ("${VERSION_CMAKEIN}" STREQUAL "")
+    message(FATAL_ERROR "Missing input parameter VERSION_CMAKEIN!")
+endif()
+if ("${VERSION_OUT}" STREQUAL "")
+    message(FATAL_ERROR "Missing input parameter VERSION_OUT!")
+endif()
 
-# If git executable exists, build the development version string.
-if(EXISTS "${GIT_EXECUTABLE}")
-    # refresh git index
-    execute_process(COMMAND ${GIT_EXECUTABLE} update-index -q --refresh
-        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
-        TIMEOUT 5
-        OUTPUT_QUIET
-        ERROR_VARIABLE EXEC_ERR
-        OUTPUT_STRIP_TRAILING_WHITESPACE
-    )
+# refresh git index
+execute_process(COMMAND ${GIT_EXECUTABLE} update-index -q --refresh
+    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+    TIMEOUT 5
+    OUTPUT_QUIET
+    ERROR_VARIABLE EXEC_ERR
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+)
 
-    # get the full hash of the current HEAD
-    execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
-        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
-        OUTPUT_VARIABLE HEAD_HASH
-        ERROR_VARIABLE EXEC_ERR
-        OUTPUT_STRIP_TRAILING_WHITESPACE
-    )
-    set(GMX_GIT_HEAD_HASH ${HEAD_HASH})
-    # extract the shortened hash (7 char)
-    execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
-        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
-        OUTPUT_VARIABLE HEAD_HASH_SHORT
-        ERROR_VARIABLE EXEC_ERR
-        OUTPUT_STRIP_TRAILING_WHITESPACE
-    )
+# get the full hash of the current HEAD
+execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
+    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+    OUTPUT_VARIABLE HEAD_HASH
+    ERROR_VARIABLE EXEC_ERR
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+set(GMX_VERSION_FULL_HASH ${HEAD_HASH})
 
-    # if there are local uncommitted changes, the build gets labeled "dirty"
-    execute_process(COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD
-        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
-        OUTPUT_VARIABLE SRC_LOCAL_CHANGES
-        ERROR_VARIABLE EXEC_ERR
-        OUTPUT_STRIP_TRAILING_WHITESPACE
-    )
-    if(NOT "${SRC_LOCAL_CHANGES}" STREQUAL "")
-        set(DIRTY_STR "-dirty")
-        set(GMX_GIT_HEAD_HASH "${GMX_GIT_HEAD_HASH} (dirty)")
-    endif()
+# extract the shortened hash (7 char)
+execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
+    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+    OUTPUT_VARIABLE HEAD_HASH_SHORT
+    ERROR_VARIABLE EXEC_ERR
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+)
 
-    # get the date of the HEAD commit
-    execute_process(COMMAND ${GIT_EXECUTABLE} rev-list -n1 "--pretty=format:%ci" HEAD
-        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
-        OUTPUT_VARIABLE HEAD_DATE
-        ERROR_VARIABLE EXEC_ERR
-        OUTPUT_STRIP_TRAILING_WHITESPACE
-    )
-    string(REGEX REPLACE "\n| " ";" HEAD_DATE "${HEAD_DATE}")
-    list(GET HEAD_DATE 2 HEAD_DATE)
-    string(REGEX REPLACE "-" "" HEAD_DATE "${HEAD_DATE}")
+# if there are local uncommitted changes, the build gets labeled "dirty"
+execute_process(COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD
+    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+    OUTPUT_VARIABLE SRC_LOCAL_CHANGES
+    ERROR_VARIABLE EXEC_ERR
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+if(NOT "${SRC_LOCAL_CHANGES}" STREQUAL "")
+    set(DIRTY_STR "-dirty")
+    set(GMX_VERSION_FULL_HASH "${GMX_VERSION_FULL_HASH} (dirty)")
+endif()
 
-    # compile the version string suffix
-    set(VERSION_STR_SUFFIX "${HEAD_DATE}-${HEAD_HASH_SHORT}${DIRTY_STR}")
+# get the date of the HEAD commit
+execute_process(COMMAND ${GIT_EXECUTABLE} rev-list -n1 "--pretty=format:%ci" HEAD
+    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+    OUTPUT_VARIABLE HEAD_DATE
+    ERROR_VARIABLE EXEC_ERR
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+string(REGEX REPLACE "\n| " ";" HEAD_DATE "${HEAD_DATE}")
+list(GET HEAD_DATE 2 HEAD_DATE)
+string(REGEX REPLACE "-" "" HEAD_DATE "${HEAD_DATE}")
 
-    if (DEFINED VERSION_NO_REMOTE_HASH)
-        set(GMX_REMOTES "")
-    else()
-        # find the names of remotes that are located on the official gromacs
-        # git/gerrit servers
-        execute_process(COMMAND ${GIT_EXECUTABLE} config --get-regexp
-                        "remote\\..*\\.url" "\\.gromacs\\.org[:/].*gromacs(\\.git)?$"
-            WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
-            OUTPUT_VARIABLE GMX_REMOTES
-            ERROR_VARIABLE EXEC_ERR
-            OUTPUT_STRIP_TRAILING_WHITESPACE
-        )
-    endif()
+# compile the version string suffix
+set(VERSION_STR_SUFFIX "${HEAD_DATE}-${HEAD_HASH_SHORT}${DIRTY_STR}")
 
-    # if there are remotes from the gromacs git servers, try to find ancestor
-    # commits of the current HEAD from this remote;
-    # otherwise, label the build "unknown"
-    if("${GMX_REMOTES}" STREQUAL "")
-        if (NOT DEFINED VERSION_NO_REMOTE_HASH)
-            set(VERSION_STR_SUFFIX "${VERSION_STR_SUFFIX}-unknown")
-        endif()
-        set(GMX_GIT_REMOTE_HASH "unknown")
-    else()
-        string(REPLACE "\n" ";" GMX_REMOTES ${GMX_REMOTES})
-        # construct a command pipeline that produces a reverse-time-ordered
-        # list of commits and their annotated names in GMX_REMOTES
-        # the max-count limit is there to put an upper bound on the execution time
-        set(BASEREVCOMMAND "COMMAND ${GIT_EXECUTABLE} rev-list --max-count=1000 HEAD")
-        foreach(REMOTE ${GMX_REMOTES})
-            string(REGEX REPLACE "remote\\.(.*)\\.url.*" "\\1" REMOTE ${REMOTE})
-            set(BASEREVCOMMAND "${BASEREVCOMMAND} COMMAND ${GIT_EXECUTABLE} name-rev --stdin --refs=refs/remotes/${REMOTE}/*")
-        endforeach(REMOTE)
-        # this is necessary for CMake to properly split the variable into
-        # parameters for execute_process().
-        string(REPLACE " " ";" BASEREVCOMMAND ${BASEREVCOMMAND})
-        # find the first ancestor in the list provided by rev-list (not
-        # necessarily the last though) which is in GMX_REMOTE, extract the
-        # hash and the number of commits HEAD is ahead with
-        execute_process(${BASEREVCOMMAND}
-            WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
-            OUTPUT_VARIABLE ANCESTOR_LIST
-        )
-        string(REGEX REPLACE "\n" ";" ANCESTOR_LIST "${ANCESTOR_LIST}")
+# find the names of remotes that are located on the official gromacs
+# git/gerrit servers
+execute_process(COMMAND ${GIT_EXECUTABLE} config --get-regexp
+                "remote\\..*\\.url" "\\.gromacs\\.org[:/].*gromacs(\\.git)?$"
+    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+    OUTPUT_VARIABLE GMX_REMOTES
+    ERROR_VARIABLE EXEC_ERR
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+)
 
-        set(AHEAD 0)
-        set(GMX_GIT_REMOTE_HASH "")
-        foreach(ANCESTOR ${ANCESTOR_LIST})
-            string(REPLACE "\n" "" HASH_AND_REVNAMES "${ANCESTOR}")
-            string(REPLACE " " ";" HASH_AND_REVNAMES "${HASH_AND_REVNAMES}")
-            list(LENGTH HASH_AND_REVNAMES COUNT)
-            # stop and set the hash if we have a hit, otherwise loop and count
-            # how far ahead is the local repo
-            if(COUNT GREATER 1)
-                LIST(GET HASH_AND_REVNAMES 0 GMX_GIT_REMOTE_HASH)
-                break()
-            endif()
-            math(EXPR AHEAD ${AHEAD}+1)
-        endforeach(ANCESTOR)
-        # mark the build "local" if didn't find any commits that are from
-        # remotes/${GMX_REMOTE}/*
-        if("${GMX_GIT_REMOTE_HASH}" STREQUAL "")
-            set(GMX_GIT_REMOTE_HASH "unknown")
-            set(VERSION_STR_SUFFIX "${VERSION_STR_SUFFIX}-local")
-        # don't print the remote hash if there are no local commits
-        elseif("${GMX_GIT_REMOTE_HASH}" STREQUAL "${HEAD_HASH}")
-            set(GMX_GIT_REMOTE_HASH "")
-        else()
-            set(GMX_GIT_REMOTE_HASH "${GMX_GIT_REMOTE_HASH} (${AHEAD} newer local commits)")
-        endif()
+# if there are remotes from the gromacs git servers, try to find ancestor
+# commits of the current HEAD from this remote;
+# otherwise, label the build "unknown"
+if("${GMX_REMOTES}" STREQUAL "")
+    if (NOT DEFINED VERSION_NO_REMOTE_HASH)
+        set(VERSION_STR_SUFFIX "${VERSION_STR_SUFFIX}-unknown")
     endif()
-
-    # compile final version string
-    set(GMX_PROJECT_VERSION_STR "${PROJECT_VERSION}-${VERSION_STR_SUFFIX}")
+    set(GMX_VERSION_CENTRAL_BASE_HASH "unknown")
 else()
-    # the version has to be defined
-    # set the GIT related information to "unknown"
-    message(WARNING "Source tree seems to be a repository, but no compatible git is available, using hard-coded version string")
-    set(GMX_PROJECT_VERSION_STR "${PROJECT_VERSION}")
-    set(GMX_GIT_HEAD_HASH "unknown")
-    set(GMX_GIT_REMOTE_HASH "unknown")
-endif()
+    string(REPLACE "\n" ";" GMX_REMOTES ${GMX_REMOTES})
+    # construct a command pipeline that produces a reverse-time-ordered
+    # list of commits and their annotated names in GMX_REMOTES
+    # the max-count limit is there to put an upper bound on the execution time
+    set(BASEREVCOMMAND "COMMAND ${GIT_EXECUTABLE} rev-list --max-count=1000 HEAD")
+    foreach(REMOTE ${GMX_REMOTES})
+        string(REGEX REPLACE "remote\\.(.*)\\.url.*" "\\1" REMOTE ${REMOTE})
+        set(BASEREVCOMMAND "${BASEREVCOMMAND} COMMAND ${GIT_EXECUTABLE} name-rev --stdin --refs=refs/remotes/${REMOTE}/*")
+    endforeach(REMOTE)
+    # this is necessary for CMake to properly split the variable into
+    # parameters for execute_process().
+    string(REPLACE " " ";" BASEREVCOMMAND ${BASEREVCOMMAND})
+    # find the first ancestor in the list provided by rev-list (not
+    # necessarily the last though) which is in GMX_REMOTE, extract the
+    # hash and the number of commits HEAD is ahead with
+    execute_process(${BASEREVCOMMAND}
+        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+        OUTPUT_VARIABLE ANCESTOR_LIST
+    )
+    string(REGEX REPLACE "\n" ";" ANCESTOR_LIST "${ANCESTOR_LIST}")
 
-# if we're generating cache variables set these
-# otherwise it's assumed that it's called in script mode to generate a file
-if(GEN_VERSION_INFO_INTERNAL)
-    set(GMX_PROJECT_VERSION_STR ${GMX_PROJECT_VERSION_STR}
-        CACHE STRING "Gromacs version string" FORCE)
-    set(GMX_GIT_HEAD_HASH ${GMX_GIT_HEAD_HASH}${DIRTY_STR}
-        CACHE STRING "Current git HEAD commit object" FORCE)
-    set(GMX_GIT_REMOTE_HASH ${GMX_GIT_REMOTE_HASH}
-        CACHE STRING "Commmit object of the nearest ancestor present in the Gromacs git repository" FORCE)
-    mark_as_advanced(GMX_GIT_HEAD_HASH GMX_GIT_REMOTE_HASH)
-else()
-    if("${VERSION_CMAKEIN}" STREQUAL "")
-        message(FATAL_ERROR "Missing input parameter VERSION_CMAKEIN!")
-    endif()
-    if("${VERSION_OUT}" STREQUAL "")
-        message(FATAL_ERROR "Missing input parameter VERSION_OUT!")
+    set(AHEAD 0)
+    set(GMX_VERSION_CENTRAL_BASE_HASH "")
+    foreach(ANCESTOR ${ANCESTOR_LIST})
+        string(REPLACE "\n" "" HASH_AND_REVNAMES "${ANCESTOR}")
+        string(REPLACE " " ";" HASH_AND_REVNAMES "${HASH_AND_REVNAMES}")
+        list(LENGTH HASH_AND_REVNAMES COUNT)
+        # stop and set the hash if we have a hit, otherwise loop and count
+        # how far ahead is the local repo
+        if(COUNT GREATER 1)
+            LIST(GET HASH_AND_REVNAMES 0 GMX_VERSION_CENTRAL_BASE_HASH)
+            break()
+        endif()
+        math(EXPR AHEAD ${AHEAD}+1)
+    endforeach(ANCESTOR)
+    # mark the build "local" if didn't find any commits that are from
+    # remotes/${GMX_REMOTE}/*
+    if("${GMX_VERSION_CENTRAL_BASE_HASH}" STREQUAL "")
+        set(GMX_VERSION_CENTRAL_BASE_HASH "unknown")
+        set(VERSION_STR_SUFFIX "${VERSION_STR_SUFFIX}-local")
+    # don't print the remote hash if there are no local commits
+    elseif("${GMX_VERSION_CENTRAL_BASE_HASH}" STREQUAL "${HEAD_HASH}")
+        set(GMX_VERSION_CENTRAL_BASE_HASH "")
+    else()
+        set(GMX_VERSION_CENTRAL_BASE_HASH "${GMX_VERSION_CENTRAL_BASE_HASH} (${AHEAD} newer local commits)")
     endif()
-    # Generate the output file.
-    configure_file(${VERSION_CMAKEIN} ${VERSION_OUT})
 endif()
+
+# Compile final version string.
+set(GMX_VERSION_STRING_FULL "${PROJECT_VERSION}-${VERSION_STR_SUFFIX}")
+
+# Generate the output file.
+configure_file(${VERSION_CMAKEIN} ${VERSION_OUT})