CMake 笔记 | [31] 构建时记录Git Hash值

注意
本文最后更新于 2024-02-01,文中内容可能已过时。

一、导言

导言
上一篇,在配置时记录了代码存储库(Git Hash)的状态。然而,该方法方法有一个令人不满意的地方,如果在配置代码之后更改分支或提交更改,则源代码中包含的版本记录可能指向错误的Git Hash值。本篇,我们将演示如何在构建时记录·Git Hash·(或者,执行其他操作),以确保每次构建代码时都运行这些操作,因为实际操作中可能只配置一次,但是会构建多次。

二、项目结构

1
2
3
4
5
6
.
├── cmake
│   └── git-hash.cmake
├── CMakeLists.txt
├── example.cpp
└── version.hpp.in

https://gitee.com/jiangli01/tutorials/tree/master/cmake-tutorial/chapter6/05

相关源码

version.hpp.in

1
2
3
4
5
#pragma once

#include <string>

const std::string GIT_HASH = "@GIT_HASH@";

example.cpp

1
2
3
4
5
6
7
#include "version.hpp"

#include <iostream>

int main() {
  std::cout << "This code has been built from version " << GIT_HASH << std::endl;
}

git-hash.cmake

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
set(GIT_HASH "unknown")

# find Git and if available set GIT_HASH variable
find_package(Git QUIET)
if(GIT_FOUND)
  execute_process(
    COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:%h
    OUTPUT_VARIABLE GIT_HASH
    OUTPUT_STRIP_TRAILING_WHITESPACE
    ERROR_QUIET
  )
endif()

message(STATUS "Git hash is ${GIT_HASH}")

configure_file(
  ${CMAKE_SOURCE_DIR}/version.hpp.in
  ${TARGET_DIR}/generated/version.hpp
  @ONLY
)

CMakeLists.txt

 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
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)

project(recipe-07 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(example example.cpp)

target_include_directories(example
  PRIVATE
    ${CMAKE_CURRENT_BINARY_DIR}/generated
)

add_custom_command(
  OUTPUT
    ${CMAKE_CURRENT_BINARY_DIR}/generated/version.hpp
    ALL
  COMMAND
    ${CMAKE_COMMAND} -D TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/git-hash.cmake
  WORKING_DIRECTORY
    ${CMAKE_CURRENT_SOURCE_DIR}
  )

# rebuild version.hpp every time
add_custom_target(
  get_git_hash
  ALL
  DEPENDS
    ${CMAKE_CURRENT_BINARY_DIR}/generated/version.hpp
)

# version.hpp has to be generated before we start building example
add_dependencies(example get_git_hash)
tips
1
2
3
4
5
6
7
8
9
add_custom_command(
  OUTPUT
    ${CMAKE_CURRENT_BINARY_DIR}/generated/version.hpp
    ALL
  COMMAND
    ${CMAKE_COMMAND} -D TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/git-hash.cmake
  WORKING_DIRECTORY
    ${CMAKE_CURRENT_SOURCE_DIR}
  )

自定义命令调用CMake来执行git-hash.cmake脚本。这里使用CLI-P开关,通过传入脚本的位置实现的。请注意,可以像往常一样使用CLI开关-D传递选项。git-hash.cmake脚本生成${TARGET_DIR}/generated/version.hpp。自定义目标被添加到ALL目标中,并且依赖于自定义命令的输出。换句话说,当构建默认目标时,我们确保自定义命令已经运行。此外,自定义命令将ALL目标作为输出。这样,我们就能确保每次都会生成version.hpp了。

三、结果展示

1
2
3
4
5
6
$ mkdir -p build
$ cd build
$ cmake ..
$ cmake --build .
$ ./example
This code has been configured from version c66f02


生成git hash版本文件

四、补充内容

可以改进配置,以便在记录的Git Hash外,包含其他的信息。检测构建环境是否污染(即是否包含未提交的更改和未跟踪的文件),或者干净。可以使用git describe --abbrev=7 --long --always --dirty --tags检测这些信息。根据可重现性,甚至可以将Git的状态,完整输出记录到头文件中。

Buy me a coffee~
支付宝
微信
0%