一个相当普遍的要求,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/