gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:27:45 26 4
gpt4 key购买 nike

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

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com