GenerateBuildInfo.cmake raw

   1  # Copyright (c) 2023-present The Limenka developers
   2  # Distributed under the MIT software license, see the accompanying
   3  # file COPYING or https://opensource.org/license/mit/.
   4  
   5  macro(fatal_error)
   6    message(FATAL_ERROR "\n"
   7      "Usage:\n"
   8      "  cmake -D BUILD_INFO_HEADER_PATH=<path> [-D SOURCE_DIR=<path>] -P ${CMAKE_CURRENT_LIST_FILE}\n"
   9      "All specified paths must be absolute ones.\n"
  10    )
  11  endmacro()
  12  
  13  if(DEFINED BUILD_INFO_HEADER_PATH AND IS_ABSOLUTE "${BUILD_INFO_HEADER_PATH}")
  14    if(EXISTS "${BUILD_INFO_HEADER_PATH}")
  15      file(STRINGS ${BUILD_INFO_HEADER_PATH} INFO LIMIT_COUNT 1)
  16    endif()
  17  else()
  18    unset(INFO)
  19    set(BUILD_INFO_HEADER_PATH "/dev/stdout")
  20  endif()
  21  
  22  if(DEFINED SOURCE_DIR)
  23    if(IS_ABSOLUTE "${SOURCE_DIR}" AND IS_DIRECTORY "${SOURCE_DIR}")
  24      set(WORKING_DIR ${SOURCE_DIR})
  25    else()
  26      fatal_error()
  27    endif()
  28  else()
  29    set(WORKING_DIR ${CMAKE_CURRENT_SOURCE_DIR})
  30  endif()
  31  
  32  set(GIT_TAG)
  33  set(GIT_COMMIT)
  34  if(NOT "$ENV{LIMENKA_GENBUILD_NO_GIT}" STREQUAL "1")
  35    find_package(Git QUIET)
  36    if(Git_FOUND)
  37      execute_process(
  38        COMMAND ${GIT_EXECUTABLE} rev-parse --is-inside-work-tree
  39        WORKING_DIRECTORY ${WORKING_DIR}
  40        OUTPUT_VARIABLE IS_INSIDE_WORK_TREE
  41        OUTPUT_STRIP_TRAILING_WHITESPACE
  42        ERROR_QUIET
  43      )
  44      if(IS_INSIDE_WORK_TREE)
  45        # This check ensures that we are actually part of the intended git repository, and not just getting info about some unrelated git repository that the code happens to be in a directory under
  46        execute_process(
  47          COMMAND ${GIT_EXECUTABLE} status --porcelain -uall --ignored cmake/script/GenerateBuildInfo.cmake
  48          WORKING_DIRECTORY ${WORKING_DIR}
  49          RESULT_VARIABLE SCRIPT_STATUS_EXITCODE
  50          OUTPUT_VARIABLE SCRIPT_STATUS
  51          OUTPUT_STRIP_TRAILING_WHITESPACE
  52          ERROR_QUIET
  53        )
  54        if(SCRIPT_STATUS_EXITCODE)
  55          set(IS_INSIDE_WORK_TREE 0)
  56        elseif(SCRIPT_STATUS MATCHES "\\?")
  57          set(IS_INSIDE_WORK_TREE 0)
  58        endif()
  59      endif()
  60      if(IS_INSIDE_WORK_TREE)
  61        # Clean 'dirty' status of touched files that haven't been modified.
  62        execute_process(
  63          COMMAND ${GIT_EXECUTABLE} diff
  64          WORKING_DIRECTORY ${WORKING_DIR}
  65          OUTPUT_QUIET
  66          ERROR_QUIET
  67        )
  68  
  69        execute_process(
  70          COMMAND ${GIT_EXECUTABLE} describe --abbrev=0
  71          WORKING_DIRECTORY ${WORKING_DIR}
  72          OUTPUT_VARIABLE MOST_RECENT_TAG
  73          OUTPUT_STRIP_TRAILING_WHITESPACE
  74          ERROR_QUIET
  75        )
  76  
  77        execute_process(
  78          COMMAND ${GIT_EXECUTABLE} rev-list -1 ${MOST_RECENT_TAG}
  79          WORKING_DIRECTORY ${WORKING_DIR}
  80          OUTPUT_VARIABLE MOST_RECENT_TAG_COMMIT
  81          OUTPUT_STRIP_TRAILING_WHITESPACE
  82          ERROR_QUIET
  83        )
  84  
  85        execute_process(
  86          COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
  87          WORKING_DIRECTORY ${WORKING_DIR}
  88          OUTPUT_VARIABLE HEAD_COMMIT
  89          OUTPUT_STRIP_TRAILING_WHITESPACE
  90          ERROR_QUIET
  91        )
  92  
  93        execute_process(
  94          COMMAND ${GIT_EXECUTABLE} diff-index --quiet HEAD --
  95          WORKING_DIRECTORY ${WORKING_DIR}
  96          RESULT_VARIABLE IS_DIRTY
  97        )
  98  
  99        if(HEAD_COMMIT STREQUAL MOST_RECENT_TAG_COMMIT AND NOT IS_DIRTY)
 100          # If latest commit is tagged and not dirty, then use the tag name.
 101          set(GIT_TAG ${MOST_RECENT_TAG})
 102        else()
 103          # Otherwise, generate suffix from git, i.e. string like "0e0a5173fae3-dirty".
 104          execute_process(
 105            COMMAND ${GIT_EXECUTABLE} rev-parse --short=12 HEAD
 106            WORKING_DIRECTORY ${WORKING_DIR}
 107            OUTPUT_VARIABLE GIT_COMMIT
 108            OUTPUT_STRIP_TRAILING_WHITESPACE
 109            ERROR_QUIET
 110          )
 111          if(IS_DIRTY)
 112            string(APPEND GIT_COMMIT "-dirty")
 113          endif()
 114        endif()
 115      endif()
 116    endif()
 117  endif()
 118  
 119  if(GIT_TAG)
 120    set(NEWINFO "#define BUILD_GIT_TAG \"${GIT_TAG}\"")
 121  elseif(GIT_COMMIT)
 122    set(NEWINFO "#define BUILD_GIT_COMMIT \"${GIT_COMMIT}\"")
 123  else()
 124    # NOTE: The NEWINFO line below this comment gets replaced by a string-match in contrib/guix/libexec/make_release_tarball.sh
 125    # If changing it, update the script too!
 126    set(NEWINFO [[// No build information available]])
 127  endif()
 128  
 129  # Only update the header if necessary.
 130  if(NOT "${INFO}" STREQUAL "${NEWINFO}")
 131    file(WRITE ${BUILD_INFO_HEADER_PATH} "${NEWINFO}\n")
 132  endif()
 133