c++ - 如何在无需重新编译的情况下使 Git 提交哈希在 C++ 代码中可用?

标签 c++ git makefile g++

一个相当普遍的要求,methinks:我希望 myapp --version 显示版本和 Git 提交哈希(包括存储库是否脏)。该应用程序是通过 Makefile 构建的(实际上是由 qmake 生成的,但让我们暂时保持“简单”)。我相当精通 Makefile,但这个让我感到难过。

我可以轻松获得所需的输出 like this :

$ git describe --always --dirty --match 'NOT A TAG'
e0e8556-dirty

C++ 代码期望提交哈希作为名为 GIT_COMMIT 的预处理器宏可用,例如:

#define GIT_COMMIT "e0e8556-dirty" // in an include file
-DGIT_COMMIT=e0e8556-dirty         // on the g++ command line

以下是我尝试将 git describe 输出到 C++ 的几种不同方法。它们都不能完美运行。

第一个方法:$(shell) 函数。

我们使用 make 的 $(shell) 函数来运行 shell 命令并将结果保存到 make 变量中:

GIT_COMMIT := $(shell git describe --always --dirty --match 'NOT A TAG')

main.o: main.cpp
    g++ -c -DGIT_COMMIT=$(GIT_COMMIT) -o$@ $<

这适用于干净的构建,但有一个问题:如果我更改 Git 哈希(例如,通过提交或修改干净工作拷贝中的某些文件),make 看不到这些更改,二进制文件也看不到得到重建。

方法二:生成version.h

在这里,我们使用 make 配方生成包含必要预处理器定义的 version.h 文件。目标是假的,所以它总是被重建(否则,在第一次构建后它总是被视为最新的)。

.PHONY: version.h
version.h:
    echo "#define GIT_COMMIT \"$(git describe --always --dirty --match 'NOT A TAG')\"" > $@

main.o: main.cpp version.h
    g++ -c -o$@ $<

这可靠地工作并且不会遗漏对 Git 提交哈希的任何更改,但这里的问题是它总是重建 version.h 以及依赖它的所有内容(包括相当长的链接阶段).

第三种方法:仅在 version.h 发生变化时生成

想法:如果我将输出写入 version.h.tmp,然后将其与现有的 version.h 进行比较,只有在不同时才覆盖后者,我们并不总是需要重建。

但是,在实际开始运行任何配方之前,请弄清楚它需要重建什么。所以这必须在那个阶段之前进行,即也从 $(shell) 函数运行。

这是我的尝试:

$(shell echo "#define GIT_COMMIT \"$$(git describe --always --dirty --match 'NOT A TAG')\"" > version.h.tmp; if diff -q version.h.tmp version.h >/dev/null 2>&1; then rm version.h.tmp; else mv version.h.tmp version.h; fi)

main.o: main.cpp version.h
    g++ -c -o$@ $<

几乎有效:每当 Git 哈希更改时,第一个构建重新生成 version.h 并重新编译,但第二个构建也是如此。从那时起,make 决定一切都是最新的。

因此,看起来 make 甚至在运行 $(shell) 函数之前就决定了要重建什么,这也使这种方法失效。

这看起来很常见,而且 make 是一个如此灵活的工具,我很难相信没有办法做到 100% 正确。 是否存在这种方法?

最佳答案

我找到了一个很好的解决方案 here :

在你的 CMakeLists.txt 中放置:

# Get the current working branch
execute_process(
    COMMAND git rev-parse --abbrev-ref HEAD
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
    OUTPUT_VARIABLE GIT_BRANCH
    OUTPUT_STRIP_TRAILING_WHITESPACE)

# Get the latest commit hash
execute_process(
    COMMAND git rev-parse HEAD
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
    OUTPUT_VARIABLE GIT_COMMIT_HASH
    OUTPUT_STRIP_TRAILING_WHITESPACE)

然后在您的源代码中定义它:

target_compile_definitions(${PROJECT_NAME} PRIVATE
    "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"")

在源代码中,它现在可以作为 #define 使用。人们可能想通过包括确保源代码仍然正确编译:

#ifndef GIT_COMMIT_HASH
#define GIT_COMMIT_HASH "?"
#endif

然后你就可以使用了,例如:

std::string hash = GIT_COMMIT_HASH;

关于c++ - 如何在无需重新编译的情况下使 Git 提交哈希在 C++ 代码中可用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51727566/

相关文章:

git - git push 是慢了还是出了什么问题?

GitHub : merging from master back into feature branch

linux - 如何将我自己的软件添加到 Buildroot Linux 软件包中?

c - 使用 make 时,目标文件应该依赖于它自己的头文件吗?

c++ - 是 !=container.end() 设计错误/功能还是必需品?

c++ - FLTK简单动画

c++ - C++ 中的静态成员 Qt 对象

c++ - 将 SWIG 与 C++ 模板函数结合使用

git - 无法在 GitHub 上将我的第二封邮件提交为 "verified"

c - OSX sbrk 已弃用