Use CMake to propagate versions and hashes to gitlab jobs
[alexxy/gromacs.git] / cmake / gmxVersionInfo.cmake
index b92786de69fc6a9f5d50e32cc8944448dffa6722..24fc3e83c6062f1514688038026ce6c298d0d3e9 100644 (file)
@@ -1,7 +1,8 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2014,2015,2016,2017,2018,2019, by the GROMACS development team, led by
+# Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
+# Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
 # Sets version information variables and provides CMake functions for
 # generating files based on them
 #
-# This script provides the following basic version variables that need to be
-# maintained manually:
+# The following variables are derived from variables initialized by
+# https://cmake.org/cmake/help/latest/command/project.html#command:project
 #   GMX_VERSION_MAJOR      Major version number.
 #   GMX_VERSION_PATCH      Patch version number.
 #       Should always be defined: zero for, e.g., 2016.
+#
+# This script provides the following basic version variables that need to be
+# maintained manually:
 #   GMX_VERSION_SUFFIX     String suffix to add to numeric version string.
 #       "-dev" is automatically added when not building from a source package,
 #       and does not need to be kept here. This mechanism is not quite enough
@@ -57,6 +61,9 @@
 #         GROMACS     2016   2
 #         GROMACS     2018   3
 #         GROMACS     2019   4
+#         GROMACS     2020   5
+#         GROMACS     2021   6
+#         GROMACS     2022   7
 #   LIBRARY_SOVERSION_MINOR so minor version for the built libraries.
 #       Should be increased for each release that changes only the implementation.
 #       In GROMACS, the typical policy is to increase it for each patch version
 # The scripts gmxGenerateVersionInfo.cmake and gmxConfigureVersionInfo.cmake
 # are used internally by this machinery, as well as VersionInfo.cmake.cmakein.
 
+#####################################################################
+# Derived version info.
+# Ref https://cmake.org/cmake/help/latest/command/project.html#command:project
+set(GMX_VERSION_MAJOR ${Gromacs_VERSION_MAJOR})
+set(GMX_VERSION_PATCH ${Gromacs_VERSION_MINOR})
+
 #####################################################################
 # Manually maintained version info
 
-# The GROMACS convention is that these are the version number of the next
-# release that is going to be made from this branch.
-set(GMX_VERSION_MAJOR 2019)
-set(GMX_VERSION_PATCH 5)
-# The suffix, on the other hand, is used mainly for betas and release
+# The suffix is used mainly for betas and release
 # candidates, where it signifies the most recent such release from
 # this branch; it will be empty before the first such release, as well
 # as after the final release is out.
-set(GMX_VERSION_SUFFIX "")
+set(GMX_VERSION_SUFFIX "-beta1")
 
 # Conventionally with libtool, any ABI change must change the major
 # version number, the minor version number should change if it's just
@@ -211,7 +220,7 @@ set(GMX_VERSION_SUFFIX "")
 # here. The important thing is to minimize the chance of third-party
 # code being able to dynamically link with a version of libgromacs
 # that might not work.
-set(LIBRARY_SOVERSION_MAJOR 4)
+set(LIBRARY_SOVERSION_MAJOR 7)
 set(LIBRARY_SOVERSION_MINOR 0)
 set(LIBRARY_VERSION ${LIBRARY_SOVERSION_MAJOR}.${LIBRARY_SOVERSION_MINOR}.0)
 
@@ -224,41 +233,62 @@ else()
     set(GMX_VERSION "${GMX_VERSION_MAJOR}")
 endif()
 set(GMX_VERSION_STRING "${GMX_VERSION}${GMX_VERSION_SUFFIX}")
+
+set(REGRESSIONTEST_VERSION "${GMX_VERSION_STRING}")
+set(REGRESSIONTEST_BRANCH "master")
+# Follow the relevant part of the release checklist at
+# https://gitlab.com/gromacs/gromacs/-/wikis/Release-checklist#how-to-build-a-regressiontests-tarball
+# in order to have it build the regressiontests tarball with all the
+# right version naming. The version number and suffix goes into the
+# directory name within the regressiontests tarball, which affects the
+# md5sum of the tarball. The matching md5sum has to go here, and if it
+# isn't right the real release workflow will report a failure.
+set(REGRESSIONTEST_MD5SUM "9e122010c6e0fea35ec621a8e6561f7f" CACHE INTERNAL "MD5 sum of the regressiontests tarball for this GROMACS version")
+
+# If you are making a custom fork of GROMACS, please describe your
+# fork, perhaps with its version number, in the value of
+# GMX_VERSION_STRING_OF_FORK here. This string will appear in the
+# header of log files that mdrun writes. This will help you, your
+# users, your system administrators, your maintainers and the
+# maintainers of GROMACS core understand how to troubleshoot and
+# reproduce potential problems.
+#
+# If you are distributing a patch to GROMACS, then this change would
+# be great as part of your patch. Otherwise for personal use, you can
+# also just set a CMake cache variable.
+set(GMX_VERSION_STRING_OF_FORK "" CACHE INTERNAL
+    "Version string for forks of GROMACS to set to describe themselves")
+mark_as_advanced(GMX_VERSION_STRING_OF_FORK)
+if (GMX_VERSION_STRING_OF_FORK)
+    set(GMX_VERSION_STRING "${GMX_VERSION_STRING}-${GMX_VERSION_STRING_OF_FORK}")
+endif()
+
 option(GMX_BUILD_TARBALL "Build tarball without -dev version suffix" OFF)
 mark_as_advanced(GMX_BUILD_TARBALL)
-# If run with cmake -P, the -dev suffix is managed elsewhere.
 if (NOT SOURCE_IS_SOURCE_DISTRIBUTION AND
-    NOT GMX_BUILD_TARBALL AND
-    NOT CMAKE_SCRIPT_MODE_FILE)
+    NOT GMX_BUILD_TARBALL)
     set(GMX_VERSION_STRING "${GMX_VERSION_STRING}-dev")
 endif()
 
-set(REGRESSIONTEST_VERSION "${GMX_VERSION_STRING}")
-set(REGRESSIONTEST_BRANCH "refs/heads/release-2019")
-# Run the regressiontests packaging job with the correct pakage
-# version string, and the release box checked, in order to have it
-# build the regressiontests tarball with all the right naming. The
-# naming affects the md5sum that has to go here, and if it isn't right
-# release workflow will report a failure.
-set(REGRESSIONTEST_MD5SUM "6b12a3b6a32d21df03a76bb7866d0b23" CACHE INTERNAL "MD5 sum of the regressiontests tarball for this GROMACS version")
-
 math(EXPR GMX_VERSION_NUMERIC
      "${GMX_VERSION_MAJOR}*10000 + ${GMX_VERSION_PATCH}")
 set(GMX_API_VERSION ${GMX_VERSION_NUMERIC})
 
-# If run with cmake -P from releng scripts, print out necessary version info
-# as JSON.
-if (CMAKE_SCRIPT_MODE_FILE)
-    message("{ \"version\": \"${GMX_VERSION_STRING}\", \"regressiontest-md5sum\": \"${REGRESSIONTEST_MD5SUM}\" }")
-    return()
-endif()
-
 # Set those values only in release versions, after getting the identifiers
 # from Zenodo for the manual and source code
 # Has to be done by hand before every final release
 # Use force to override anything given as a cmake command line input
-set(GMX_MANUAL_DOI "" CACHE INTERNAL "reserved doi for GROMACS manual" FORCE)
-set(GMX_SOURCE_DOI "" CACHE INTERNAL "reserved doi for GROMACS source code" FORCE)
+# Actual input depends on the GMX_VERSION_STRING_OF_FORK variable being set or not.
+# If it is set, we always default to an empty string, otherwise to the value set for the release build.
+if (GMX_VERSION_STRING_OF_FORK)
+    set(GMX_MANUAL_DOI_INTERNAL "")
+    set(GMX_SOURCE_DOI_INTERNAL "")
+else()
+    set(GMX_MANUAL_DOI_INTERNAL "") # Set correct doi string here
+    set(GMX_SOURCE_DOI_INTERNAL "") # Set correct doi string here
+endif()
+set(GMX_MANUAL_DOI ${GMX_MANUAL_DOI_INTERNAL} CACHE INTERNAL "reserved doi for GROMACS manual" FORCE)
+set(GMX_SOURCE_DOI ${GMX_SOURCE_DOI_INTERNAL} CACHE INTERNAL "reserved doi for GROMACS source code" FORCE)
 
 #####################################################################
 # git version info management
@@ -292,7 +322,7 @@ if (GMX_GIT_VERSION_INFO)
 endif()
 
 include(gmxCustomCommandUtilities)
-
+include(FindPythonModule)
 # The first two are also for use outside this file, encapsulating the details
 # of how to use the generated VersionInfo.cmake.
 set(VERSION_INFO_CMAKE_FILE   ${PROJECT_BINARY_DIR}/VersionInfo.cmake)
@@ -301,6 +331,11 @@ set(VERSION_INFO_DEPS         ${VERSION_INFO_CMAKE_FILE})
 # the function below.
 set(VERSION_INFO_CMAKEIN_FILE     ${CMAKE_CURRENT_LIST_DIR}/VersionInfo.cmake.cmakein)
 set(VERSION_INFO_CONFIGURE_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/gmxConfigureVersionInfo.cmake)
+# A set of directories to scan for calculating the hash of source files.
+set(SET_OF_DIRECTORIES_TO_CHECKSUM  "src")
+list(APPEND SET_OF_DIRECTORIES_TO_CHECKSUM "python_packaging")
+# Due to the limitations for passing a list as arguments, we make the directories a string here
+string(REPLACE ";" ":" DIRECTORIES_TO_CHECKSUM_STRING "${SET_OF_DIRECTORIES_TO_CHECKSUM}")
 
 # Rules to create the VersionInfo.cmake file.
 # For git info, the sequence is:
@@ -328,18 +363,36 @@ set(VERSION_INFO_CONFIGURE_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/gmxConfigureVersionI
 #        - These are again custom commands that depend on the output from
 #          step 1, so they get regenerated only when the static version info
 #          changes.
+#
+# Note that VersionInfo-partial.cmake is also used to transfer version
+# information between GitLab CI jobs for release and documentation builds.
+
+# Check if we have all necessary python modules available
+if (Python3_Interpreter_FOUND)
+    set(HAVE_FULL_FUNCTIONING_PYTHON Python3_Interpreter_FOUND)
+    foreach(module argparse hashlib hmac os stat re) # add further modules if necessary
+        find_python_module(${module} QUIET)
+        string(TOUPPER ${module} module_upper)
+        if(NOT PYTHONMODULE_${module_upper})
+            message(STATUS
+                "Python module ${module} not found - disabling checksum validation")
+            unset(HAVE_FULL_FUNCTIONING_PYTHON)
+        endif()
+    endforeach()
+endif()
+
+# Configure information known at this time into a partially filled
+# version info file.
+set(VERSION_INFO_CMAKEIN_FILE_PARTIAL
+    ${PROJECT_BINARY_DIR}/VersionInfo-partial.cmake.cmakein)
+# Leave these to be substituted by the targets below.
+set(GMX_VERSION_STRING_FULL       "\@GMX_VERSION_STRING_FULL\@")
+
 if (GMX_GIT_VERSION_INFO)
-    # Configure information known at this time into a partially filled
-    # version info file.
-    set(VERSION_INFO_CMAKEIN_FILE_PARTIAL
-        ${PROJECT_BINARY_DIR}/VersionInfo-partial.cmake.cmakein)
     # Leave these to be substituted by the custom target below.
-    set(GMX_VERSION_STRING_FULL       "\@GMX_VERSION_STRING_FULL\@")
+    # Specific for building from git.
     set(GMX_VERSION_FULL_HASH         "\@GMX_VERSION_FULL_HASH\@")
     set(GMX_VERSION_CENTRAL_BASE_HASH "\@GMX_VERSION_CENTRAL_BASE_HASH\@")
-    configure_file(${VERSION_INFO_CMAKEIN_FILE}
-                   ${VERSION_INFO_CMAKEIN_FILE_PARTIAL}
-                   @ONLY)
     # If generating the version info, create a target that runs on every build
     # and does the actual git calls, storing the results into a CMake script.
     # This needs to be run at build time to update the version information
@@ -360,16 +413,66 @@ if (GMX_GIT_VERSION_INFO)
         COMMENT "Generating git version information")
     list(APPEND VERSION_INFO_DEPS git-version-info)
 else()
-    # If the version info is static, just generate the CMake script with the
-    # version variables during the CMake run.
-    set(GMX_VERSION_STRING_FULL       ${GMX_VERSION_STRING})
-    set(GMX_VERSION_FULL_HASH         "")
-    set(GMX_VERSION_CENTRAL_BASE_HASH "")
-    configure_file(${VERSION_INFO_CMAKEIN_FILE} ${VERSION_INFO_CMAKE_FILE})
+    # Leave these to be substituted by the custom target below.
+    # Specific for building from source tarball.
+    set(GMX_RELEASE_SOURCE_FILE_CHECKSUM "\@GMX_RELEASE_SOURCE_FILE_CHECKSUM\@")
+    set(GMX_CURRENT_SOURCE_FILE_CHECKSUM "\@GMX_CURRENT_SOURCE_FILE_CHECKSUM\@")
+    gmx_add_custom_output_target(release-version-info RUN_ALWAYS
+        OUTPUT ${VERSION_INFO_CMAKE_FILE}
+        COMMAND ${CMAKE_COMMAND}
+            -D PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}
+            -D HAVE_FULL_FUNCTIONING_PYTHON=${HAVE_FULL_FUNCTIONING_PYTHON}
+            -D PROJECT_VERSION=${GMX_VERSION_STRING}
+            -D PROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}
+            -D DIRECTORIES_TO_CHECKSUM=${DIRECTORIES_TO_CHECKSUM_STRING}
+            -D VERSION_CMAKEIN=${VERSION_INFO_CMAKEIN_FILE_PARTIAL}
+            -D VERSION_OUT=${VERSION_INFO_CMAKE_FILE}
+            -D VERSION_STRING_OF_FORK=${GMX_VERSION_STRING_OF_FORK}
+            -D SOURCE_IS_SOURCE_DISTRIBUTION=${SOURCE_IS_SOURCE_DISTRIBUTION}
+            -P ${CMAKE_CURRENT_LIST_DIR}/gmxGenerateVersionInfoWithoutGit.cmake
+        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+        COMMENT "Generating release version information")
+    list(APPEND VERSION_INFO_DEPS release-version-info)
 endif()
+configure_file(${VERSION_INFO_CMAKEIN_FILE}
+               ${VERSION_INFO_CMAKEIN_FILE_PARTIAL}
+               @ONLY)
 unset(GMX_VERSION_STRING_FULL)
 unset(GMX_VERSION_FULL_HASH)
 unset(GMX_VERSION_CENTRAL_BASE_HASH)
+unset(GMX_RELEASE_SOURCE_FILE_CHECKSUM)
+unset(GMX_CURRENT_SOURCE_FILE_CHECKSUM)
+
+
+# What file the checksum should be written to
+set(CHECKSUM_FILE "${PROJECT_SOURCE_DIR}/src/reference_checksum")
+
+# Target that allows checksumming a source tree when producing a tarball.
+# Allows verification of builds from the tarball to make sure the source had
+# not been tampered with.
+# Note: The RUN_ALWAYS here is to regenerate the hash file only, it does not
+# mean that the target is run in all builds
+if (HAVE_FULL_FUNCTIONING_PYTHON)
+    # We need the full path to the directories after passing it through
+    set(FULL_PATH_DIRECTORIES "")
+    foreach(DIR ${SET_OF_DIRECTORIES_TO_CHECKSUM})
+        list(APPEND FULL_PATH_DIRECTORIES "${PROJECT_SOURCE_DIR}/${DIR}")
+    endforeach()
+    gmx_add_custom_output_target(reference_checksum RUN_ALWAYS
+        OUTPUT ${CHECKSUM_FILE}
+        COMMAND ${PYTHON_EXECUTABLE}
+            ${PROJECT_SOURCE_DIR}/admin/createFileHash.py
+            -s ${FULL_PATH_DIRECTORIES}
+            -o ${CHECKSUM_FILE}
+        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+        COMMENT "Generating reference checksum of source files")
+else()
+    add_custom_target(reference_checksum
+        COMMAND ${CMAKE_COMMAND} -E echo
+        "Can not checksum files without python3 being available"
+        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+        COMMENT "Generating reference checksum of source files")
+endif()
 
 # The main user-visible interface to the machinery.
 # See documentation at the top of the script.