首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何保存makefile中的git-diff

如何保存makefile中的git-diff
EN

Stack Overflow用户
提问于 2021-01-27 10:00:05
回答 2查看 158关注 0票数 0

我有一个使用makefile编译的项目。我想在编译时将git diff的输出保存到可执行文件中。简单地将git diff的输出赋值给makefile中的一个变量,然后传递给编译器,例如

代码语言:javascript
复制
GIT_DIFF := $(shell git diff)

CXXFLAGS += -D$(GIT_DIFF)

失败的原因是字符串的某些部分被求值,例如,换行符将编译命令拆分为几个无意义的命令。

在编译时将git diff的输出传递为可以在C++代码中使用的字符串的最佳方法是什么?

EN

回答 2

Stack Overflow用户

发布于 2021-01-27 10:00:05

我找到了一个方法来做到这一点。不过,我不太确定它的健壮性和可移植性。这个解决方案假设shell是bash。在makefile中我有

代码语言:javascript
复制
GIT_DIFF := $(shell printf '%q\n' "$$(git diff | awk '{ gsub("\"","\\\"",$$$$1) ; print $$$$1 }' ORS='\\n')" )

CXXFLAGS += -DGIT_DIFF=\"$(GIT_DIFF)\"

然后在头文件中,我有

代码语言:javascript
复制
// Convert macro to a string constant
#define STRINGIFY1(x) #x
#define STRINGIFY(x) STRINGIFY1(x)

constexpr auto git_diff = STRINGIFY(GIT_DIFF)

(这是一个C++11项目)。

稍微解压一下该命令:

  • $$转义makefile中的$符号,以便bash看到命令printf '%q\n‘"$(git diff | awk '{ gsub(“\”,“\\”,$$1);print $$1 }’ORS='\n')“

(我在这里了解到了这一点,对于awk命令,gsub()位转义引号,因为否则C++编译器(可能也是bash)会被混淆。(从这里开始,https://www.cyberciti.biz/faq/awk-find-and-replace-fields-values/)

  • the shell bit使用bash内置的printf来转义所有特殊字符(据我所知,这是可移植性较差的代码,如果您想使用不同的shell,需要检查一下)。(从此处复制https://unix.stackexchange.com/a/141323)

传递给C++代码的字符串充满了转义序列,因此可读性不是很好。通过颠倒awk替换并使用echo -e计算转义字符,可以将其转换回更具可读性的内容(出于某种原因,这需要执行两次)。因此,如果字符串被保存到文本文件中,比如mygitdiff,那么

代码语言:javascript
复制
echo -e $(echo -e "$(cat mygitdiff | awk '{ gsub("\\\"", "\"",$$1) ; print $$1 }' IRS='\\n')")

应该让它具有可读性。

这种方法很笨拙,传递给C++的字符串可读性也不是很好,所以如果有人有更好的解决方案或改进建议,那将是非常受欢迎的!

票数 0
EN

Stack Overflow用户

发布于 2021-01-27 20:22:56

另一种可能是使用从makefile调用的Python脚本将git diff写入到头文件中。我提出的解决方案有一些错误处理。它是C++11特定的,因为它使用“原始字符串文字”来避免需要转义特殊字符(也使用constexpr auto,但可以用const std::string替换)。这个函数保存了一个来自git describe的散列以及diff。

Python脚本:

代码语言:javascript
复制
#!/usr/bin/env python3

from pathlib import Path
from string import ascii_uppercase

try:
    from git import Repo
except ImportError:
    # print a return code to stdout so we can capture and test it in the makefile
    print(11)
    raise

scriptdir = Path(__file__).parent

repo = Repo(scriptdir.parent)

diff = repo.git.diff()

# Find a string to use for the delimiter
delimiter = "_DIFF_DELIMITER_"
for letter in ascii_uppercase:
    if ")" + delimiter not in diff:
        delimiter_success = True
        break
    delimiter = "_DIFF_DELIMITER_" + letter + "_"
if ")" + delimiter in diff:
    # print a return code to stdout so we can capture and test it in the makefile
    print(12)
    raise ValueError(
        "save_git_version.py failed to find a delimiter that is not in the git diff"
    )

with open("my_git_version.hxx", "w") as f:
    f.write("constexpr auto my_git_hash = \"")
    f.write(repo.git.describe(abbrev=40, dirty=True, always=True, tags=True))
    f.write("\";\n")
    f.write("constexpr auto my_git_diff = R\"" + delimiter + "(")
    f.write(diff)
    f.write(")" + delimiter + "\";\n")

# print a return code to stdout so we can capture and test it in the makefile
print(0)

在makefile中:

代码语言:javascript
复制
save_git_version_status := $(shell ./save_git_version.py)
ifeq ($(save_git_version_status), 11)
  $(error "gitpython not installed. You can install with 'conda install gitpython' or 'pip install --user gitpython'")
endif
ifeq ($(save_git_version_status), 12)
  $(error "save_git_version.py failed to find a delimiter that is not in the git diff")
endif
ifneq ($(save_git_version_status), 0)
  $(error "save_git_version.py failed with an unrecognised error $(save_git_version_status)")
endif

然后,您可以#include "my_git_version.hxx" in the C++ file where you want the my_git_hashormy_git_diff`字符串。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65911886

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档