GenerateBuildInfo.cmake raw

   1  # Copyright (c) 2023-present The Bitcoin Core 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 GIT_EXECUTABLE=<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    fatal_error()
  19  endif()
  20  
  21  if(DEFINED SOURCE_DIR)
  22    if(IS_ABSOLUTE "${SOURCE_DIR}" AND IS_DIRECTORY "${SOURCE_DIR}")
  23      set(WORKING_DIR ${SOURCE_DIR})
  24    else()
  25      fatal_error()
  26    endif()
  27  else()
  28    set(WORKING_DIR ${CMAKE_CURRENT_SOURCE_DIR})
  29  endif()
  30  
  31  set(GIT_TAG "")
  32  set(GIT_COMMIT "")
  33  if(GIT_EXECUTABLE)
  34    execute_process(
  35      COMMAND ${GIT_EXECUTABLE} rev-parse --is-inside-work-tree
  36      WORKING_DIRECTORY ${WORKING_DIR}
  37      OUTPUT_VARIABLE IS_INSIDE_WORK_TREE
  38      OUTPUT_STRIP_TRAILING_WHITESPACE
  39      ERROR_QUIET
  40    )
  41    if(IS_INSIDE_WORK_TREE)
  42      # Clean 'dirty' status of touched files that haven't been modified.
  43      execute_process(
  44        COMMAND ${GIT_EXECUTABLE} diff
  45        WORKING_DIRECTORY ${WORKING_DIR}
  46        OUTPUT_QUIET
  47        ERROR_QUIET
  48      )
  49  
  50      execute_process(
  51        COMMAND ${GIT_EXECUTABLE} describe --abbrev=0
  52        WORKING_DIRECTORY ${WORKING_DIR}
  53        OUTPUT_VARIABLE MOST_RECENT_TAG
  54        OUTPUT_STRIP_TRAILING_WHITESPACE
  55        ERROR_QUIET
  56      )
  57  
  58      execute_process(
  59        COMMAND ${GIT_EXECUTABLE} rev-list -1 ${MOST_RECENT_TAG}
  60        WORKING_DIRECTORY ${WORKING_DIR}
  61        OUTPUT_VARIABLE MOST_RECENT_TAG_COMMIT
  62        OUTPUT_STRIP_TRAILING_WHITESPACE
  63        ERROR_QUIET
  64      )
  65  
  66      execute_process(
  67        COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
  68        WORKING_DIRECTORY ${WORKING_DIR}
  69        OUTPUT_VARIABLE HEAD_COMMIT
  70        OUTPUT_STRIP_TRAILING_WHITESPACE
  71        ERROR_QUIET
  72      )
  73  
  74      execute_process(
  75        COMMAND ${GIT_EXECUTABLE} diff-index --quiet HEAD --
  76        WORKING_DIRECTORY ${WORKING_DIR}
  77        RESULT_VARIABLE IS_DIRTY
  78      )
  79  
  80      if(HEAD_COMMIT STREQUAL MOST_RECENT_TAG_COMMIT AND NOT IS_DIRTY)
  81        # If latest commit is tagged and not dirty, then use the tag name.
  82        set(GIT_TAG ${MOST_RECENT_TAG})
  83      else()
  84        # Otherwise, generate suffix from git, i.e. string like "0e0a5173fae3-dirty".
  85        execute_process(
  86          COMMAND ${GIT_EXECUTABLE} rev-parse --short=12 HEAD
  87          WORKING_DIRECTORY ${WORKING_DIR}
  88          OUTPUT_VARIABLE GIT_COMMIT
  89          OUTPUT_STRIP_TRAILING_WHITESPACE
  90          ERROR_QUIET
  91        )
  92        if(IS_DIRTY)
  93          string(APPEND GIT_COMMIT "-dirty")
  94        endif()
  95      endif()
  96    endif()
  97  endif()
  98  
  99  if(GIT_TAG)
 100    set(NEWINFO "#define BUILD_GIT_TAG \"${GIT_TAG}\"")
 101  elseif(GIT_COMMIT)
 102    set(NEWINFO "#define BUILD_GIT_COMMIT \"${GIT_COMMIT}\"")
 103  else()
 104    set(NEWINFO "// No build information available")
 105  endif()
 106  
 107  # Only update the header if necessary.
 108  if(NOT "${INFO}" STREQUAL "${NEWINFO}")
 109    file(WRITE ${BUILD_INFO_HEADER_PATH} "${NEWINFO}\n")
 110  endif()
 111