1# SPDX-License-Identifier: BSD-3-Clause 2 3# Generates header for which version is taken from (in order of precedence): 4# 1) .tarball-version file 5# 2) git 6# 7# Version is checked during configuration step and for every target 8# that has check_version_h target as dependency 9 10cmake_minimum_required(VERSION 3.13) 11 12set(VERSION_CMAKE_PATH ${CMAKE_CURRENT_LIST_DIR}/version.cmake) 13 14 15# In an ideal world, every CI engine records the most basic and most 16# important information: 17# - current date and time 18# - git version of the pull request 19# - git version of the moving branch it's being merged with 20# 21# In the real world, some CI results use a random timezone without 22# telling which one or don't provide any time at all. 23string(TIMESTAMP build_start_time UTC) 24message(STATUS "SOF version.cmake starting at ${build_start_time} UTC") 25 26# Most CI engines test a temporary merge of the pull request with a 27# moving target: the latest target branch. In that case the HEAD SHA is 28# very volatile and the --parents are much more relevant and useful. 29# 30# --no-abbrev-commit because some git servers like github allow fetching 31# by full length SHA (others forbid this entirely, see last page of 32# `git help fetch-pack`) 33message(STATUS "${SOF_ROOT_SOURCE_DIRECTORY} is at git commit with parent(s):") 34# Note execute_process() failures are ignored by default (missing git...) 35execute_process( 36 COMMAND git -C "${SOF_ROOT_SOURCE_DIRECTORY}" 37 log --parents --no-abbrev-commit --decorate -n 1 HEAD 38 ) 39 40 41# Don't confuse this manual _input_ file with the other, output file of 42# the same name auto-generated in the top _build_ directory by "make 43# dist", see dist.cmake 44set(TARBALL_VERSION_FILE_NAME ".tarball-version") 45 46set(TARBALL_VERSION_SOURCE_PATH "${SOF_ROOT_SOURCE_DIRECTORY}/${TARBALL_VERSION_FILE_NAME}") 47 48if(EXISTS ${TARBALL_VERSION_SOURCE_PATH}) 49 file(STRINGS ${TARBALL_VERSION_SOURCE_PATH} lines ENCODING "UTF-8") 50 list(GET lines 0 GIT_TAG) 51 list(GET lines 1 GIT_LOG_HASH) 52 message(STATUS "Found ${TARBALL_VERSION_SOURCE_PATH}") 53else() 54 # execute_process() errors are not fatal by default! 55 execute_process( 56 COMMAND git describe --tags --abbrev=12 --match v* --dirty 57 WORKING_DIRECTORY ${SOF_ROOT_SOURCE_DIRECTORY} 58 OUTPUT_VARIABLE GIT_TAG 59 OUTPUT_STRIP_TRAILING_WHITESPACE 60 ) 61 62 execute_process(COMMAND git log --pretty=format:%h -1 63 WORKING_DIRECTORY ${SOF_ROOT_SOURCE_DIRECTORY} 64 OUTPUT_VARIABLE GIT_LOG_HASH 65 OUTPUT_STRIP_TRAILING_WHITESPACE 66 ) 67endif() 68 69if(NOT GIT_TAG MATCHES "^v") 70 message(WARNING 71 "git describe found ${GIT_TAG} / nothing starting with 'v'. Shallow clone?") 72 set(GIT_TAG "v0.0-0-g0000") 73endif() 74 75message(STATUS "GIT_TAG / GIT_LOG_HASH : ${GIT_TAG} / ${GIT_LOG_HASH}") 76 77string(REGEX MATCH "^v([0-9]+)[.]([0-9]+)([.]([0-9]+))?" ignored "${GIT_TAG}") 78set(SOF_MAJOR ${CMAKE_MATCH_1}) 79set(SOF_MINOR ${CMAKE_MATCH_2}) 80set(SOF_MICRO ${CMAKE_MATCH_4}) 81 82if(NOT SOF_MICRO MATCHES "^[0-9]+$") 83 set(SOF_MICRO 0) 84endif() 85 86string(SUBSTRING "${GIT_LOG_HASH}" 0 5 SOF_TAG) 87if(NOT SOF_TAG) 88 set(SOF_TAG 0) 89endif() 90 91# Calculate source hash value, used to check ldc file and firmware compatibility 92if(EXISTS ${SOF_ROOT_SOURCE_DIRECTORY}/.git/) 93 set(SOURCE_HASH_DIR "${SOF_ROOT_BINARY_DIRECTORY}/source_hash") 94 file(MAKE_DIRECTORY ${SOURCE_HASH_DIR}) 95 96 # When building with Zephyr, add a few extra files so the XTOS 97 # and Zephyr .ldc files (which have different content!) do not 98 # end up with the exact same "source checksum". The concept of 99 # source checksum is flawed (see issue #3890) but this is much 100 # better than nothing at all. 101 # 102 # Warning: ZEPHYR_CURRENT_MODULE_DIR is _undefined_ the first 103 # time we're run and _defined empty_ the second time. To 104 # understand why look at the check_version_h target below. 105 if("${ZEPHYR_CURRENT_MODULE_DIR}" STREQUAL "") 106 set(_sof_zephyr_dir "") 107 else() 108 set(_sof_zephyr_dir "zephyr/") 109 endif() 110 111 # list tracked files from src directory 112 execute_process(COMMAND git ls-files src/ scripts/ ${_sof_zephyr_dir} 113 WORKING_DIRECTORY ${SOF_ROOT_SOURCE_DIRECTORY} 114 OUTPUT_FILE "${SOURCE_HASH_DIR}/tracked_file_list" 115 ) 116 # calculate hash of each listed files (from file version saved in file system) 117 execute_process(COMMAND git hash-object --stdin-paths 118 WORKING_DIRECTORY ${SOF_ROOT_SOURCE_DIRECTORY} 119 INPUT_FILE "${SOURCE_HASH_DIR}/tracked_file_list" 120 OUTPUT_FILE "${SOURCE_HASH_DIR}/tracked_file_hash_list" 121 ) 122 # then calculate single hash of previously calculated hash list 123 execute_process(COMMAND git hash-object --stdin 124 WORKING_DIRECTORY ${SOF_ROOT_SOURCE_DIRECTORY} 125 OUTPUT_STRIP_TRAILING_WHITESPACE 126 INPUT_FILE "${SOURCE_HASH_DIR}/tracked_file_hash_list" 127 OUTPUT_VARIABLE SOF_SRC_HASH_LONG 128 ) 129 string(SUBSTRING ${SOF_SRC_HASH_LONG} 0 8 SOF_SRC_HASH) 130 message(STATUS "Source content hash: ${SOF_SRC_HASH}. \ 131Notes: 132 - by design, source hash is broken by Kconfig changes. See #3890. 133 - Source hash is also broken by _asymmetric_ autocrlf=input, see 134 #5917 and reverted #5920.") 135else() # Zephyr, tarball,... 136 if(NOT "${GIT_LOG_HASH}" STREQUAL "") 137 string(SUBSTRING "${GIT_LOG_HASH}" 0 8 SOF_SRC_HASH) 138 else() 139 set(SOF_SRC_HASH "baadf00d") 140 endif() 141 message(WARNING "${SOF_ROOT_SOURCE_DIRECTORY}/.git not found, \ 142source content hash cannot computed for the .ldc. Using SOF_SRC_HASH=${SOF_SRC_HASH} \ 143from GIT_LOG_HASH instead") 144endif() 145 146# for SOF_BUILD 147include(${CMAKE_CURRENT_LIST_DIR}/version-build-counter.cmake) 148 149# (Re)-generate "${VERSION_H_PATH}" but overwrite the old one only if 150# different to avoid a full rebuild. TODO: check how Zephyr solves this 151# problem, see Zephyr commit 91709778a4878c 152# 153# This function is called only below; not supposed to be used elsewhere. 154# This entire file is run at CMake configure time _and_ invoked 155# again at build time. 156function(sof_check_version_h) 157 string(CONCAT header_content 158 "#define SOF_MAJOR ${SOF_MAJOR}\n" 159 "#define SOF_MINOR ${SOF_MINOR}\n" 160 "#define SOF_MICRO ${SOF_MICRO}\n" 161 "#define SOF_TAG \"${SOF_TAG}\"\n" 162 "#define SOF_BUILD ${SOF_BUILD}\n" 163 "#define SOF_GIT_TAG \"${GIT_TAG}\"\n" 164 "#define SOF_SRC_HASH 0x${SOF_SRC_HASH}\n" 165 ) 166 167 if(EXISTS "${VERSION_H_PATH}") 168 file(READ "${VERSION_H_PATH}" old_version_content) 169 if("${header_content}" STREQUAL "${old_version_content}") 170 message(STATUS "Unchanged ${VERSION_H_PATH}") 171 return() 172 endif() 173 endif() 174 175 file(WRITE "${VERSION_H_PATH}" "${header_content}") 176 message(STATUS "Generated new ${VERSION_H_PATH}") 177endfunction() 178 179# This ${VERSION_CMAKE_PATH} file is run in two (very) different ways: 180# 181# 1. explicitly included by some other, top-level CMakeLists.txt file, and 182# 2. directly and "recursively" invoking itself with 'cmake -P myself' here. 183# 184# Add this check_version_h target only in case 1. (no "infinite recursion") 185if("${CMAKE_SCRIPT_MODE_FILE}" STREQUAL "") 186 add_custom_target( 187 check_version_h 188 BYPRODUCTS ${VERSION_H_PATH} 189 COMMAND ${CMAKE_COMMAND} 190 -DVERSION_H_PATH=${VERSION_H_PATH} 191 -DSOF_ROOT_SOURCE_DIRECTORY=${SOF_ROOT_SOURCE_DIRECTORY} 192 -DSOF_ROOT_BINARY_DIRECTORY=${SOF_ROOT_BINARY_DIRECTORY} 193 -DZEPHYR_CURRENT_MODULE_DIR=${ZEPHYR_CURRENT_MODULE_DIR} 194 -P ${VERSION_CMAKE_PATH} 195 COMMENT "cmake -P ${VERSION_CMAKE_PATH}" 196 VERBATIM 197 USES_TERMINAL 198 ) 199endif() 200 201sof_check_version_h() 202