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

大多数现代源代码存储库都使用Git作为版本控制系统进行跟踪,这可以归功于存储库托管平台GitHub的流行。因此,我们将在本示例中使用Git;然而,实际中会根据具体的动机和实现,可以转化为其他版本控制系统。我们以Git为例,提交的Git Hash决定了源代码的状态。因此,为了标记可执行文件,我们将尝试将Git Hash记录到可执行文件中,方法是将哈希字符串记录在一个头文件中,该头文件可以包含在代码中。

准备工作

我们需要两个源文件,类似于前面的示例。其中一个将配置记录的Hash(version.hpp.in),详情如下:

  1. #pragma once
  2. #include <string>
  3. const std::string GIT_HASH = "@GIT_HASH@";

还需要一个示例源文件(example.cpp),将Hash打印到屏幕上:

#include "version.hpp"

#include <iostream>

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

此示例还假定在Git存储库中至少有一个提交。因此,使用git init初始化这个示例,并使用git add <filename>,然后使用git commit创建提交,以便获得一个有意义的示例。

具体实施

下面演示了从Git记录版本信息的步骤:

  1. 定义项目和支持语言:
    cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
    project(recipe-06 LANGUAGES CXX)
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_EXTENSIONS OFF)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    
  1. 定义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 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) endif()

message(STATUS “Git hash is ${GIT_HASH}”)



3. 
`CMakeLists.txt`剩余的部分,类似于之前的示例:
```cmake
# generate file version.hpp based on version.hpp.in
configure_file(
  version.hpp.in
  generated/version.hpp
  @ONLY
  )

# example code
add_executable(example example.cpp)

# needs to find the generated header file
target_include_directories(example
  PRIVATE
      ${CMAKE_CURRENT_BINARY_DIR}/generated
  )
  1. 验证输出(Hash不同): ```shell $ mkdir -p build $ cd build $ cmake .. $ cmake —build . $ ./example

This code has been configured from version d58c64f




<a name="b3fbd195"></a>
## 工作原理

使用`find_package(Git QUIET)`来检测系统上是否有可用的Git。如果有(`GIT_FOUND`为`True`),运行一个Git命令:<br />
`${GIT_EXECUTABLE} log -1 --pretty=format:%h`。这个命令给出了当前提交Hash的简短版本。当然,这里我们可以灵活地运行Git命令。我们要求`execute_process`命令将结果放入名为`GIT_HASH`的变量中,然后删除任何尾随的空格。使用`ERROR_QUIET`,如果Git命令由于某种原因失败,我们不会停止配置。

由于Git命令可能会失败(源代码已经分发到Git存储库之外),或者Git在系统上不可用,我们希望为这个变量设置一个默认值,如下所示:

```cmake
set(GIT_HASH "unknown")

此示例有一个问题,Git Hash是在配置时记录的,而不是在构建时记录。下一个示例中,我们将演示如何实现后一种方法。