将git信息嵌入到二进制文件中。
目标
考虑以下C++程序:
#include <iostream>
#include <format>
#include "gitversion.h"
int main()
{
std::cout << std::format("Build Info: {}\n{}\n{}\n{}",
FromGit::Branch, FromGit::Tag, FromGit::Commit, FromGit::Date) <<
std::endl;
return 0;
}
目标是拥有一个
gitversion.h
文件,引入该文件后可以访问存储库的分支、标签、提交和日期信息。
建议采用
离线构建方法,即
构建树位于
源代码树之外。要通过命令行实现此目标:
mkdir ../build
cd ../build
如果你使用的是QtCreator,可以在IDE左侧的“Projects”选项卡中选择正确的“kit”,然后在构建选项卡中选择“Shadow build”。如果你使用的是Microsoft Visual Studio,则右键单击CMakeLists.txt并选择“CMake Settings for...”,然后将“Build root”更改为以下内容:
${projectDir}\..\build\${name}
如果您违反此建议并将构建目录放在源代码内部,则每次运行cmake
或更改IDE中的项目设置时,git status
可能会发生变化,并且不需要的更改将反映在您的二进制文件中。
CMakeLists 文件
以下是CMakeLists.txt
的内容:
cmake_minimum_required(VERSION 3.20)
project(Tutorial)
include(${PROJECT_SOURCE_DIR}/gitversion.cmake)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_executable(Tutorial tutorial.cxx)
target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}")
.cmake文件
这是大部分工作发生的地方:
find_package(Git)
execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --abbrev=8
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT)
execute_process(COMMAND ${GIT_EXECUTABLE} status --short
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_STATUS)
if (("${GIT_COMMIT}" STREQUAL "") OR (NOT "${GIT_STATUS}" STREQUAL ""))
set(GIT_COMMIT "N/A")
endif()
execute_process(COMMAND ${GIT_EXECUTABLE} describe --exact-match --tags
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_TAG
ERROR_QUIET)
if ("${GIT_TAG}" STREQUAL "")
set(GIT_TAG "N/A")
endif()
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH)
if ("${GIT_BRANCH}" STREQUAL "")
set(GIT_BRANCH "N/A")
endif()
execute_process(COMMAND ${GIT_EXECUTABLE} log -n 1 --pretty=%cd --pretty=%cI
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_DATE)
if ("${GIT_DATE}" STREQUAL "")
set(GIT_DATE "N/A")
endif()
string(STRIP "${GIT_COMMIT}" GIT_COMMIT)
string(STRIP "${GIT_TAG}" GIT_TAG)
string(STRIP "${GIT_BRANCH}" GIT_BRANCH)
string(STRIP "${GIT_DATE}" GIT_DATE)
configure_file(gitversion.h.in gitversion.h)
.in文件
这个文件实际上是一个包含与cmake相关的变量的.h
文件,在cmake
执行期间将被替换:
#pragma once
#include <string_view>
namespace FromGit
{
const std::string_view Commit{"@GIT_COMMIT@"};
const std::string_view Tag{"@GIT_TAG@"};
const std::string_view Branch{"@GIT_BRANCH@"};
const std::string_view Date{"@GIT_DATE@"};
}
最后一步
最后,在我们的构建目录中运行:
cmake ../Tutorial
cmake --build .
确保使用git
初始化Tutorial
目录。
此解决方案基于Matt Keeter的工作。