1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
|
# add_git_dir_dependency(GIT_DIR SUCCESS_VAR)
#
# Adds a configure time dependency on the git directory such that if the HEAD
# of the git directory changes CMake will be forced to re-run. This useful
# for fetching the current git hash and including it in the build.
#
# `GIT_DOT_FILE` is the path to the git directory (i.e. the `.git` directory) or
# `.git` file used by a git worktree.
# `SUCCESS_VAR` is the name of the variable to set. It will be set to TRUE
# if the dependency was successfully added and FALSE otherwise.
function(add_git_dir_dependency GIT_DOT_FILE SUCCESS_VAR)
if (NOT "${ARGC}" EQUAL 2)
message(FATAL_ERROR "Invalid number (${ARGC}) of arguments")
endif()
if (NOT IS_ABSOLUTE "${GIT_DOT_FILE}")
message(FATAL_ERROR "GIT_DOT_FILE (\"${GIT_DOT_FILE}\") is not an absolute path")
endif()
if (NOT EXISTS "${GIT_DOT_FILE}")
message(FATAL_ERROR "GIT_DOT_FILE (\"${GIT_DOT_FILE}\") does not exist")
endif()
if (NOT IS_DIRECTORY "${GIT_DOT_FILE}")
# Might be a git worktree. In this case we need parse out the worktree
# git directory
file(READ "${GIT_DOT_FILE}" GIT_DOT_FILE_DATA LIMIT 512)
string(STRIP "${GIT_DOT_FILE_DATA}" GIT_DOT_FILE_DATA_STRIPPED)
if (GIT_DOT_FILE_DATA_STRIPPED MATCHES "^gitdir:[ ]*(.+)$")
# Git worktree
message(STATUS "Found git worktree")
set(GIT_WORKTREE_DIR "${CMAKE_MATCH_1}")
set(GIT_HEAD_FILE "${GIT_WORKTREE_DIR}/HEAD")
# Figure out where real git directory lives
set(GIT_COMMON_DIR_FILE "${GIT_WORKTREE_DIR}/commondir")
if (NOT EXISTS "${GIT_COMMON_DIR_FILE}")
get_filename_component(GIT_WORKTREE_PARENT "${GIT_WORKTREE_DIR}" DIRECTORY)
get_filename_component(GIT_WORKTREE_PARENT "${GIT_WORKTREE_PARENT}" NAME)
if (EXISTS "${Z3_SOURCE_DIR}/${GIT_HEAD_FILE}" AND EXISTS "${Z3_SOURCE_DIR}/${GIT_WORKTREE_DIR}")
# Z3 is a git submodule
set(GIT_HEAD_FILE "${Z3_SOURCE_DIR}/${GIT_HEAD_FILE}")
set(GIT_DIR "${Z3_SOURCE_DIR}/${GIT_WORKTREE_DIR}")
else()
message(FATAL_ERROR "Found git worktree dir but could not find \"${GIT_COMMON_DIR_FILE}\"")
endif()
else()
file(READ "${GIT_COMMON_DIR_FILE}" GIT_COMMON_DIR_FILE_DATA LIMIT 512)
string(STRIP "${GIT_COMMON_DIR_FILE_DATA}" GIT_COMMON_DIR_FILE_DATA_STRIPPED)
get_filename_component(GIT_DIR "${GIT_WORKTREE_DIR}/${GIT_COMMON_DIR_FILE_DATA_STRIPPED}" ABSOLUTE)
endif()
if (NOT IS_DIRECTORY "${GIT_DIR}")
message(FATAL_ERROR "Failed to compute path to git directory from git worktree")
endif()
else()
message(FATAL_ERROR "GIT_DOT_FILE (\"${GIT_DOT_FILE}\") is not a directory or a pointer to git worktree directory")
endif()
else()
# Just a normal `.git` directory
message(STATUS "Found simple git working directory")
set(GIT_HEAD_FILE "${GIT_DOT_FILE}/HEAD")
set(GIT_DIR "${GIT_DOT_FILE}")
endif()
message(STATUS "Found git directory \"${GIT_DIR}\"")
if (NOT EXISTS "${GIT_HEAD_FILE}")
message(AUTHOR_WARNING "Git head file \"${GIT_HEAD_FILE}\" cannot be found")
set(${SUCCESS_VAR} FALSE PARENT_SCOPE)
return()
endif()
# List of files in the git tree that CMake configuration should depend on
set(GIT_FILE_DEPS "${GIT_HEAD_FILE}")
# Examine the HEAD and workout what additional dependencies there are.
file(READ "${GIT_HEAD_FILE}" GIT_HEAD_DATA LIMIT 128)
string(STRIP "${GIT_HEAD_DATA}" GIT_HEAD_DATA_STRIPPED)
if (GIT_HEAD_DATA_STRIPPED MATCHES "^ref:[ ]*(.+)$")
# HEAD points at a reference.
set(GIT_REF "${CMAKE_MATCH_1}")
if (EXISTS "${GIT_DIR}/${GIT_REF}")
# Unpacked reference. The file contains the commit hash
# so add a dependency on this file so that if we stay on this
# reference (i.e. branch) but change commit CMake will be forced
# to reconfigure.
list(APPEND GIT_FILE_DEPS "${GIT_DIR}/${GIT_REF}")
elseif(EXISTS "${GIT_DIR}/packed-refs")
# The ref must be packed (see `man git-pack-refs`).
list(APPEND GIT_FILE_DEPS "${GIT_DIR}/packed-refs")
else()
# Fail
message(AUTHOR_WARNING "Unhandled git reference")
set(${SUCCESS_VAR} FALSE PARENT_SCOPE)
return()
endif()
else()
# Detached HEAD.
# No other dependencies needed
endif()
# FIXME:
# This is the directory we will copy (via `configure_file()`) git files
# into. This is a hack. It would be better to use the
# `CMAKE_CONFIGURE_DEPENDS` directory property but that feature is not
# available in CMake 2.8.12. So we use `configure_file()` to effectively
# do the same thing. When the source file to `configure_file()` changes
# it will trigger a re-run of CMake.
set(GIT_CMAKE_FILES_DIR "${CMAKE_CURRENT_BINARY_DIR}/git_cmake_files")
file(MAKE_DIRECTORY "${GIT_CMAKE_FILES_DIR}")
foreach (git_dependency ${GIT_FILE_DEPS})
message(STATUS "Adding git dependency \"${git_dependency}\"")
configure_file(
"${git_dependency}"
"${GIT_CMAKE_FILES_DIR}"
COPYONLY
)
endforeach()
set(${SUCCESS_VAR} TRUE PARENT_SCOPE)
endfunction()
# get_git_head_hash(GIT_DOT_FILE OUTPUT_VAR)
#
# Retrieve the current commit hash for a git working directory where
# `GIT_DOT_FILE` is the `.git` directory or `.git` pointer file in a git
# worktree in the root of the git working directory.
#
# `OUTPUT_VAR` should be the name of the variable to put the result in. If this
# function fails then either a fatal error will be raised or `OUTPUT_VAR` will
# contain a string with the suffix `NOTFOUND` which can be used in CMake `if()`
# commands.
function(get_git_head_hash GIT_DOT_FILE OUTPUT_VAR)
if (NOT "${ARGC}" EQUAL 2)
message(FATAL_ERROR "Invalid number of arguments")
endif()
if (NOT EXISTS "${GIT_DOT_FILE}")
message(FATAL_ERROR "\"${GIT_DOT_FILE}\" does not exist")
endif()
if (NOT IS_ABSOLUTE "${GIT_DOT_FILE}")
message(FATAL_ERROR \""${GIT_DOT_FILE}\" is not an absolute path")
endif()
find_package(Git)
# NOTE: Use `GIT_FOUND` rather than `Git_FOUND` which was only
# available in CMake >= 3.5
if (NOT GIT_FOUND)
set(${OUTPUT_VAR} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
get_filename_component(GIT_WORKING_DIR "${GIT_DOT_FILE}" DIRECTORY)
execute_process(
COMMAND
"${GIT_EXECUTABLE}"
"rev-parse"
"-q" # Quiet
"HEAD"
WORKING_DIRECTORY
"${GIT_WORKING_DIR}"
RESULT_VARIABLE
GIT_EXIT_CODE
OUTPUT_VARIABLE
Z3_GIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (NOT "${GIT_EXIT_CODE}" EQUAL 0)
message(WARNING "Failed to execute git")
set(${OUTPUT_VAR} NOTFOUND PARENT_SCOPE)
return()
endif()
set(${OUTPUT_VAR} "${Z3_GIT_HASH}" PARENT_SCOPE)
endfunction()
# get_git_head_describe(GIT_DOT_FILE OUTPUT_VAR)
#
# Retrieve the output of `git describe` for a git working directory where
# `GIT_DOT_FILE` is the `.git` directory or `.git` pointer file in a git
# worktree in the root of the git working directory.
#
# `OUTPUT_VAR` should be the name of the variable to put the result in. If this
# function fails then either a fatal error will be raised or `OUTPUT_VAR` will
# contain a string with the suffix `NOTFOUND` which can be used in CMake `if()`
# commands.
function(get_git_head_describe GIT_DOT_FILE OUTPUT_VAR)
if (NOT "${ARGC}" EQUAL 2)
message(FATAL_ERROR "Invalid number of arguments")
endif()
if (NOT EXISTS "${GIT_DOT_FILE}")
message(FATAL_ERROR "\"${GIT_DOT_FILE}\" does not exist")
endif()
if (NOT IS_ABSOLUTE "${GIT_DOT_FILE}")
message(FATAL_ERROR \""${GIT_DOT_FILE}\" is not an absolute path")
endif()
find_package(Git)
# NOTE: Use `GIT_FOUND` rather than `Git_FOUND` which was only
# available in CMake >= 3.5
if (NOT GIT_FOUND)
set(${OUTPUT_VAR} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
get_filename_component(GIT_WORKING_DIR "${GIT_DOT_FILE}" DIRECTORY)
execute_process(
COMMAND
"${GIT_EXECUTABLE}"
"describe"
"--long"
WORKING_DIRECTORY
"${GIT_WORKING_DIR}"
RESULT_VARIABLE
GIT_EXIT_CODE
OUTPUT_VARIABLE
Z3_GIT_DESCRIPTION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (NOT "${GIT_EXIT_CODE}" EQUAL 0)
message(WARNING "Failed to execute git")
set(${OUTPUT_VAR} NOTFOUND PARENT_SCOPE)
return()
endif()
set(${OUTPUT_VAR} "${Z3_GIT_DESCRIPTION}" PARENT_SCOPE)
endfunction()
|