避免使用git和make重新编译

时间:2012-04-27 18:45:59

标签: c++ c git makefile git-pull

我在git中有两个开发分支,我经常需要在两者之间进行更改。然而,真正令人沮丧的是,每次我在git中更改分支时,整个项目都会重建,因为某些文件的文件系统时间戳会发生变化。

Ofc,makefile被配置为将项目构建到两个不同的构建目录中。

这有什么办法吗?编译是一个非常漫长而耗时的过程...

编辑: - 这是对问题的更详细解释...... 假设我有一个头文件Basic.h,它包含在许多其他文件中。 Basic.h在分支1和分支2之间是不同的。

现在假设我已将分支1编译为build_branch1,将分支2编译为build_branch2。说我目前检查了分支2。现在我签出分支1并更改File1.cpp并重新编译。理想情况下,因为自上次编译以来只有File1.cpp发生了变化,所以这是唯一应该重新编译的文件。

但是,由于Basic.h由于结帐而更改了时间戳,因此所有包含Basic.h的文件都将被重新编译。我想避免这种情况。

5 个答案:

答案 0 :(得分:15)

Git仅更改分支之间更新的文件。但是,如果您的编译器执行完全重建,即使任何单个文件已更改,您也可以始终克隆并将不同的分支签出到不同的目录中。那就像:

/your-repo-name.branch1
/your-repo-name.branch2

这需要额外的磁盘空间,但比在巨大的仓库中切换发散分支要方便得多。

答案 1 :(得分:9)

另一个部分答案:编译器缓存。

当您切换回原始分支并重建时,虽然依赖关系表示必须重建大量依赖于Basic.h的文件,但是可以从编译器缓存中提取目标文件。

ccachehttp://ccache.samba.org/)仍然需要做一些相当昂贵的工作(处理预处理的翻译单元,因为整个翻译单元使用的是哈希键),但它比编译便宜很多

在某些情况下,ccache可以在面对不会影响它的更改时消除编译,就像一些空白更改一样。例如,如果更改依赖文件(标头或源)中的注释,则不会使缓存的对象文件失效。

即使您执行了git pull并获得了之前未曾见过的Basic.h的新更改,它也会有所帮助。

答案 2 :(得分:4)

如果您知道哪些文件实际需要编译,并且手动执行,GNU Make(至少,我不知道其他实现)有一个标志:-t,基本上运行在Makefile上更改时间戳而不是运行命令。

在使用此标记之前,您仍需要更新需要更新的文件,否则您最终会得到合法过时但看起来<的对象文件/ em>已更新。有关详细信息,请参阅链接的文档。

-o选项可能也会让您感兴趣,具体取决于切换分支时的更改次数。

答案 3 :(得分:3)

如果Basic.h在分支之间实际上有所不同,那么唯一的解决办法是将其分解为具有更细粒度依赖关系的较小文件,以便在更改时重建更少的东西。

但是假设Basic.h实际上在分支之间完全相同,但git正在改变其时间戳。这是一个错误的触发器,就像执行touch Basic.h一样,它揭示了基于时间戳的构建系统的局限性。理想情况下,我们希望构建系统在内容更改时重建,而不是在时间戳更改时重建。使用时间戳是因为它们是检测内容更改的廉价替代品。优越的方法是使构建系统保持所有文件的哈希并检测实际修改,而不考虑时间戳。这也解决了“检测到时钟偏差;您的构建可能不完整”等问题。

你不会从Make中获得这种构建系统;但是你可能能够针对某些文件处理它的某些方面。例如,您可以编写Make规则,使您的目标文件不直接依赖于Basic.h,而是依赖于Basic.h.sha,这是一个图章文件。现在,Basic.h.sha中的内容是什么?此文件包含Basic.h的SHA256哈希值。

每次运行Make时,Makefile中的逻辑都会计算Basic.h上的哈希值,并将其与Basic.h.sha中存储的哈希值进行比较。如果它们不同,则Basic.h.sha将被新哈希覆盖。因此,它的时间戳被撞击,触发重建。

BASIC_H_SHA := $(shell sha256sum Basic.h)
BASIC_H_SHA_OLD := $(shell cat Basic.h.sha)

ifneq ($(BASIC_H_SHA),$(BASIC_H_SHA_OLD))
$(info Basic.h has changed!)
DUMMY := $(shell echo "$(BASIC_H_SHA)" > Basic.h.sha)
endif

我已经在这些方面实现了逻辑,以使模块依赖于各自CFLAGS的更改。基本上,我们可以将任何中的更改转换为时间戳文件的触摸,该文件控制所构建的内容。

答案 4 :(得分:2)

没有好的方法可以保留时间戳,也不会在构建环境中遇到麻烦。使用git clone / git checkout branchB创建第二个工作目录,用于构建和使用分支B.不要同时构建Makefile,将每个构建到自己的构建目录中。