返回介绍

6.7 构建时记录 Git Hash 值

发布于 2025-05-06 21:45:57 字数 3771 浏览 0 评论 0 收藏

NOTE : 此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-6/recipe-07 中找到,其中包含一个 C++例子。该示例在 CMake 3.5 版(或更高版本) 中是有效的,并且已经在 GNU/Linux、macOS 和 Windows 上进行过测试。

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

准备工作

我们将使用与之前示例相同的 version.hpp.in ,只会对 example.cpp 文件进行修改,以确保它打印构建时 Git 提交 Hash 值:

#include "version.hpp"
​
#include <iostream>
​
int main() {
    std::cout << "This code has been built from version " << GIT_HASH << std::endl;
}

具体实施

将 Git 信息保存到 version.hpp 头文件在构建时需要进行以下操作:

  1. 把前一个示例的 CMakeLists.txt 中的大部分代码移到一个单独的文件中,并将该文件命名为 git-hash.cmake :
    # in case Git is not available, we default to "unknown"
    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}")
    ​
    # generate file version.hpp based on version.hpp.in
    configure_file(
      ${CMAKE_CURRENT_LIST_DIR}/version.hpp.in
      ${TARGET_DIR}/generated/version.hpp
      @ONLY
      )
  2. CMakeLists.txt 熟悉的部分:
    # set minimum cmake version
    cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
    # project name and language
    project(recipe-07 LANGUAGES CXX)
    # require C++11
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_EXTENSIONS OFF)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    # example code
    add_executable(example example.cpp)
    # needs to find the generated header file
    target_include_directories(example
      PRIVATE
          ${CMAKE_CURRENT_BINARY_DIR}/generated
      )
  3. CMakeLists.txt 的剩余部分,记录了每次编译代码时的 Git Hash :
    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}/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)

工作原理

示例中,在构建时执行 CMake 代码。为此,定义了一个自定义命令:

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}/git-hash.cmake
  WORKING_DIRECTORY
      ${CMAKE_CURRENT_SOURCE_DIR}
  )

我们还定义了一个目标:

add_custom_target(
  get_git_hash
  ALL
  DEPENDS
      ${CMAKE_CURRENT_BINARY_DIR}/generated/version.hpp
  )

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

更多信息

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

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。